149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU i8255x (PRO100) emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (C) 2006-2011 Stefan Weil
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * Portions of the code are copies from grub / etherboot eepro100.c
749ab747fSPaolo Bonzini * and linux e100.c.
849ab747fSPaolo Bonzini *
949ab747fSPaolo Bonzini * This program is free software: you can redistribute it and/or modify
1049ab747fSPaolo Bonzini * it under the terms of the GNU General Public License as published by
1149ab747fSPaolo Bonzini * the Free Software Foundation, either version 2 of the License, or
1249ab747fSPaolo Bonzini * (at your option) version 3 or any later version.
1349ab747fSPaolo Bonzini *
1449ab747fSPaolo Bonzini * This program is distributed in the hope that it will be useful,
1549ab747fSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
1649ab747fSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1749ab747fSPaolo Bonzini * GNU General Public License for more details.
1849ab747fSPaolo Bonzini *
1949ab747fSPaolo Bonzini * You should have received a copy of the GNU General Public License
2049ab747fSPaolo Bonzini * along with this program. If not, see <http://www.gnu.org/licenses/>.
2149ab747fSPaolo Bonzini *
2249ab747fSPaolo Bonzini * Tested features (i82559):
2349ab747fSPaolo Bonzini * PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
2449ab747fSPaolo Bonzini * Linux networking (i386) ok
2549ab747fSPaolo Bonzini *
2649ab747fSPaolo Bonzini * Untested:
2749ab747fSPaolo Bonzini * Windows networking
2849ab747fSPaolo Bonzini *
2949ab747fSPaolo Bonzini * References:
3049ab747fSPaolo Bonzini *
3149ab747fSPaolo Bonzini * Intel 8255x 10/100 Mbps Ethernet Controller Family
3249ab747fSPaolo Bonzini * Open Source Software Developer Manual
3349ab747fSPaolo Bonzini *
3449ab747fSPaolo Bonzini * TODO:
3549ab747fSPaolo Bonzini * * PHY emulation should be separated from nic emulation.
3649ab747fSPaolo Bonzini * Most nic emulations could share the same phy code.
3749ab747fSPaolo Bonzini * * i82550 is untested. It is programmed like the i82559.
3849ab747fSPaolo Bonzini * * i82562 is untested. It is programmed like the i82559.
3949ab747fSPaolo Bonzini * * Power management (i82558 and later) is not implemented.
4049ab747fSPaolo Bonzini * * Wake-on-LAN is not implemented.
4149ab747fSPaolo Bonzini */
4249ab747fSPaolo Bonzini
43e8d40465SPeter Maydell #include "qemu/osdep.h"
44872a2b7cSPhilippe Mathieu-Daudé #include "qemu/units.h"
45edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
46a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
47d6454270SMarkus Armbruster #include "migration/vmstate.h"
4849ab747fSPaolo Bonzini #include "net/net.h"
497c0348bdSMark Cave-Ayland #include "net/eth.h"
5049ab747fSPaolo Bonzini #include "hw/nvram/eeprom93xx.h"
5149ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
5249ab747fSPaolo Bonzini #include "sysemu/dma.h"
5371e8a915SMarkus Armbruster #include "sysemu/reset.h"
54949fc823SMarcel Apfelbaum #include "qemu/bitops.h"
550b8fa32fSMarkus Armbruster #include "qemu/module.h"
569a7c2a59SMao Zhongyi #include "qapi/error.h"
5749ab747fSPaolo Bonzini
5849ab747fSPaolo Bonzini /* QEMU sends frames smaller than 60 bytes to ethernet nics.
5949ab747fSPaolo Bonzini * Such frames are rejected by real nics and their emulations.
6049ab747fSPaolo Bonzini * To avoid this behaviour, other nic emulations pad received
6149ab747fSPaolo Bonzini * frames. The following definition enables this padding for
6249ab747fSPaolo Bonzini * eepro100, too. We keep the define around in case it might
6349ab747fSPaolo Bonzini * become useful the future if the core networking is ever
6449ab747fSPaolo Bonzini * changed to pad short packets itself. */
6549ab747fSPaolo Bonzini #define CONFIG_PAD_RECEIVED_FRAMES
6649ab747fSPaolo Bonzini
6749ab747fSPaolo Bonzini /* Debug EEPRO100 card. */
6849ab747fSPaolo Bonzini #if 0
6949ab747fSPaolo Bonzini # define DEBUG_EEPRO100
7049ab747fSPaolo Bonzini #endif
7149ab747fSPaolo Bonzini
7249ab747fSPaolo Bonzini #ifdef DEBUG_EEPRO100
7349ab747fSPaolo Bonzini #define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
7449ab747fSPaolo Bonzini #else
7549ab747fSPaolo Bonzini #define logout(fmt, ...) ((void)0)
7649ab747fSPaolo Bonzini #endif
7749ab747fSPaolo Bonzini
7849ab747fSPaolo Bonzini /* Set flags to 0 to disable debug output. */
7949ab747fSPaolo Bonzini #define INT 1 /* interrupt related actions */
8049ab747fSPaolo Bonzini #define MDI 1 /* mdi related actions */
8149ab747fSPaolo Bonzini #define OTHER 1
8249ab747fSPaolo Bonzini #define RXTX 1
8349ab747fSPaolo Bonzini #define EEPROM 1 /* eeprom related actions */
8449ab747fSPaolo Bonzini
8549ab747fSPaolo Bonzini #define TRACE(flag, command) ((flag) ? (command) : (void)0)
8649ab747fSPaolo Bonzini
8749ab747fSPaolo Bonzini #define missing(text) fprintf(stderr, "eepro100: feature is missing in this emulation: " text "\n")
8849ab747fSPaolo Bonzini
8949ab747fSPaolo Bonzini #define MAX_ETH_FRAME_SIZE 1514
9049ab747fSPaolo Bonzini
9149ab747fSPaolo Bonzini /* This driver supports several different devices which are declared here. */
9249ab747fSPaolo Bonzini #define i82550 0x82550
9349ab747fSPaolo Bonzini #define i82551 0x82551
9449ab747fSPaolo Bonzini #define i82557A 0x82557a
9549ab747fSPaolo Bonzini #define i82557B 0x82557b
9649ab747fSPaolo Bonzini #define i82557C 0x82557c
9749ab747fSPaolo Bonzini #define i82558A 0x82558a
9849ab747fSPaolo Bonzini #define i82558B 0x82558b
9949ab747fSPaolo Bonzini #define i82559A 0x82559a
10049ab747fSPaolo Bonzini #define i82559B 0x82559b
10149ab747fSPaolo Bonzini #define i82559C 0x82559c
10249ab747fSPaolo Bonzini #define i82559ER 0x82559e
10349ab747fSPaolo Bonzini #define i82562 0x82562
10449ab747fSPaolo Bonzini #define i82801 0x82801
10549ab747fSPaolo Bonzini
10649ab747fSPaolo Bonzini /* Use 64 word EEPROM. TODO: could be a runtime option. */
10749ab747fSPaolo Bonzini #define EEPROM_SIZE 64
10849ab747fSPaolo Bonzini
10949ab747fSPaolo Bonzini #define PCI_MEM_SIZE (4 * KiB)
11049ab747fSPaolo Bonzini #define PCI_IO_SIZE 64
11149ab747fSPaolo Bonzini #define PCI_FLASH_SIZE (128 * KiB)
11249ab747fSPaolo Bonzini
11349ab747fSPaolo Bonzini #define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
11449ab747fSPaolo Bonzini
11549ab747fSPaolo Bonzini /* The SCB accepts the following controls for the Tx and Rx units: */
11649ab747fSPaolo Bonzini #define CU_NOP 0x0000 /* No operation. */
11749ab747fSPaolo Bonzini #define CU_START 0x0010 /* CU start. */
11849ab747fSPaolo Bonzini #define CU_RESUME 0x0020 /* CU resume. */
11949ab747fSPaolo Bonzini #define CU_STATSADDR 0x0040 /* Load dump counters address. */
12049ab747fSPaolo Bonzini #define CU_SHOWSTATS 0x0050 /* Dump statistical counters. */
12149ab747fSPaolo Bonzini #define CU_CMD_BASE 0x0060 /* Load CU base address. */
12249ab747fSPaolo Bonzini #define CU_DUMPSTATS 0x0070 /* Dump and reset statistical counters. */
12349ab747fSPaolo Bonzini #define CU_SRESUME 0x00a0 /* CU static resume. */
12449ab747fSPaolo Bonzini
12549ab747fSPaolo Bonzini #define RU_NOP 0x0000
12649ab747fSPaolo Bonzini #define RX_START 0x0001
12749ab747fSPaolo Bonzini #define RX_RESUME 0x0002
12849ab747fSPaolo Bonzini #define RU_ABORT 0x0004
12949ab747fSPaolo Bonzini #define RX_ADDR_LOAD 0x0006
13049ab747fSPaolo Bonzini #define RX_RESUMENR 0x0007
13149ab747fSPaolo Bonzini #define INT_MASK 0x0100
13249ab747fSPaolo Bonzini #define DRVR_INT 0x0200 /* Driver generated interrupt. */
13349ab747fSPaolo Bonzini
13449ab747fSPaolo Bonzini typedef struct {
13549ab747fSPaolo Bonzini const char *name;
13649ab747fSPaolo Bonzini const char *desc;
13749ab747fSPaolo Bonzini uint16_t device_id;
13849ab747fSPaolo Bonzini uint8_t revision;
13949ab747fSPaolo Bonzini uint16_t subsystem_vendor_id;
14049ab747fSPaolo Bonzini uint16_t subsystem_id;
14149ab747fSPaolo Bonzini
14249ab747fSPaolo Bonzini uint32_t device;
14349ab747fSPaolo Bonzini uint8_t stats_size;
14449ab747fSPaolo Bonzini bool has_extended_tcb_support;
14549ab747fSPaolo Bonzini bool power_management;
14649ab747fSPaolo Bonzini } E100PCIDeviceInfo;
14749ab747fSPaolo Bonzini
14849ab747fSPaolo Bonzini /* Offsets to the various registers.
14949ab747fSPaolo Bonzini All accesses need not be longword aligned. */
15049ab747fSPaolo Bonzini typedef enum {
15149ab747fSPaolo Bonzini SCBStatus = 0, /* Status Word. */
15249ab747fSPaolo Bonzini SCBAck = 1,
15349ab747fSPaolo Bonzini SCBCmd = 2, /* Rx/Command Unit command and status. */
15449ab747fSPaolo Bonzini SCBIntmask = 3,
15549ab747fSPaolo Bonzini SCBPointer = 4, /* General purpose pointer. */
15649ab747fSPaolo Bonzini SCBPort = 8, /* Misc. commands and operands. */
15749ab747fSPaolo Bonzini SCBflash = 12, /* Flash memory control. */
15849ab747fSPaolo Bonzini SCBeeprom = 14, /* EEPROM control. */
15949ab747fSPaolo Bonzini SCBCtrlMDI = 16, /* MDI interface control. */
16049ab747fSPaolo Bonzini SCBEarlyRx = 20, /* Early receive byte count. */
16149ab747fSPaolo Bonzini SCBFlow = 24, /* Flow Control. */
16249ab747fSPaolo Bonzini SCBpmdr = 27, /* Power Management Driver. */
16349ab747fSPaolo Bonzini SCBgctrl = 28, /* General Control. */
16449ab747fSPaolo Bonzini SCBgstat = 29, /* General Status. */
16549ab747fSPaolo Bonzini } E100RegisterOffset;
16649ab747fSPaolo Bonzini
16749ab747fSPaolo Bonzini /* A speedo3 transmit buffer descriptor with two buffers... */
16849ab747fSPaolo Bonzini typedef struct {
16949ab747fSPaolo Bonzini uint16_t status;
17049ab747fSPaolo Bonzini uint16_t command;
17149ab747fSPaolo Bonzini uint32_t link; /* void * */
17249ab747fSPaolo Bonzini uint32_t tbd_array_addr; /* transmit buffer descriptor array address. */
17349ab747fSPaolo Bonzini uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */
17449ab747fSPaolo Bonzini uint8_t tx_threshold; /* transmit threshold */
17549ab747fSPaolo Bonzini uint8_t tbd_count; /* TBD number */
17649ab747fSPaolo Bonzini #if 0
17749ab747fSPaolo Bonzini /* This constitutes two "TBD" entries: hdr and data */
17849ab747fSPaolo Bonzini uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */
17949ab747fSPaolo Bonzini int32_t tx_buf_size0; /* Length of Tx hdr. */
18049ab747fSPaolo Bonzini uint32_t tx_buf_addr1; /* void *, data to be transmitted. */
18149ab747fSPaolo Bonzini int32_t tx_buf_size1; /* Length of Tx data. */
18249ab747fSPaolo Bonzini #endif
18349ab747fSPaolo Bonzini } eepro100_tx_t;
18449ab747fSPaolo Bonzini
18549ab747fSPaolo Bonzini /* Receive frame descriptor. */
18649ab747fSPaolo Bonzini typedef struct {
18749ab747fSPaolo Bonzini int16_t status;
18849ab747fSPaolo Bonzini uint16_t command;
18949ab747fSPaolo Bonzini uint32_t link; /* struct RxFD * */
19049ab747fSPaolo Bonzini uint32_t rx_buf_addr; /* void * */
19149ab747fSPaolo Bonzini uint16_t count;
19249ab747fSPaolo Bonzini uint16_t size;
19349ab747fSPaolo Bonzini /* Ethernet frame data follows. */
19449ab747fSPaolo Bonzini } eepro100_rx_t;
19549ab747fSPaolo Bonzini
19649ab747fSPaolo Bonzini typedef enum {
19749ab747fSPaolo Bonzini COMMAND_EL = BIT(15),
19849ab747fSPaolo Bonzini COMMAND_S = BIT(14),
19949ab747fSPaolo Bonzini COMMAND_I = BIT(13),
20049ab747fSPaolo Bonzini COMMAND_NC = BIT(4),
20149ab747fSPaolo Bonzini COMMAND_SF = BIT(3),
20249ab747fSPaolo Bonzini COMMAND_CMD = BITS(2, 0),
20349ab747fSPaolo Bonzini } scb_command_bit;
20449ab747fSPaolo Bonzini
20549ab747fSPaolo Bonzini typedef enum {
20649ab747fSPaolo Bonzini STATUS_C = BIT(15),
20749ab747fSPaolo Bonzini STATUS_OK = BIT(13),
20849ab747fSPaolo Bonzini } scb_status_bit;
20949ab747fSPaolo Bonzini
21049ab747fSPaolo Bonzini typedef struct {
21149ab747fSPaolo Bonzini uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
21249ab747fSPaolo Bonzini tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
21349ab747fSPaolo Bonzini tx_multiple_collisions, tx_total_collisions;
21449ab747fSPaolo Bonzini uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
21549ab747fSPaolo Bonzini rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
21649ab747fSPaolo Bonzini rx_short_frame_errors;
21749ab747fSPaolo Bonzini uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
21849ab747fSPaolo Bonzini uint16_t xmt_tco_frames, rcv_tco_frames;
21949ab747fSPaolo Bonzini /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
22049ab747fSPaolo Bonzini uint32_t reserved[4];
22149ab747fSPaolo Bonzini } eepro100_stats_t;
22249ab747fSPaolo Bonzini
22349ab747fSPaolo Bonzini typedef enum {
22449ab747fSPaolo Bonzini cu_idle = 0,
22549ab747fSPaolo Bonzini cu_suspended = 1,
22649ab747fSPaolo Bonzini cu_active = 2,
22749ab747fSPaolo Bonzini cu_lpq_active = 2,
22849ab747fSPaolo Bonzini cu_hqp_active = 3
22949ab747fSPaolo Bonzini } cu_state_t;
23049ab747fSPaolo Bonzini
23149ab747fSPaolo Bonzini typedef enum {
23249ab747fSPaolo Bonzini ru_idle = 0,
23349ab747fSPaolo Bonzini ru_suspended = 1,
23449ab747fSPaolo Bonzini ru_no_resources = 2,
23549ab747fSPaolo Bonzini ru_ready = 4
23649ab747fSPaolo Bonzini } ru_state_t;
23749ab747fSPaolo Bonzini
23849ab747fSPaolo Bonzini typedef struct {
23949ab747fSPaolo Bonzini PCIDevice dev;
24049ab747fSPaolo Bonzini /* Hash register (multicast mask array, multiple individual addresses). */
24149ab747fSPaolo Bonzini uint8_t mult[8];
24249ab747fSPaolo Bonzini MemoryRegion mmio_bar;
24349ab747fSPaolo Bonzini MemoryRegion io_bar;
24449ab747fSPaolo Bonzini MemoryRegion flash_bar;
24549ab747fSPaolo Bonzini NICState *nic;
24649ab747fSPaolo Bonzini NICConf conf;
24749ab747fSPaolo Bonzini uint8_t scb_stat; /* SCB stat/ack byte */
24849ab747fSPaolo Bonzini uint8_t int_stat; /* PCI interrupt status */
24949ab747fSPaolo Bonzini /* region must not be saved by nic_save. */
25049ab747fSPaolo Bonzini uint16_t mdimem[32];
25149ab747fSPaolo Bonzini eeprom_t *eeprom;
25249ab747fSPaolo Bonzini uint32_t device; /* device variant */
25349ab747fSPaolo Bonzini /* (cu_base + cu_offset) address the next command block in the command block list. */
25449ab747fSPaolo Bonzini uint32_t cu_base; /* CU base address */
25549ab747fSPaolo Bonzini uint32_t cu_offset; /* CU address offset */
25649ab747fSPaolo Bonzini /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
25749ab747fSPaolo Bonzini uint32_t ru_base; /* RU base address */
25849ab747fSPaolo Bonzini uint32_t ru_offset; /* RU address offset */
25949ab747fSPaolo Bonzini uint32_t statsaddr; /* pointer to eepro100_stats_t */
26049ab747fSPaolo Bonzini
26149ab747fSPaolo Bonzini /* Temporary status information (no need to save these values),
26249ab747fSPaolo Bonzini * used while processing CU commands. */
26349ab747fSPaolo Bonzini eepro100_tx_t tx; /* transmit buffer descriptor */
26449ab747fSPaolo Bonzini uint32_t cb_address; /* = cu_base + cu_offset */
26549ab747fSPaolo Bonzini
26649ab747fSPaolo Bonzini /* Statistical counters. Also used for wake-up packet (i82559). */
26749ab747fSPaolo Bonzini eepro100_stats_t statistics;
26849ab747fSPaolo Bonzini
26949ab747fSPaolo Bonzini /* Data in mem is always in the byte order of the controller (le).
27049ab747fSPaolo Bonzini * It must be dword aligned to allow direct access to 32 bit values. */
27149ab747fSPaolo Bonzini uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));
27249ab747fSPaolo Bonzini
27349ab747fSPaolo Bonzini /* Configuration bytes. */
27449ab747fSPaolo Bonzini uint8_t configuration[22];
27549ab747fSPaolo Bonzini
27649ab747fSPaolo Bonzini /* vmstate for each particular nic */
27749ab747fSPaolo Bonzini VMStateDescription *vmstate;
27849ab747fSPaolo Bonzini
27949ab747fSPaolo Bonzini /* Quasi static device properties (no need to save them). */
28049ab747fSPaolo Bonzini uint16_t stats_size;
28149ab747fSPaolo Bonzini bool has_extended_tcb_support;
28249ab747fSPaolo Bonzini } EEPRO100State;
28349ab747fSPaolo Bonzini
28449ab747fSPaolo Bonzini /* Word indices in EEPROM. */
28549ab747fSPaolo Bonzini typedef enum {
28649ab747fSPaolo Bonzini EEPROM_CNFG_MDIX = 0x03,
28749ab747fSPaolo Bonzini EEPROM_ID = 0x05,
28849ab747fSPaolo Bonzini EEPROM_PHY_ID = 0x06,
28949ab747fSPaolo Bonzini EEPROM_VENDOR_ID = 0x0c,
29049ab747fSPaolo Bonzini EEPROM_CONFIG_ASF = 0x0d,
29149ab747fSPaolo Bonzini EEPROM_DEVICE_ID = 0x23,
29249ab747fSPaolo Bonzini EEPROM_SMBUS_ADDR = 0x90,
29349ab747fSPaolo Bonzini } EEPROMOffset;
29449ab747fSPaolo Bonzini
29549ab747fSPaolo Bonzini /* Bit values for EEPROM ID word. */
29649ab747fSPaolo Bonzini typedef enum {
29749ab747fSPaolo Bonzini EEPROM_ID_MDM = BIT(0), /* Modem */
29849ab747fSPaolo Bonzini EEPROM_ID_STB = BIT(1), /* Standby Enable */
29949ab747fSPaolo Bonzini EEPROM_ID_WMR = BIT(2), /* ??? */
30049ab747fSPaolo Bonzini EEPROM_ID_WOL = BIT(5), /* Wake on LAN */
30149ab747fSPaolo Bonzini EEPROM_ID_DPD = BIT(6), /* Deep Power Down */
30249ab747fSPaolo Bonzini EEPROM_ID_ALT = BIT(7), /* */
30349ab747fSPaolo Bonzini /* BITS(10, 8) device revision */
30449ab747fSPaolo Bonzini EEPROM_ID_BD = BIT(11), /* boot disable */
30549ab747fSPaolo Bonzini EEPROM_ID_ID = BIT(13), /* id bit */
30649ab747fSPaolo Bonzini /* BITS(15, 14) signature */
30749ab747fSPaolo Bonzini EEPROM_ID_VALID = BIT(14), /* signature for valid eeprom */
30849ab747fSPaolo Bonzini } eeprom_id_bit;
30949ab747fSPaolo Bonzini
31049ab747fSPaolo Bonzini /* Default values for MDI (PHY) registers */
31149ab747fSPaolo Bonzini static const uint16_t eepro100_mdi_default[] = {
31249ab747fSPaolo Bonzini /* MDI Registers 0 - 6, 7 */
31349ab747fSPaolo Bonzini 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
31449ab747fSPaolo Bonzini /* MDI Registers 8 - 15 */
31549ab747fSPaolo Bonzini 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
31649ab747fSPaolo Bonzini /* MDI Registers 16 - 31 */
31749ab747fSPaolo Bonzini 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
31849ab747fSPaolo Bonzini 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
31949ab747fSPaolo Bonzini };
32049ab747fSPaolo Bonzini
32149ab747fSPaolo Bonzini /* Readonly mask for MDI (PHY) registers */
32249ab747fSPaolo Bonzini static const uint16_t eepro100_mdi_mask[] = {
32349ab747fSPaolo Bonzini 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
32449ab747fSPaolo Bonzini 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
32549ab747fSPaolo Bonzini 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
32649ab747fSPaolo Bonzini 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
32749ab747fSPaolo Bonzini };
32849ab747fSPaolo Bonzini
32949ab747fSPaolo Bonzini static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
33049ab747fSPaolo Bonzini
33149ab747fSPaolo Bonzini /* Read a 16 bit control/status (CSR) register. */
e100_read_reg2(EEPRO100State * s,E100RegisterOffset addr)33249ab747fSPaolo Bonzini static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
33349ab747fSPaolo Bonzini {
33449ab747fSPaolo Bonzini assert(!((uintptr_t)&s->mem[addr] & 1));
3354d9be252SPeter Maydell return lduw_le_p(&s->mem[addr]);
33649ab747fSPaolo Bonzini }
33749ab747fSPaolo Bonzini
33849ab747fSPaolo Bonzini /* Read a 32 bit control/status (CSR) register. */
e100_read_reg4(EEPRO100State * s,E100RegisterOffset addr)33949ab747fSPaolo Bonzini static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
34049ab747fSPaolo Bonzini {
34149ab747fSPaolo Bonzini assert(!((uintptr_t)&s->mem[addr] & 3));
3424d9be252SPeter Maydell return ldl_le_p(&s->mem[addr]);
34349ab747fSPaolo Bonzini }
34449ab747fSPaolo Bonzini
34549ab747fSPaolo Bonzini /* Write a 16 bit control/status (CSR) register. */
e100_write_reg2(EEPRO100State * s,E100RegisterOffset addr,uint16_t val)34649ab747fSPaolo Bonzini static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
34749ab747fSPaolo Bonzini uint16_t val)
34849ab747fSPaolo Bonzini {
34949ab747fSPaolo Bonzini assert(!((uintptr_t)&s->mem[addr] & 1));
3504d9be252SPeter Maydell stw_le_p(&s->mem[addr], val);
35149ab747fSPaolo Bonzini }
35249ab747fSPaolo Bonzini
35349ab747fSPaolo Bonzini /* Read a 32 bit control/status (CSR) register. */
e100_write_reg4(EEPRO100State * s,E100RegisterOffset addr,uint32_t val)35449ab747fSPaolo Bonzini static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
35549ab747fSPaolo Bonzini uint32_t val)
35649ab747fSPaolo Bonzini {
35749ab747fSPaolo Bonzini assert(!((uintptr_t)&s->mem[addr] & 3));
3584d9be252SPeter Maydell stl_le_p(&s->mem[addr], val);
35949ab747fSPaolo Bonzini }
36049ab747fSPaolo Bonzini
36149ab747fSPaolo Bonzini #if defined(DEBUG_EEPRO100)
nic_dump(const uint8_t * buf,unsigned size)36249ab747fSPaolo Bonzini static const char *nic_dump(const uint8_t * buf, unsigned size)
36349ab747fSPaolo Bonzini {
36449ab747fSPaolo Bonzini static char dump[3 * 16 + 1];
36549ab747fSPaolo Bonzini char *p = &dump[0];
36649ab747fSPaolo Bonzini if (size > 16) {
36749ab747fSPaolo Bonzini size = 16;
36849ab747fSPaolo Bonzini }
36949ab747fSPaolo Bonzini while (size-- > 0) {
37049ab747fSPaolo Bonzini p += sprintf(p, " %02x", *buf++);
37149ab747fSPaolo Bonzini }
37249ab747fSPaolo Bonzini return dump;
37349ab747fSPaolo Bonzini }
37449ab747fSPaolo Bonzini #endif /* DEBUG_EEPRO100 */
37549ab747fSPaolo Bonzini
37649ab747fSPaolo Bonzini enum scb_stat_ack {
37749ab747fSPaolo Bonzini stat_ack_not_ours = 0x00,
37849ab747fSPaolo Bonzini stat_ack_sw_gen = 0x04,
37949ab747fSPaolo Bonzini stat_ack_rnr = 0x10,
38049ab747fSPaolo Bonzini stat_ack_cu_idle = 0x20,
38149ab747fSPaolo Bonzini stat_ack_frame_rx = 0x40,
38249ab747fSPaolo Bonzini stat_ack_cu_cmd_done = 0x80,
38349ab747fSPaolo Bonzini stat_ack_not_present = 0xFF,
38449ab747fSPaolo Bonzini stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
38549ab747fSPaolo Bonzini stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
38649ab747fSPaolo Bonzini };
38749ab747fSPaolo Bonzini
disable_interrupt(EEPRO100State * s)38849ab747fSPaolo Bonzini static void disable_interrupt(EEPRO100State * s)
38949ab747fSPaolo Bonzini {
39049ab747fSPaolo Bonzini if (s->int_stat) {
39149ab747fSPaolo Bonzini TRACE(INT, logout("interrupt disabled\n"));
3929e64f8a3SMarcel Apfelbaum pci_irq_deassert(&s->dev);
39349ab747fSPaolo Bonzini s->int_stat = 0;
39449ab747fSPaolo Bonzini }
39549ab747fSPaolo Bonzini }
39649ab747fSPaolo Bonzini
enable_interrupt(EEPRO100State * s)39749ab747fSPaolo Bonzini static void enable_interrupt(EEPRO100State * s)
39849ab747fSPaolo Bonzini {
39949ab747fSPaolo Bonzini if (!s->int_stat) {
40049ab747fSPaolo Bonzini TRACE(INT, logout("interrupt enabled\n"));
4019e64f8a3SMarcel Apfelbaum pci_irq_assert(&s->dev);
40249ab747fSPaolo Bonzini s->int_stat = 1;
40349ab747fSPaolo Bonzini }
40449ab747fSPaolo Bonzini }
40549ab747fSPaolo Bonzini
eepro100_acknowledge(EEPRO100State * s)40649ab747fSPaolo Bonzini static void eepro100_acknowledge(EEPRO100State * s)
40749ab747fSPaolo Bonzini {
40849ab747fSPaolo Bonzini s->scb_stat &= ~s->mem[SCBAck];
40949ab747fSPaolo Bonzini s->mem[SCBAck] = s->scb_stat;
41049ab747fSPaolo Bonzini if (s->scb_stat == 0) {
41149ab747fSPaolo Bonzini disable_interrupt(s);
41249ab747fSPaolo Bonzini }
41349ab747fSPaolo Bonzini }
41449ab747fSPaolo Bonzini
eepro100_interrupt(EEPRO100State * s,uint8_t status)41549ab747fSPaolo Bonzini static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
41649ab747fSPaolo Bonzini {
41749ab747fSPaolo Bonzini uint8_t mask = ~s->mem[SCBIntmask];
41849ab747fSPaolo Bonzini s->mem[SCBAck] |= status;
41949ab747fSPaolo Bonzini status = s->scb_stat = s->mem[SCBAck];
42049ab747fSPaolo Bonzini status &= (mask | 0x0f);
42149ab747fSPaolo Bonzini #if 0
42249ab747fSPaolo Bonzini status &= (~s->mem[SCBIntmask] | 0x0xf);
42349ab747fSPaolo Bonzini #endif
42449ab747fSPaolo Bonzini if (status && (mask & 0x01)) {
42549ab747fSPaolo Bonzini /* SCB mask and SCB Bit M do not disable interrupt. */
42649ab747fSPaolo Bonzini enable_interrupt(s);
42749ab747fSPaolo Bonzini } else if (s->int_stat) {
42849ab747fSPaolo Bonzini disable_interrupt(s);
42949ab747fSPaolo Bonzini }
43049ab747fSPaolo Bonzini }
43149ab747fSPaolo Bonzini
eepro100_cx_interrupt(EEPRO100State * s)43249ab747fSPaolo Bonzini static void eepro100_cx_interrupt(EEPRO100State * s)
43349ab747fSPaolo Bonzini {
43449ab747fSPaolo Bonzini /* CU completed action command. */
43549ab747fSPaolo Bonzini /* Transmit not ok (82557 only, not in emulation). */
43649ab747fSPaolo Bonzini eepro100_interrupt(s, 0x80);
43749ab747fSPaolo Bonzini }
43849ab747fSPaolo Bonzini
eepro100_cna_interrupt(EEPRO100State * s)43949ab747fSPaolo Bonzini static void eepro100_cna_interrupt(EEPRO100State * s)
44049ab747fSPaolo Bonzini {
44149ab747fSPaolo Bonzini /* CU left the active state. */
44249ab747fSPaolo Bonzini eepro100_interrupt(s, 0x20);
44349ab747fSPaolo Bonzini }
44449ab747fSPaolo Bonzini
eepro100_fr_interrupt(EEPRO100State * s)44549ab747fSPaolo Bonzini static void eepro100_fr_interrupt(EEPRO100State * s)
44649ab747fSPaolo Bonzini {
44749ab747fSPaolo Bonzini /* RU received a complete frame. */
44849ab747fSPaolo Bonzini eepro100_interrupt(s, 0x40);
44949ab747fSPaolo Bonzini }
45049ab747fSPaolo Bonzini
eepro100_rnr_interrupt(EEPRO100State * s)45149ab747fSPaolo Bonzini static void eepro100_rnr_interrupt(EEPRO100State * s)
45249ab747fSPaolo Bonzini {
45349ab747fSPaolo Bonzini /* RU is not ready. */
45449ab747fSPaolo Bonzini eepro100_interrupt(s, 0x10);
45549ab747fSPaolo Bonzini }
45649ab747fSPaolo Bonzini
eepro100_mdi_interrupt(EEPRO100State * s)45749ab747fSPaolo Bonzini static void eepro100_mdi_interrupt(EEPRO100State * s)
45849ab747fSPaolo Bonzini {
45949ab747fSPaolo Bonzini /* MDI completed read or write cycle. */
46049ab747fSPaolo Bonzini eepro100_interrupt(s, 0x08);
46149ab747fSPaolo Bonzini }
46249ab747fSPaolo Bonzini
eepro100_swi_interrupt(EEPRO100State * s)46349ab747fSPaolo Bonzini static void eepro100_swi_interrupt(EEPRO100State * s)
46449ab747fSPaolo Bonzini {
46549ab747fSPaolo Bonzini /* Software has requested an interrupt. */
46649ab747fSPaolo Bonzini eepro100_interrupt(s, 0x04);
46749ab747fSPaolo Bonzini }
46849ab747fSPaolo Bonzini
46949ab747fSPaolo Bonzini #if 0
47049ab747fSPaolo Bonzini static void eepro100_fcp_interrupt(EEPRO100State * s)
47149ab747fSPaolo Bonzini {
47249ab747fSPaolo Bonzini /* Flow control pause interrupt (82558 and later). */
47349ab747fSPaolo Bonzini eepro100_interrupt(s, 0x01);
47449ab747fSPaolo Bonzini }
47549ab747fSPaolo Bonzini #endif
47649ab747fSPaolo Bonzini
e100_pci_reset(EEPRO100State * s,Error ** errp)4779a7c2a59SMao Zhongyi static void e100_pci_reset(EEPRO100State *s, Error **errp)
47849ab747fSPaolo Bonzini {
47949ab747fSPaolo Bonzini E100PCIDeviceInfo *info = eepro100_get_class(s);
48049ab747fSPaolo Bonzini uint32_t device = s->device;
48149ab747fSPaolo Bonzini uint8_t *pci_conf = s->dev.config;
48249ab747fSPaolo Bonzini
48349ab747fSPaolo Bonzini TRACE(OTHER, logout("%p\n", s));
48449ab747fSPaolo Bonzini
48549ab747fSPaolo Bonzini /* PCI Status */
48649ab747fSPaolo Bonzini pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
48749ab747fSPaolo Bonzini PCI_STATUS_FAST_BACK);
48849ab747fSPaolo Bonzini /* PCI Latency Timer */
48949ab747fSPaolo Bonzini pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20); /* latency timer = 32 clocks */
49049ab747fSPaolo Bonzini /* Capability Pointer is set by PCI framework. */
49149ab747fSPaolo Bonzini /* Interrupt Line */
49249ab747fSPaolo Bonzini /* Interrupt Pin */
49349ab747fSPaolo Bonzini pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1); /* interrupt pin A */
49449ab747fSPaolo Bonzini /* Minimum Grant */
49549ab747fSPaolo Bonzini pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
49649ab747fSPaolo Bonzini /* Maximum Latency */
49749ab747fSPaolo Bonzini pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
49849ab747fSPaolo Bonzini
49949ab747fSPaolo Bonzini s->stats_size = info->stats_size;
50049ab747fSPaolo Bonzini s->has_extended_tcb_support = info->has_extended_tcb_support;
50149ab747fSPaolo Bonzini
50249ab747fSPaolo Bonzini switch (device) {
50349ab747fSPaolo Bonzini case i82550:
50449ab747fSPaolo Bonzini case i82551:
50549ab747fSPaolo Bonzini case i82557A:
50649ab747fSPaolo Bonzini case i82557B:
50749ab747fSPaolo Bonzini case i82557C:
50849ab747fSPaolo Bonzini case i82558A:
50949ab747fSPaolo Bonzini case i82558B:
51049ab747fSPaolo Bonzini case i82559A:
51149ab747fSPaolo Bonzini case i82559B:
51249ab747fSPaolo Bonzini case i82559ER:
51349ab747fSPaolo Bonzini case i82562:
51449ab747fSPaolo Bonzini case i82801:
51549ab747fSPaolo Bonzini case i82559C:
51649ab747fSPaolo Bonzini break;
51749ab747fSPaolo Bonzini default:
51849ab747fSPaolo Bonzini logout("Device %X is undefined!\n", device);
51949ab747fSPaolo Bonzini }
52049ab747fSPaolo Bonzini
52149ab747fSPaolo Bonzini /* Standard TxCB. */
52249ab747fSPaolo Bonzini s->configuration[6] |= BIT(4);
52349ab747fSPaolo Bonzini
52449ab747fSPaolo Bonzini /* Standard statistical counters. */
52549ab747fSPaolo Bonzini s->configuration[6] |= BIT(5);
52649ab747fSPaolo Bonzini
52749ab747fSPaolo Bonzini if (s->stats_size == 80) {
52849ab747fSPaolo Bonzini /* TODO: check TCO Statistical Counters bit. Documentation not clear. */
52949ab747fSPaolo Bonzini if (s->configuration[6] & BIT(2)) {
53049ab747fSPaolo Bonzini /* TCO statistical counters. */
53149ab747fSPaolo Bonzini assert(s->configuration[6] & BIT(5));
53249ab747fSPaolo Bonzini } else {
53349ab747fSPaolo Bonzini if (s->configuration[6] & BIT(5)) {
53449ab747fSPaolo Bonzini /* No extended statistical counters, i82557 compatible. */
53549ab747fSPaolo Bonzini s->stats_size = 64;
53649ab747fSPaolo Bonzini } else {
53749ab747fSPaolo Bonzini /* i82558 compatible. */
53849ab747fSPaolo Bonzini s->stats_size = 76;
53949ab747fSPaolo Bonzini }
54049ab747fSPaolo Bonzini }
54149ab747fSPaolo Bonzini } else {
54249ab747fSPaolo Bonzini if (s->configuration[6] & BIT(5)) {
54349ab747fSPaolo Bonzini /* No extended statistical counters. */
54449ab747fSPaolo Bonzini s->stats_size = 64;
54549ab747fSPaolo Bonzini }
54649ab747fSPaolo Bonzini }
54749ab747fSPaolo Bonzini assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
54849ab747fSPaolo Bonzini
54949ab747fSPaolo Bonzini if (info->power_management) {
55049ab747fSPaolo Bonzini /* Power Management Capabilities */
55149ab747fSPaolo Bonzini int cfg_offset = 0xdc;
55249ab747fSPaolo Bonzini int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
5539a7c2a59SMao Zhongyi cfg_offset, PCI_PM_SIZEOF,
5549a7c2a59SMao Zhongyi errp);
5559a7c2a59SMao Zhongyi if (r < 0) {
5569a7c2a59SMao Zhongyi return;
5579a7c2a59SMao Zhongyi }
5589a7c2a59SMao Zhongyi
55949ab747fSPaolo Bonzini pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
56049ab747fSPaolo Bonzini #if 0 /* TODO: replace dummy code for power management emulation. */
56149ab747fSPaolo Bonzini /* TODO: Power Management Control / Status. */
56249ab747fSPaolo Bonzini pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
56349ab747fSPaolo Bonzini /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
56449ab747fSPaolo Bonzini pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
56549ab747fSPaolo Bonzini #endif
56649ab747fSPaolo Bonzini }
56749ab747fSPaolo Bonzini
56849ab747fSPaolo Bonzini #if EEPROM_SIZE > 0
56949ab747fSPaolo Bonzini if (device == i82557C || device == i82558B || device == i82559C) {
57049ab747fSPaolo Bonzini /*
57149ab747fSPaolo Bonzini TODO: get vendor id from EEPROM for i82557C or later.
57249ab747fSPaolo Bonzini TODO: get device id from EEPROM for i82557C or later.
57349ab747fSPaolo Bonzini TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
57449ab747fSPaolo Bonzini TODO: header type is determined by EEPROM for i82559.
57549ab747fSPaolo Bonzini TODO: get subsystem id from EEPROM for i82557C or later.
57649ab747fSPaolo Bonzini TODO: get subsystem vendor id from EEPROM for i82557C or later.
57749ab747fSPaolo Bonzini TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
57849ab747fSPaolo Bonzini TODO: capability pointer depends on EEPROM for i82558.
57949ab747fSPaolo Bonzini */
58049ab747fSPaolo Bonzini logout("Get device id and revision from EEPROM!!!\n");
58149ab747fSPaolo Bonzini }
58249ab747fSPaolo Bonzini #endif /* EEPROM_SIZE > 0 */
58349ab747fSPaolo Bonzini }
58449ab747fSPaolo Bonzini
nic_selective_reset(EEPRO100State * s)58549ab747fSPaolo Bonzini static void nic_selective_reset(EEPRO100State * s)
58649ab747fSPaolo Bonzini {
58749ab747fSPaolo Bonzini size_t i;
58849ab747fSPaolo Bonzini uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
58949ab747fSPaolo Bonzini #if 0
59049ab747fSPaolo Bonzini eeprom93xx_reset(s->eeprom);
59149ab747fSPaolo Bonzini #endif
59249ab747fSPaolo Bonzini memcpy(eeprom_contents, s->conf.macaddr.a, 6);
59349ab747fSPaolo Bonzini eeprom_contents[EEPROM_ID] = EEPROM_ID_VALID;
59449ab747fSPaolo Bonzini if (s->device == i82557B || s->device == i82557C)
59549ab747fSPaolo Bonzini eeprom_contents[5] = 0x0100;
59649ab747fSPaolo Bonzini eeprom_contents[EEPROM_PHY_ID] = 1;
59749ab747fSPaolo Bonzini uint16_t sum = 0;
59849ab747fSPaolo Bonzini for (i = 0; i < EEPROM_SIZE - 1; i++) {
59949ab747fSPaolo Bonzini sum += eeprom_contents[i];
60049ab747fSPaolo Bonzini }
60149ab747fSPaolo Bonzini eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
60249ab747fSPaolo Bonzini TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
60349ab747fSPaolo Bonzini
60449ab747fSPaolo Bonzini memset(s->mem, 0, sizeof(s->mem));
60549ab747fSPaolo Bonzini e100_write_reg4(s, SCBCtrlMDI, BIT(21));
60649ab747fSPaolo Bonzini
60749ab747fSPaolo Bonzini assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
60849ab747fSPaolo Bonzini memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
60949ab747fSPaolo Bonzini }
61049ab747fSPaolo Bonzini
nic_reset(void * opaque)61149ab747fSPaolo Bonzini static void nic_reset(void *opaque)
61249ab747fSPaolo Bonzini {
61349ab747fSPaolo Bonzini EEPRO100State *s = opaque;
61449ab747fSPaolo Bonzini TRACE(OTHER, logout("%p\n", s));
61549ab747fSPaolo Bonzini /* TODO: Clearing of hash register for selective reset, too? */
61649ab747fSPaolo Bonzini memset(&s->mult[0], 0, sizeof(s->mult));
61749ab747fSPaolo Bonzini nic_selective_reset(s);
61849ab747fSPaolo Bonzini }
61949ab747fSPaolo Bonzini
62049ab747fSPaolo Bonzini #if defined(DEBUG_EEPRO100)
62149ab747fSPaolo Bonzini static const char * const e100_reg[PCI_IO_SIZE / 4] = {
62249ab747fSPaolo Bonzini "Command/Status",
62349ab747fSPaolo Bonzini "General Pointer",
62449ab747fSPaolo Bonzini "Port",
62549ab747fSPaolo Bonzini "EEPROM/Flash Control",
62649ab747fSPaolo Bonzini "MDI Control",
62749ab747fSPaolo Bonzini "Receive DMA Byte Count",
62849ab747fSPaolo Bonzini "Flow Control",
62949ab747fSPaolo Bonzini "General Status/Control"
63049ab747fSPaolo Bonzini };
63149ab747fSPaolo Bonzini
regname(uint32_t addr)63249ab747fSPaolo Bonzini static char *regname(uint32_t addr)
63349ab747fSPaolo Bonzini {
63449ab747fSPaolo Bonzini static char buf[32];
63549ab747fSPaolo Bonzini if (addr < PCI_IO_SIZE) {
63649ab747fSPaolo Bonzini const char *r = e100_reg[addr / 4];
63749ab747fSPaolo Bonzini if (r != 0) {
63849ab747fSPaolo Bonzini snprintf(buf, sizeof(buf), "%s+%u", r, addr % 4);
63949ab747fSPaolo Bonzini } else {
64049ab747fSPaolo Bonzini snprintf(buf, sizeof(buf), "0x%02x", addr);
64149ab747fSPaolo Bonzini }
64249ab747fSPaolo Bonzini } else {
64349ab747fSPaolo Bonzini snprintf(buf, sizeof(buf), "??? 0x%08x", addr);
64449ab747fSPaolo Bonzini }
64549ab747fSPaolo Bonzini return buf;
64649ab747fSPaolo Bonzini }
64749ab747fSPaolo Bonzini #endif /* DEBUG_EEPRO100 */
64849ab747fSPaolo Bonzini
64949ab747fSPaolo Bonzini /*****************************************************************************
65049ab747fSPaolo Bonzini *
65149ab747fSPaolo Bonzini * Command emulation.
65249ab747fSPaolo Bonzini *
65349ab747fSPaolo Bonzini ****************************************************************************/
65449ab747fSPaolo Bonzini
65549ab747fSPaolo Bonzini #if 0
65649ab747fSPaolo Bonzini static uint16_t eepro100_read_command(EEPRO100State * s)
65749ab747fSPaolo Bonzini {
65849ab747fSPaolo Bonzini uint16_t val = 0xffff;
65949ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%04x\n", val));
66049ab747fSPaolo Bonzini return val;
66149ab747fSPaolo Bonzini }
66249ab747fSPaolo Bonzini #endif
66349ab747fSPaolo Bonzini
66449ab747fSPaolo Bonzini /* Commands that can be put in a command list entry. */
66549ab747fSPaolo Bonzini enum commands {
66649ab747fSPaolo Bonzini CmdNOp = 0,
66749ab747fSPaolo Bonzini CmdIASetup = 1,
66849ab747fSPaolo Bonzini CmdConfigure = 2,
66949ab747fSPaolo Bonzini CmdMulticastList = 3,
67049ab747fSPaolo Bonzini CmdTx = 4,
67149ab747fSPaolo Bonzini CmdTDR = 5, /* load microcode */
67249ab747fSPaolo Bonzini CmdDump = 6,
67349ab747fSPaolo Bonzini CmdDiagnose = 7,
67449ab747fSPaolo Bonzini
67549ab747fSPaolo Bonzini /* And some extra flags: */
67649ab747fSPaolo Bonzini CmdSuspend = 0x4000, /* Suspend after completion. */
67749ab747fSPaolo Bonzini CmdIntr = 0x2000, /* Interrupt after completion. */
67849ab747fSPaolo Bonzini CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */
67949ab747fSPaolo Bonzini };
68049ab747fSPaolo Bonzini
get_cu_state(EEPRO100State * s)68149ab747fSPaolo Bonzini static cu_state_t get_cu_state(EEPRO100State * s)
68249ab747fSPaolo Bonzini {
68349ab747fSPaolo Bonzini return ((s->mem[SCBStatus] & BITS(7, 6)) >> 6);
68449ab747fSPaolo Bonzini }
68549ab747fSPaolo Bonzini
set_cu_state(EEPRO100State * s,cu_state_t state)68649ab747fSPaolo Bonzini static void set_cu_state(EEPRO100State * s, cu_state_t state)
68749ab747fSPaolo Bonzini {
68849ab747fSPaolo Bonzini s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(7, 6)) + (state << 6);
68949ab747fSPaolo Bonzini }
69049ab747fSPaolo Bonzini
get_ru_state(EEPRO100State * s)69149ab747fSPaolo Bonzini static ru_state_t get_ru_state(EEPRO100State * s)
69249ab747fSPaolo Bonzini {
69349ab747fSPaolo Bonzini return ((s->mem[SCBStatus] & BITS(5, 2)) >> 2);
69449ab747fSPaolo Bonzini }
69549ab747fSPaolo Bonzini
set_ru_state(EEPRO100State * s,ru_state_t state)69649ab747fSPaolo Bonzini static void set_ru_state(EEPRO100State * s, ru_state_t state)
69749ab747fSPaolo Bonzini {
69849ab747fSPaolo Bonzini s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(5, 2)) + (state << 2);
69949ab747fSPaolo Bonzini }
70049ab747fSPaolo Bonzini
dump_statistics(EEPRO100State * s)70149ab747fSPaolo Bonzini static void dump_statistics(EEPRO100State * s)
70249ab747fSPaolo Bonzini {
703a423a1b5SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
704a423a1b5SPhilippe Mathieu-Daudé
70549ab747fSPaolo Bonzini /* Dump statistical data. Most data is never changed by the emulation
70649ab747fSPaolo Bonzini * and always 0, so we first just copy the whole block and then those
70749ab747fSPaolo Bonzini * values which really matter.
70849ab747fSPaolo Bonzini * Number of data should check configuration!!!
70949ab747fSPaolo Bonzini */
71049ab747fSPaolo Bonzini pci_dma_write(&s->dev, s->statsaddr, &s->statistics, s->stats_size);
71149ab747fSPaolo Bonzini stl_le_pci_dma(&s->dev, s->statsaddr + 0,
712a423a1b5SPhilippe Mathieu-Daudé s->statistics.tx_good_frames, attrs);
71349ab747fSPaolo Bonzini stl_le_pci_dma(&s->dev, s->statsaddr + 36,
714a423a1b5SPhilippe Mathieu-Daudé s->statistics.rx_good_frames, attrs);
71549ab747fSPaolo Bonzini stl_le_pci_dma(&s->dev, s->statsaddr + 48,
716a423a1b5SPhilippe Mathieu-Daudé s->statistics.rx_resource_errors, attrs);
71749ab747fSPaolo Bonzini stl_le_pci_dma(&s->dev, s->statsaddr + 60,
718a423a1b5SPhilippe Mathieu-Daudé s->statistics.rx_short_frame_errors, attrs);
71949ab747fSPaolo Bonzini #if 0
720a423a1b5SPhilippe Mathieu-Daudé stw_le_pci_dma(&s->dev, s->statsaddr + 76,
721a423a1b5SPhilippe Mathieu-Daudé s->statistics.xmt_tco_frames, attrs);
722a423a1b5SPhilippe Mathieu-Daudé stw_le_pci_dma(&s->dev, s->statsaddr + 78,
723a423a1b5SPhilippe Mathieu-Daudé s->statistics.rcv_tco_frames, attrs);
72449ab747fSPaolo Bonzini missing("CU dump statistical counters");
72549ab747fSPaolo Bonzini #endif
72649ab747fSPaolo Bonzini }
72749ab747fSPaolo Bonzini
read_cb(EEPRO100State * s)72849ab747fSPaolo Bonzini static void read_cb(EEPRO100State *s)
72949ab747fSPaolo Bonzini {
73049ab747fSPaolo Bonzini pci_dma_read(&s->dev, s->cb_address, &s->tx, sizeof(s->tx));
73149ab747fSPaolo Bonzini s->tx.status = le16_to_cpu(s->tx.status);
73249ab747fSPaolo Bonzini s->tx.command = le16_to_cpu(s->tx.command);
73349ab747fSPaolo Bonzini s->tx.link = le32_to_cpu(s->tx.link);
73449ab747fSPaolo Bonzini s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
73549ab747fSPaolo Bonzini s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
73649ab747fSPaolo Bonzini }
73749ab747fSPaolo Bonzini
tx_command(EEPRO100State * s)73849ab747fSPaolo Bonzini static void tx_command(EEPRO100State *s)
73949ab747fSPaolo Bonzini {
740398f9a84SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
7418f8e8053SThomas Huth uint32_t tbd_array = s->tx.tbd_array_addr;
7428f8e8053SThomas Huth uint16_t tcb_bytes = s->tx.tcb_bytes & 0x3fff;
74349ab747fSPaolo Bonzini /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
74449ab747fSPaolo Bonzini uint8_t buf[2600];
74549ab747fSPaolo Bonzini uint16_t size = 0;
74649ab747fSPaolo Bonzini uint32_t tbd_address = s->cb_address + 0x10;
74749ab747fSPaolo Bonzini TRACE(RXTX, logout
74849ab747fSPaolo Bonzini ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
74949ab747fSPaolo Bonzini tbd_array, tcb_bytes, s->tx.tbd_count));
75049ab747fSPaolo Bonzini
75149ab747fSPaolo Bonzini if (tcb_bytes > 2600) {
75249ab747fSPaolo Bonzini logout("TCB byte count too large, using 2600\n");
75349ab747fSPaolo Bonzini tcb_bytes = 2600;
75449ab747fSPaolo Bonzini }
75549ab747fSPaolo Bonzini if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
75649ab747fSPaolo Bonzini logout
75749ab747fSPaolo Bonzini ("illegal values of TBD array address and TCB byte count!\n");
75849ab747fSPaolo Bonzini }
75949ab747fSPaolo Bonzini assert(tcb_bytes <= sizeof(buf));
76049ab747fSPaolo Bonzini while (size < tcb_bytes) {
76149ab747fSPaolo Bonzini TRACE(RXTX, logout
76249ab747fSPaolo Bonzini ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
7631865e288SMike Nawrocki tbd_address, tcb_bytes));
7641865e288SMike Nawrocki pci_dma_read(&s->dev, tbd_address, &buf[size], tcb_bytes);
7651865e288SMike Nawrocki size += tcb_bytes;
76649ab747fSPaolo Bonzini }
76749ab747fSPaolo Bonzini if (tbd_array == 0xffffffff) {
76849ab747fSPaolo Bonzini /* Simplified mode. Was already handled by code above. */
76949ab747fSPaolo Bonzini } else {
77049ab747fSPaolo Bonzini /* Flexible mode. */
77149ab747fSPaolo Bonzini uint8_t tbd_count = 0;
7724a63054bSPhilippe Mathieu-Daudé uint32_t tx_buffer_address;
7734a63054bSPhilippe Mathieu-Daudé uint16_t tx_buffer_size;
7744a63054bSPhilippe Mathieu-Daudé uint16_t tx_buffer_el;
7754a63054bSPhilippe Mathieu-Daudé
77649ab747fSPaolo Bonzini if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
77749ab747fSPaolo Bonzini /* Extended Flexible TCB. */
77849ab747fSPaolo Bonzini for (; tbd_count < 2; tbd_count++) {
7794a63054bSPhilippe Mathieu-Daudé ldl_le_pci_dma(&s->dev, tbd_address, &tx_buffer_address, attrs);
7804a63054bSPhilippe Mathieu-Daudé lduw_le_pci_dma(&s->dev, tbd_address + 4, &tx_buffer_size, attrs);
7814a63054bSPhilippe Mathieu-Daudé lduw_le_pci_dma(&s->dev, tbd_address + 6, &tx_buffer_el, attrs);
78249ab747fSPaolo Bonzini tbd_address += 8;
78349ab747fSPaolo Bonzini TRACE(RXTX, logout
78449ab747fSPaolo Bonzini ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
78549ab747fSPaolo Bonzini tx_buffer_address, tx_buffer_size));
78649ab747fSPaolo Bonzini tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
78749ab747fSPaolo Bonzini pci_dma_read(&s->dev, tx_buffer_address,
78849ab747fSPaolo Bonzini &buf[size], tx_buffer_size);
78949ab747fSPaolo Bonzini size += tx_buffer_size;
79049ab747fSPaolo Bonzini if (tx_buffer_el & 1) {
79149ab747fSPaolo Bonzini break;
79249ab747fSPaolo Bonzini }
79349ab747fSPaolo Bonzini }
79449ab747fSPaolo Bonzini }
79549ab747fSPaolo Bonzini tbd_address = tbd_array;
79649ab747fSPaolo Bonzini for (; tbd_count < s->tx.tbd_count; tbd_count++) {
7974a63054bSPhilippe Mathieu-Daudé ldl_le_pci_dma(&s->dev, tbd_address, &tx_buffer_address, attrs);
7984a63054bSPhilippe Mathieu-Daudé lduw_le_pci_dma(&s->dev, tbd_address + 4, &tx_buffer_size, attrs);
7994a63054bSPhilippe Mathieu-Daudé lduw_le_pci_dma(&s->dev, tbd_address + 6, &tx_buffer_el, attrs);
80049ab747fSPaolo Bonzini tbd_address += 8;
80149ab747fSPaolo Bonzini TRACE(RXTX, logout
80249ab747fSPaolo Bonzini ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
80349ab747fSPaolo Bonzini tx_buffer_address, tx_buffer_size));
80449ab747fSPaolo Bonzini tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
80549ab747fSPaolo Bonzini pci_dma_read(&s->dev, tx_buffer_address,
80649ab747fSPaolo Bonzini &buf[size], tx_buffer_size);
80749ab747fSPaolo Bonzini size += tx_buffer_size;
80849ab747fSPaolo Bonzini if (tx_buffer_el & 1) {
80949ab747fSPaolo Bonzini break;
81049ab747fSPaolo Bonzini }
81149ab747fSPaolo Bonzini }
81249ab747fSPaolo Bonzini }
81349ab747fSPaolo Bonzini TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size)));
81449ab747fSPaolo Bonzini qemu_send_packet(qemu_get_queue(s->nic), buf, size);
81549ab747fSPaolo Bonzini s->statistics.tx_good_frames++;
81649ab747fSPaolo Bonzini /* Transmit with bad status would raise an CX/TNO interrupt.
81749ab747fSPaolo Bonzini * (82557 only). Emulation never has bad status. */
81849ab747fSPaolo Bonzini #if 0
81949ab747fSPaolo Bonzini eepro100_cx_interrupt(s);
82049ab747fSPaolo Bonzini #endif
82149ab747fSPaolo Bonzini }
82249ab747fSPaolo Bonzini
set_multicast_list(EEPRO100State * s)82349ab747fSPaolo Bonzini static void set_multicast_list(EEPRO100State *s)
82449ab747fSPaolo Bonzini {
82549ab747fSPaolo Bonzini uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0);
82649ab747fSPaolo Bonzini uint16_t i;
82749ab747fSPaolo Bonzini memset(&s->mult[0], 0, sizeof(s->mult));
82849ab747fSPaolo Bonzini TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
82949ab747fSPaolo Bonzini for (i = 0; i < multicast_count; i += 6) {
83049ab747fSPaolo Bonzini uint8_t multicast_addr[6];
83149ab747fSPaolo Bonzini pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
83249ab747fSPaolo Bonzini TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
8337c0348bdSMark Cave-Ayland unsigned mcast_idx = (net_crc32(multicast_addr, ETH_ALEN) &
8347c0348bdSMark Cave-Ayland BITS(7, 2)) >> 2;
83549ab747fSPaolo Bonzini assert(mcast_idx < 64);
83649ab747fSPaolo Bonzini s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
83749ab747fSPaolo Bonzini }
83849ab747fSPaolo Bonzini }
83949ab747fSPaolo Bonzini
action_command(EEPRO100State * s)84049ab747fSPaolo Bonzini static void action_command(EEPRO100State *s)
84149ab747fSPaolo Bonzini {
842a423a1b5SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
84300837731SStefan Weil /* The loop below won't stop if it gets special handcrafted data.
84400837731SStefan Weil Therefore we limit the number of iterations. */
84500837731SStefan Weil unsigned max_loop_count = 16;
84600837731SStefan Weil
84749ab747fSPaolo Bonzini for (;;) {
84849ab747fSPaolo Bonzini bool bit_el;
84949ab747fSPaolo Bonzini bool bit_s;
85049ab747fSPaolo Bonzini bool bit_i;
85149ab747fSPaolo Bonzini bool bit_nc;
85249ab747fSPaolo Bonzini uint16_t ok_status = STATUS_OK;
85349ab747fSPaolo Bonzini s->cb_address = s->cu_base + s->cu_offset;
85449ab747fSPaolo Bonzini read_cb(s);
85549ab747fSPaolo Bonzini bit_el = ((s->tx.command & COMMAND_EL) != 0);
85649ab747fSPaolo Bonzini bit_s = ((s->tx.command & COMMAND_S) != 0);
85749ab747fSPaolo Bonzini bit_i = ((s->tx.command & COMMAND_I) != 0);
85849ab747fSPaolo Bonzini bit_nc = ((s->tx.command & COMMAND_NC) != 0);
85949ab747fSPaolo Bonzini #if 0
86049ab747fSPaolo Bonzini bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
86149ab747fSPaolo Bonzini #endif
86200837731SStefan Weil
86300837731SStefan Weil if (max_loop_count-- == 0) {
86400837731SStefan Weil /* Prevent an endless loop. */
86500837731SStefan Weil logout("loop in %s:%u\n", __FILE__, __LINE__);
86600837731SStefan Weil break;
86700837731SStefan Weil }
86800837731SStefan Weil
86949ab747fSPaolo Bonzini s->cu_offset = s->tx.link;
87049ab747fSPaolo Bonzini TRACE(OTHER,
87149ab747fSPaolo Bonzini logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
87249ab747fSPaolo Bonzini s->tx.status, s->tx.command, s->tx.link));
87349ab747fSPaolo Bonzini switch (s->tx.command & COMMAND_CMD) {
87449ab747fSPaolo Bonzini case CmdNOp:
87549ab747fSPaolo Bonzini /* Do nothing. */
87649ab747fSPaolo Bonzini break;
87749ab747fSPaolo Bonzini case CmdIASetup:
87849ab747fSPaolo Bonzini pci_dma_read(&s->dev, s->cb_address + 8, &s->conf.macaddr.a[0], 6);
87949ab747fSPaolo Bonzini TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
88049ab747fSPaolo Bonzini break;
88149ab747fSPaolo Bonzini case CmdConfigure:
88249ab747fSPaolo Bonzini pci_dma_read(&s->dev, s->cb_address + 8,
88349ab747fSPaolo Bonzini &s->configuration[0], sizeof(s->configuration));
88449ab747fSPaolo Bonzini TRACE(OTHER, logout("configuration: %s\n",
88549ab747fSPaolo Bonzini nic_dump(&s->configuration[0], 16)));
88649ab747fSPaolo Bonzini TRACE(OTHER, logout("configuration: %s\n",
88749ab747fSPaolo Bonzini nic_dump(&s->configuration[16],
88849ab747fSPaolo Bonzini ARRAY_SIZE(s->configuration) - 16)));
88949ab747fSPaolo Bonzini if (s->configuration[20] & BIT(6)) {
89049ab747fSPaolo Bonzini TRACE(OTHER, logout("Multiple IA bit\n"));
89149ab747fSPaolo Bonzini }
89249ab747fSPaolo Bonzini break;
89349ab747fSPaolo Bonzini case CmdMulticastList:
89449ab747fSPaolo Bonzini set_multicast_list(s);
89549ab747fSPaolo Bonzini break;
89649ab747fSPaolo Bonzini case CmdTx:
89749ab747fSPaolo Bonzini if (bit_nc) {
89849ab747fSPaolo Bonzini missing("CmdTx: NC = 0");
89949ab747fSPaolo Bonzini ok_status = 0;
90049ab747fSPaolo Bonzini break;
90149ab747fSPaolo Bonzini }
90249ab747fSPaolo Bonzini tx_command(s);
90349ab747fSPaolo Bonzini break;
90449ab747fSPaolo Bonzini case CmdTDR:
90549ab747fSPaolo Bonzini TRACE(OTHER, logout("load microcode\n"));
90649ab747fSPaolo Bonzini /* Starting with offset 8, the command contains
90749ab747fSPaolo Bonzini * 64 dwords microcode which we just ignore here. */
90849ab747fSPaolo Bonzini break;
90949ab747fSPaolo Bonzini case CmdDiagnose:
91049ab747fSPaolo Bonzini TRACE(OTHER, logout("diagnose\n"));
91149ab747fSPaolo Bonzini /* Make sure error flag is not set. */
91249ab747fSPaolo Bonzini s->tx.status = 0;
91349ab747fSPaolo Bonzini break;
91449ab747fSPaolo Bonzini default:
91549ab747fSPaolo Bonzini missing("undefined command");
91649ab747fSPaolo Bonzini ok_status = 0;
91749ab747fSPaolo Bonzini break;
91849ab747fSPaolo Bonzini }
91949ab747fSPaolo Bonzini /* Write new status. */
92049ab747fSPaolo Bonzini stw_le_pci_dma(&s->dev, s->cb_address,
921a423a1b5SPhilippe Mathieu-Daudé s->tx.status | ok_status | STATUS_C, attrs);
92249ab747fSPaolo Bonzini if (bit_i) {
92349ab747fSPaolo Bonzini /* CU completed action. */
92449ab747fSPaolo Bonzini eepro100_cx_interrupt(s);
92549ab747fSPaolo Bonzini }
92649ab747fSPaolo Bonzini if (bit_el) {
92749ab747fSPaolo Bonzini /* CU becomes idle. Terminate command loop. */
92849ab747fSPaolo Bonzini set_cu_state(s, cu_idle);
92949ab747fSPaolo Bonzini eepro100_cna_interrupt(s);
93049ab747fSPaolo Bonzini break;
93149ab747fSPaolo Bonzini } else if (bit_s) {
93249ab747fSPaolo Bonzini /* CU becomes suspended. Terminate command loop. */
93349ab747fSPaolo Bonzini set_cu_state(s, cu_suspended);
93449ab747fSPaolo Bonzini eepro100_cna_interrupt(s);
93549ab747fSPaolo Bonzini break;
93649ab747fSPaolo Bonzini } else {
93749ab747fSPaolo Bonzini /* More entries in list. */
93849ab747fSPaolo Bonzini TRACE(OTHER, logout("CU list with at least one more entry\n"));
93949ab747fSPaolo Bonzini }
94049ab747fSPaolo Bonzini }
94149ab747fSPaolo Bonzini TRACE(OTHER, logout("CU list empty\n"));
94249ab747fSPaolo Bonzini /* List is empty. Now CU is idle or suspended. */
94349ab747fSPaolo Bonzini }
94449ab747fSPaolo Bonzini
eepro100_cu_command(EEPRO100State * s,uint8_t val)94549ab747fSPaolo Bonzini static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
94649ab747fSPaolo Bonzini {
947a423a1b5SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
94849ab747fSPaolo Bonzini cu_state_t cu_state;
94949ab747fSPaolo Bonzini switch (val) {
95049ab747fSPaolo Bonzini case CU_NOP:
95149ab747fSPaolo Bonzini /* No operation. */
95249ab747fSPaolo Bonzini break;
95349ab747fSPaolo Bonzini case CU_START:
95449ab747fSPaolo Bonzini cu_state = get_cu_state(s);
95549ab747fSPaolo Bonzini if (cu_state != cu_idle && cu_state != cu_suspended) {
95649ab747fSPaolo Bonzini /* Intel documentation says that CU must be idle or suspended
95749ab747fSPaolo Bonzini * for the CU start command. */
95849ab747fSPaolo Bonzini logout("unexpected CU state is %u\n", cu_state);
95949ab747fSPaolo Bonzini }
96049ab747fSPaolo Bonzini set_cu_state(s, cu_active);
96149ab747fSPaolo Bonzini s->cu_offset = e100_read_reg4(s, SCBPointer);
96249ab747fSPaolo Bonzini action_command(s);
96349ab747fSPaolo Bonzini break;
96449ab747fSPaolo Bonzini case CU_RESUME:
96549ab747fSPaolo Bonzini if (get_cu_state(s) != cu_suspended) {
96649ab747fSPaolo Bonzini logout("bad CU resume from CU state %u\n", get_cu_state(s));
96749ab747fSPaolo Bonzini /* Workaround for bad Linux eepro100 driver which resumes
96849ab747fSPaolo Bonzini * from idle state. */
96949ab747fSPaolo Bonzini #if 0
97049ab747fSPaolo Bonzini missing("cu resume");
97149ab747fSPaolo Bonzini #endif
97249ab747fSPaolo Bonzini set_cu_state(s, cu_suspended);
97349ab747fSPaolo Bonzini }
97449ab747fSPaolo Bonzini if (get_cu_state(s) == cu_suspended) {
97549ab747fSPaolo Bonzini TRACE(OTHER, logout("CU resuming\n"));
97649ab747fSPaolo Bonzini set_cu_state(s, cu_active);
97749ab747fSPaolo Bonzini action_command(s);
97849ab747fSPaolo Bonzini }
97949ab747fSPaolo Bonzini break;
98049ab747fSPaolo Bonzini case CU_STATSADDR:
98149ab747fSPaolo Bonzini /* Load dump counters address. */
98249ab747fSPaolo Bonzini s->statsaddr = e100_read_reg4(s, SCBPointer);
98349ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val));
98449ab747fSPaolo Bonzini if (s->statsaddr & 3) {
98549ab747fSPaolo Bonzini /* Memory must be Dword aligned. */
98649ab747fSPaolo Bonzini logout("unaligned dump counters address\n");
98749ab747fSPaolo Bonzini /* Handling of misaligned addresses is undefined.
98849ab747fSPaolo Bonzini * Here we align the address by ignoring the lower bits. */
98949ab747fSPaolo Bonzini /* TODO: Test unaligned dump counter address on real hardware. */
99049ab747fSPaolo Bonzini s->statsaddr &= ~3;
99149ab747fSPaolo Bonzini }
99249ab747fSPaolo Bonzini break;
99349ab747fSPaolo Bonzini case CU_SHOWSTATS:
99449ab747fSPaolo Bonzini /* Dump statistical counters. */
99549ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
99649ab747fSPaolo Bonzini dump_statistics(s);
997a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005, attrs);
99849ab747fSPaolo Bonzini break;
99949ab747fSPaolo Bonzini case CU_CMD_BASE:
100049ab747fSPaolo Bonzini /* Load CU base. */
100149ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
100249ab747fSPaolo Bonzini s->cu_base = e100_read_reg4(s, SCBPointer);
100349ab747fSPaolo Bonzini break;
100449ab747fSPaolo Bonzini case CU_DUMPSTATS:
100549ab747fSPaolo Bonzini /* Dump and reset statistical counters. */
100649ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
100749ab747fSPaolo Bonzini dump_statistics(s);
1008a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007, attrs);
100949ab747fSPaolo Bonzini memset(&s->statistics, 0, sizeof(s->statistics));
101049ab747fSPaolo Bonzini break;
101149ab747fSPaolo Bonzini case CU_SRESUME:
101249ab747fSPaolo Bonzini /* CU static resume. */
101349ab747fSPaolo Bonzini missing("CU static resume");
101449ab747fSPaolo Bonzini break;
101549ab747fSPaolo Bonzini default:
101649ab747fSPaolo Bonzini missing("Undefined CU command");
101749ab747fSPaolo Bonzini }
101849ab747fSPaolo Bonzini }
101949ab747fSPaolo Bonzini
eepro100_ru_command(EEPRO100State * s,uint8_t val)102049ab747fSPaolo Bonzini static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
102149ab747fSPaolo Bonzini {
102249ab747fSPaolo Bonzini switch (val) {
102349ab747fSPaolo Bonzini case RU_NOP:
102449ab747fSPaolo Bonzini /* No operation. */
102549ab747fSPaolo Bonzini break;
102649ab747fSPaolo Bonzini case RX_START:
102749ab747fSPaolo Bonzini /* RU start. */
102849ab747fSPaolo Bonzini if (get_ru_state(s) != ru_idle) {
102949ab747fSPaolo Bonzini logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
103049ab747fSPaolo Bonzini #if 0
103149ab747fSPaolo Bonzini assert(!"wrong RU state");
103249ab747fSPaolo Bonzini #endif
103349ab747fSPaolo Bonzini }
103449ab747fSPaolo Bonzini set_ru_state(s, ru_ready);
103549ab747fSPaolo Bonzini s->ru_offset = e100_read_reg4(s, SCBPointer);
103649ab747fSPaolo Bonzini qemu_flush_queued_packets(qemu_get_queue(s->nic));
103749ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
103849ab747fSPaolo Bonzini break;
103949ab747fSPaolo Bonzini case RX_RESUME:
104049ab747fSPaolo Bonzini /* Restart RU. */
104149ab747fSPaolo Bonzini if (get_ru_state(s) != ru_suspended) {
104249ab747fSPaolo Bonzini logout("RU state is %u, should be %u\n", get_ru_state(s),
104349ab747fSPaolo Bonzini ru_suspended);
104449ab747fSPaolo Bonzini #if 0
104549ab747fSPaolo Bonzini assert(!"wrong RU state");
104649ab747fSPaolo Bonzini #endif
104749ab747fSPaolo Bonzini }
104849ab747fSPaolo Bonzini set_ru_state(s, ru_ready);
104949ab747fSPaolo Bonzini break;
105049ab747fSPaolo Bonzini case RU_ABORT:
105149ab747fSPaolo Bonzini /* RU abort. */
105249ab747fSPaolo Bonzini if (get_ru_state(s) == ru_ready) {
105349ab747fSPaolo Bonzini eepro100_rnr_interrupt(s);
105449ab747fSPaolo Bonzini }
105549ab747fSPaolo Bonzini set_ru_state(s, ru_idle);
105649ab747fSPaolo Bonzini break;
105749ab747fSPaolo Bonzini case RX_ADDR_LOAD:
105849ab747fSPaolo Bonzini /* Load RU base. */
105949ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
106049ab747fSPaolo Bonzini s->ru_base = e100_read_reg4(s, SCBPointer);
106149ab747fSPaolo Bonzini break;
106249ab747fSPaolo Bonzini default:
106349ab747fSPaolo Bonzini logout("val=0x%02x (undefined RU command)\n", val);
106449ab747fSPaolo Bonzini missing("Undefined SU command");
106549ab747fSPaolo Bonzini }
106649ab747fSPaolo Bonzini }
106749ab747fSPaolo Bonzini
eepro100_write_command(EEPRO100State * s,uint8_t val)106849ab747fSPaolo Bonzini static void eepro100_write_command(EEPRO100State * s, uint8_t val)
106949ab747fSPaolo Bonzini {
107049ab747fSPaolo Bonzini eepro100_ru_command(s, val & 0x0f);
107149ab747fSPaolo Bonzini eepro100_cu_command(s, val & 0xf0);
107249ab747fSPaolo Bonzini if ((val) == 0) {
107349ab747fSPaolo Bonzini TRACE(OTHER, logout("val=0x%02x\n", val));
107449ab747fSPaolo Bonzini }
107549ab747fSPaolo Bonzini /* Clear command byte after command was accepted. */
107649ab747fSPaolo Bonzini s->mem[SCBCmd] = 0;
107749ab747fSPaolo Bonzini }
107849ab747fSPaolo Bonzini
107949ab747fSPaolo Bonzini /*****************************************************************************
108049ab747fSPaolo Bonzini *
108149ab747fSPaolo Bonzini * EEPROM emulation.
108249ab747fSPaolo Bonzini *
108349ab747fSPaolo Bonzini ****************************************************************************/
108449ab747fSPaolo Bonzini
108549ab747fSPaolo Bonzini #define EEPROM_CS 0x02
108649ab747fSPaolo Bonzini #define EEPROM_SK 0x01
108749ab747fSPaolo Bonzini #define EEPROM_DI 0x04
108849ab747fSPaolo Bonzini #define EEPROM_DO 0x08
108949ab747fSPaolo Bonzini
eepro100_read_eeprom(EEPRO100State * s)109049ab747fSPaolo Bonzini static uint16_t eepro100_read_eeprom(EEPRO100State * s)
109149ab747fSPaolo Bonzini {
109249ab747fSPaolo Bonzini uint16_t val = e100_read_reg2(s, SCBeeprom);
109349ab747fSPaolo Bonzini if (eeprom93xx_read(s->eeprom)) {
109449ab747fSPaolo Bonzini val |= EEPROM_DO;
109549ab747fSPaolo Bonzini } else {
109649ab747fSPaolo Bonzini val &= ~EEPROM_DO;
109749ab747fSPaolo Bonzini }
109849ab747fSPaolo Bonzini TRACE(EEPROM, logout("val=0x%04x\n", val));
109949ab747fSPaolo Bonzini return val;
110049ab747fSPaolo Bonzini }
110149ab747fSPaolo Bonzini
eepro100_write_eeprom(eeprom_t * eeprom,uint8_t val)110249ab747fSPaolo Bonzini static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
110349ab747fSPaolo Bonzini {
110449ab747fSPaolo Bonzini TRACE(EEPROM, logout("val=0x%02x\n", val));
110549ab747fSPaolo Bonzini
110649ab747fSPaolo Bonzini /* mask unwritable bits */
110749ab747fSPaolo Bonzini #if 0
110849ab747fSPaolo Bonzini val = SET_MASKED(val, 0x31, eeprom->value);
110949ab747fSPaolo Bonzini #endif
111049ab747fSPaolo Bonzini
111149ab747fSPaolo Bonzini int eecs = ((val & EEPROM_CS) != 0);
111249ab747fSPaolo Bonzini int eesk = ((val & EEPROM_SK) != 0);
111349ab747fSPaolo Bonzini int eedi = ((val & EEPROM_DI) != 0);
111449ab747fSPaolo Bonzini eeprom93xx_write(eeprom, eecs, eesk, eedi);
111549ab747fSPaolo Bonzini }
111649ab747fSPaolo Bonzini
111749ab747fSPaolo Bonzini /*****************************************************************************
111849ab747fSPaolo Bonzini *
111949ab747fSPaolo Bonzini * MDI emulation.
112049ab747fSPaolo Bonzini *
112149ab747fSPaolo Bonzini ****************************************************************************/
112249ab747fSPaolo Bonzini
112349ab747fSPaolo Bonzini #if defined(DEBUG_EEPRO100)
112449ab747fSPaolo Bonzini static const char * const mdi_op_name[] = {
112549ab747fSPaolo Bonzini "opcode 0",
112649ab747fSPaolo Bonzini "write",
112749ab747fSPaolo Bonzini "read",
112849ab747fSPaolo Bonzini "opcode 3"
112949ab747fSPaolo Bonzini };
113049ab747fSPaolo Bonzini
113149ab747fSPaolo Bonzini static const char * const mdi_reg_name[] = {
113249ab747fSPaolo Bonzini "Control",
113349ab747fSPaolo Bonzini "Status",
113449ab747fSPaolo Bonzini "PHY Identification (Word 1)",
113549ab747fSPaolo Bonzini "PHY Identification (Word 2)",
113649ab747fSPaolo Bonzini "Auto-Negotiation Advertisement",
113749ab747fSPaolo Bonzini "Auto-Negotiation Link Partner Ability",
113849ab747fSPaolo Bonzini "Auto-Negotiation Expansion"
113949ab747fSPaolo Bonzini };
114049ab747fSPaolo Bonzini
reg2name(uint8_t reg)114149ab747fSPaolo Bonzini static const char *reg2name(uint8_t reg)
114249ab747fSPaolo Bonzini {
114349ab747fSPaolo Bonzini static char buffer[10];
114449ab747fSPaolo Bonzini const char *p = buffer;
114549ab747fSPaolo Bonzini if (reg < ARRAY_SIZE(mdi_reg_name)) {
114649ab747fSPaolo Bonzini p = mdi_reg_name[reg];
114749ab747fSPaolo Bonzini } else {
114849ab747fSPaolo Bonzini snprintf(buffer, sizeof(buffer), "reg=0x%02x", reg);
114949ab747fSPaolo Bonzini }
115049ab747fSPaolo Bonzini return p;
115149ab747fSPaolo Bonzini }
115249ab747fSPaolo Bonzini #endif /* DEBUG_EEPRO100 */
115349ab747fSPaolo Bonzini
eepro100_read_mdi(EEPRO100State * s)115449ab747fSPaolo Bonzini static uint32_t eepro100_read_mdi(EEPRO100State * s)
115549ab747fSPaolo Bonzini {
115649ab747fSPaolo Bonzini uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
115749ab747fSPaolo Bonzini
115849ab747fSPaolo Bonzini #ifdef DEBUG_EEPRO100
115949ab747fSPaolo Bonzini uint8_t raiseint = (val & BIT(29)) >> 29;
116049ab747fSPaolo Bonzini uint8_t opcode = (val & BITS(27, 26)) >> 26;
116149ab747fSPaolo Bonzini uint8_t phy = (val & BITS(25, 21)) >> 21;
116249ab747fSPaolo Bonzini uint8_t reg = (val & BITS(20, 16)) >> 16;
116349ab747fSPaolo Bonzini uint16_t data = (val & BITS(15, 0));
116449ab747fSPaolo Bonzini #endif
116549ab747fSPaolo Bonzini /* Emulation takes no time to finish MDI transaction. */
116649ab747fSPaolo Bonzini val |= BIT(28);
116749ab747fSPaolo Bonzini TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
116849ab747fSPaolo Bonzini val, raiseint, mdi_op_name[opcode], phy,
116949ab747fSPaolo Bonzini reg2name(reg), data));
117049ab747fSPaolo Bonzini return val;
117149ab747fSPaolo Bonzini }
117249ab747fSPaolo Bonzini
eepro100_write_mdi(EEPRO100State * s)117349ab747fSPaolo Bonzini static void eepro100_write_mdi(EEPRO100State *s)
117449ab747fSPaolo Bonzini {
117549ab747fSPaolo Bonzini uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
117649ab747fSPaolo Bonzini uint8_t raiseint = (val & BIT(29)) >> 29;
117749ab747fSPaolo Bonzini uint8_t opcode = (val & BITS(27, 26)) >> 26;
117849ab747fSPaolo Bonzini uint8_t phy = (val & BITS(25, 21)) >> 21;
117949ab747fSPaolo Bonzini uint8_t reg = (val & BITS(20, 16)) >> 16;
118049ab747fSPaolo Bonzini uint16_t data = (val & BITS(15, 0));
118149ab747fSPaolo Bonzini TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
118249ab747fSPaolo Bonzini val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
118349ab747fSPaolo Bonzini if (phy != 1) {
118449ab747fSPaolo Bonzini /* Unsupported PHY address. */
118549ab747fSPaolo Bonzini #if 0
118649ab747fSPaolo Bonzini logout("phy must be 1 but is %u\n", phy);
118749ab747fSPaolo Bonzini #endif
118849ab747fSPaolo Bonzini data = 0;
118949ab747fSPaolo Bonzini } else if (opcode != 1 && opcode != 2) {
119049ab747fSPaolo Bonzini /* Unsupported opcode. */
119149ab747fSPaolo Bonzini logout("opcode must be 1 or 2 but is %u\n", opcode);
119249ab747fSPaolo Bonzini data = 0;
119349ab747fSPaolo Bonzini } else if (reg > 6) {
119449ab747fSPaolo Bonzini /* Unsupported register. */
119549ab747fSPaolo Bonzini logout("register must be 0...6 but is %u\n", reg);
119649ab747fSPaolo Bonzini data = 0;
119749ab747fSPaolo Bonzini } else {
119849ab747fSPaolo Bonzini TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
119949ab747fSPaolo Bonzini val, raiseint, mdi_op_name[opcode], phy,
120049ab747fSPaolo Bonzini reg2name(reg), data));
120149ab747fSPaolo Bonzini if (opcode == 1) {
120249ab747fSPaolo Bonzini /* MDI write */
120349ab747fSPaolo Bonzini switch (reg) {
120449ab747fSPaolo Bonzini case 0: /* Control Register */
120549ab747fSPaolo Bonzini if (data & 0x8000) {
120649ab747fSPaolo Bonzini /* Reset status and control registers to default. */
120749ab747fSPaolo Bonzini s->mdimem[0] = eepro100_mdi_default[0];
120849ab747fSPaolo Bonzini s->mdimem[1] = eepro100_mdi_default[1];
120949ab747fSPaolo Bonzini data = s->mdimem[reg];
121049ab747fSPaolo Bonzini } else {
121149ab747fSPaolo Bonzini /* Restart Auto Configuration = Normal Operation */
121249ab747fSPaolo Bonzini data &= ~0x0200;
121349ab747fSPaolo Bonzini }
121449ab747fSPaolo Bonzini break;
121549ab747fSPaolo Bonzini case 1: /* Status Register */
121649ab747fSPaolo Bonzini missing("not writable");
121749ab747fSPaolo Bonzini break;
121849ab747fSPaolo Bonzini case 2: /* PHY Identification Register (Word 1) */
121949ab747fSPaolo Bonzini case 3: /* PHY Identification Register (Word 2) */
122049ab747fSPaolo Bonzini missing("not implemented");
122149ab747fSPaolo Bonzini break;
122249ab747fSPaolo Bonzini case 4: /* Auto-Negotiation Advertisement Register */
122349ab747fSPaolo Bonzini case 5: /* Auto-Negotiation Link Partner Ability Register */
122449ab747fSPaolo Bonzini break;
122549ab747fSPaolo Bonzini case 6: /* Auto-Negotiation Expansion Register */
122649ab747fSPaolo Bonzini default:
122749ab747fSPaolo Bonzini missing("not implemented");
122849ab747fSPaolo Bonzini }
12295e80dd22SPeter Maydell s->mdimem[reg] &= eepro100_mdi_mask[reg];
12305e80dd22SPeter Maydell s->mdimem[reg] |= data & ~eepro100_mdi_mask[reg];
123149ab747fSPaolo Bonzini } else if (opcode == 2) {
123249ab747fSPaolo Bonzini /* MDI read */
123349ab747fSPaolo Bonzini switch (reg) {
123449ab747fSPaolo Bonzini case 0: /* Control Register */
123549ab747fSPaolo Bonzini if (data & 0x8000) {
123649ab747fSPaolo Bonzini /* Reset status and control registers to default. */
123749ab747fSPaolo Bonzini s->mdimem[0] = eepro100_mdi_default[0];
123849ab747fSPaolo Bonzini s->mdimem[1] = eepro100_mdi_default[1];
123949ab747fSPaolo Bonzini }
124049ab747fSPaolo Bonzini break;
124149ab747fSPaolo Bonzini case 1: /* Status Register */
124249ab747fSPaolo Bonzini s->mdimem[reg] |= 0x0020;
124349ab747fSPaolo Bonzini break;
124449ab747fSPaolo Bonzini case 2: /* PHY Identification Register (Word 1) */
124549ab747fSPaolo Bonzini case 3: /* PHY Identification Register (Word 2) */
124649ab747fSPaolo Bonzini case 4: /* Auto-Negotiation Advertisement Register */
124749ab747fSPaolo Bonzini break;
124849ab747fSPaolo Bonzini case 5: /* Auto-Negotiation Link Partner Ability Register */
124949ab747fSPaolo Bonzini s->mdimem[reg] = 0x41fe;
125049ab747fSPaolo Bonzini break;
125149ab747fSPaolo Bonzini case 6: /* Auto-Negotiation Expansion Register */
125249ab747fSPaolo Bonzini s->mdimem[reg] = 0x0001;
125349ab747fSPaolo Bonzini break;
125449ab747fSPaolo Bonzini }
125549ab747fSPaolo Bonzini data = s->mdimem[reg];
125649ab747fSPaolo Bonzini }
125749ab747fSPaolo Bonzini /* Emulation takes no time to finish MDI transaction.
125849ab747fSPaolo Bonzini * Set MDI bit in SCB status register. */
125949ab747fSPaolo Bonzini s->mem[SCBAck] |= 0x08;
126049ab747fSPaolo Bonzini val |= BIT(28);
126149ab747fSPaolo Bonzini if (raiseint) {
126249ab747fSPaolo Bonzini eepro100_mdi_interrupt(s);
126349ab747fSPaolo Bonzini }
126449ab747fSPaolo Bonzini }
126549ab747fSPaolo Bonzini val = (val & 0xffff0000) + data;
126649ab747fSPaolo Bonzini e100_write_reg4(s, SCBCtrlMDI, val);
126749ab747fSPaolo Bonzini }
126849ab747fSPaolo Bonzini
126949ab747fSPaolo Bonzini /*****************************************************************************
127049ab747fSPaolo Bonzini *
127149ab747fSPaolo Bonzini * Port emulation.
127249ab747fSPaolo Bonzini *
127349ab747fSPaolo Bonzini ****************************************************************************/
127449ab747fSPaolo Bonzini
127549ab747fSPaolo Bonzini #define PORT_SOFTWARE_RESET 0
127649ab747fSPaolo Bonzini #define PORT_SELFTEST 1
127749ab747fSPaolo Bonzini #define PORT_SELECTIVE_RESET 2
127849ab747fSPaolo Bonzini #define PORT_DUMP 3
127949ab747fSPaolo Bonzini #define PORT_SELECTION_MASK 3
128049ab747fSPaolo Bonzini
128149ab747fSPaolo Bonzini typedef struct {
128249ab747fSPaolo Bonzini uint32_t st_sign; /* Self Test Signature */
128349ab747fSPaolo Bonzini uint32_t st_result; /* Self Test Results */
128449ab747fSPaolo Bonzini } eepro100_selftest_t;
128549ab747fSPaolo Bonzini
eepro100_read_port(EEPRO100State * s)128649ab747fSPaolo Bonzini static uint32_t eepro100_read_port(EEPRO100State * s)
128749ab747fSPaolo Bonzini {
128849ab747fSPaolo Bonzini return 0;
128949ab747fSPaolo Bonzini }
129049ab747fSPaolo Bonzini
eepro100_write_port(EEPRO100State * s)129149ab747fSPaolo Bonzini static void eepro100_write_port(EEPRO100State *s)
129249ab747fSPaolo Bonzini {
129349ab747fSPaolo Bonzini uint32_t val = e100_read_reg4(s, SCBPort);
129449ab747fSPaolo Bonzini uint32_t address = (val & ~PORT_SELECTION_MASK);
129549ab747fSPaolo Bonzini uint8_t selection = (val & PORT_SELECTION_MASK);
129649ab747fSPaolo Bonzini switch (selection) {
129749ab747fSPaolo Bonzini case PORT_SOFTWARE_RESET:
129849ab747fSPaolo Bonzini nic_reset(s);
129949ab747fSPaolo Bonzini break;
130049ab747fSPaolo Bonzini case PORT_SELFTEST:
130149ab747fSPaolo Bonzini TRACE(OTHER, logout("selftest address=0x%08x\n", address));
130249ab747fSPaolo Bonzini eepro100_selftest_t data;
130349ab747fSPaolo Bonzini pci_dma_read(&s->dev, address, (uint8_t *) &data, sizeof(data));
130449ab747fSPaolo Bonzini data.st_sign = 0xffffffff;
130549ab747fSPaolo Bonzini data.st_result = 0;
130649ab747fSPaolo Bonzini pci_dma_write(&s->dev, address, (uint8_t *) &data, sizeof(data));
130749ab747fSPaolo Bonzini break;
130849ab747fSPaolo Bonzini case PORT_SELECTIVE_RESET:
130949ab747fSPaolo Bonzini TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
131049ab747fSPaolo Bonzini nic_selective_reset(s);
131149ab747fSPaolo Bonzini break;
131249ab747fSPaolo Bonzini default:
131349ab747fSPaolo Bonzini logout("val=0x%08x\n", val);
131449ab747fSPaolo Bonzini missing("unknown port selection");
131549ab747fSPaolo Bonzini }
131649ab747fSPaolo Bonzini }
131749ab747fSPaolo Bonzini
131849ab747fSPaolo Bonzini /*****************************************************************************
131949ab747fSPaolo Bonzini *
132049ab747fSPaolo Bonzini * General hardware emulation.
132149ab747fSPaolo Bonzini *
132249ab747fSPaolo Bonzini ****************************************************************************/
132349ab747fSPaolo Bonzini
eepro100_read1(EEPRO100State * s,uint32_t addr)132449ab747fSPaolo Bonzini static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
132549ab747fSPaolo Bonzini {
132649ab747fSPaolo Bonzini uint8_t val = 0;
132749ab747fSPaolo Bonzini if (addr <= sizeof(s->mem) - sizeof(val)) {
132849ab747fSPaolo Bonzini val = s->mem[addr];
132949ab747fSPaolo Bonzini }
133049ab747fSPaolo Bonzini
133149ab747fSPaolo Bonzini switch (addr) {
133249ab747fSPaolo Bonzini case SCBStatus:
133349ab747fSPaolo Bonzini case SCBAck:
133449ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
133549ab747fSPaolo Bonzini break;
133649ab747fSPaolo Bonzini case SCBCmd:
133749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
133849ab747fSPaolo Bonzini #if 0
133949ab747fSPaolo Bonzini val = eepro100_read_command(s);
134049ab747fSPaolo Bonzini #endif
134149ab747fSPaolo Bonzini break;
134249ab747fSPaolo Bonzini case SCBIntmask:
134349ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
134449ab747fSPaolo Bonzini break;
134549ab747fSPaolo Bonzini case SCBPort + 3:
134649ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
134749ab747fSPaolo Bonzini break;
134849ab747fSPaolo Bonzini case SCBeeprom:
134949ab747fSPaolo Bonzini val = eepro100_read_eeprom(s);
135049ab747fSPaolo Bonzini break;
135149ab747fSPaolo Bonzini case SCBCtrlMDI:
135249ab747fSPaolo Bonzini case SCBCtrlMDI + 1:
135349ab747fSPaolo Bonzini case SCBCtrlMDI + 2:
135449ab747fSPaolo Bonzini case SCBCtrlMDI + 3:
135549ab747fSPaolo Bonzini val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
135649ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
135749ab747fSPaolo Bonzini break;
135849ab747fSPaolo Bonzini case SCBpmdr: /* Power Management Driver Register */
135949ab747fSPaolo Bonzini val = 0;
136049ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
136149ab747fSPaolo Bonzini break;
136249ab747fSPaolo Bonzini case SCBgctrl: /* General Control Register */
136349ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
136449ab747fSPaolo Bonzini break;
136549ab747fSPaolo Bonzini case SCBgstat: /* General Status Register */
136649ab747fSPaolo Bonzini /* 100 Mbps full duplex, valid link */
136749ab747fSPaolo Bonzini val = 0x07;
136849ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
136949ab747fSPaolo Bonzini break;
137049ab747fSPaolo Bonzini default:
137149ab747fSPaolo Bonzini logout("addr=%s val=0x%02x\n", regname(addr), val);
137249ab747fSPaolo Bonzini missing("unknown byte read");
137349ab747fSPaolo Bonzini }
137449ab747fSPaolo Bonzini return val;
137549ab747fSPaolo Bonzini }
137649ab747fSPaolo Bonzini
eepro100_read2(EEPRO100State * s,uint32_t addr)137749ab747fSPaolo Bonzini static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
137849ab747fSPaolo Bonzini {
137949ab747fSPaolo Bonzini uint16_t val = 0;
138049ab747fSPaolo Bonzini if (addr <= sizeof(s->mem) - sizeof(val)) {
138149ab747fSPaolo Bonzini val = e100_read_reg2(s, addr);
138249ab747fSPaolo Bonzini }
138349ab747fSPaolo Bonzini
138449ab747fSPaolo Bonzini switch (addr) {
138549ab747fSPaolo Bonzini case SCBStatus:
138649ab747fSPaolo Bonzini case SCBCmd:
138749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
138849ab747fSPaolo Bonzini break;
138949ab747fSPaolo Bonzini case SCBeeprom:
139049ab747fSPaolo Bonzini val = eepro100_read_eeprom(s);
139149ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
139249ab747fSPaolo Bonzini break;
139349ab747fSPaolo Bonzini case SCBCtrlMDI:
139449ab747fSPaolo Bonzini case SCBCtrlMDI + 2:
139549ab747fSPaolo Bonzini val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
139649ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
139749ab747fSPaolo Bonzini break;
139849ab747fSPaolo Bonzini default:
139949ab747fSPaolo Bonzini logout("addr=%s val=0x%04x\n", regname(addr), val);
140049ab747fSPaolo Bonzini missing("unknown word read");
140149ab747fSPaolo Bonzini }
140249ab747fSPaolo Bonzini return val;
140349ab747fSPaolo Bonzini }
140449ab747fSPaolo Bonzini
eepro100_read4(EEPRO100State * s,uint32_t addr)140549ab747fSPaolo Bonzini static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
140649ab747fSPaolo Bonzini {
140749ab747fSPaolo Bonzini uint32_t val = 0;
140849ab747fSPaolo Bonzini if (addr <= sizeof(s->mem) - sizeof(val)) {
140949ab747fSPaolo Bonzini val = e100_read_reg4(s, addr);
141049ab747fSPaolo Bonzini }
141149ab747fSPaolo Bonzini
141249ab747fSPaolo Bonzini switch (addr) {
141349ab747fSPaolo Bonzini case SCBStatus:
141449ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
141549ab747fSPaolo Bonzini break;
141649ab747fSPaolo Bonzini case SCBPointer:
141749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
141849ab747fSPaolo Bonzini break;
141949ab747fSPaolo Bonzini case SCBPort:
142049ab747fSPaolo Bonzini val = eepro100_read_port(s);
142149ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
142249ab747fSPaolo Bonzini break;
142349ab747fSPaolo Bonzini case SCBflash:
142449ab747fSPaolo Bonzini val = eepro100_read_eeprom(s);
142549ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
142649ab747fSPaolo Bonzini break;
142749ab747fSPaolo Bonzini case SCBCtrlMDI:
142849ab747fSPaolo Bonzini val = eepro100_read_mdi(s);
142949ab747fSPaolo Bonzini break;
143049ab747fSPaolo Bonzini default:
143149ab747fSPaolo Bonzini logout("addr=%s val=0x%08x\n", regname(addr), val);
143249ab747fSPaolo Bonzini missing("unknown longword read");
143349ab747fSPaolo Bonzini }
143449ab747fSPaolo Bonzini return val;
143549ab747fSPaolo Bonzini }
143649ab747fSPaolo Bonzini
eepro100_write1(EEPRO100State * s,uint32_t addr,uint8_t val)143749ab747fSPaolo Bonzini static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
143849ab747fSPaolo Bonzini {
143949ab747fSPaolo Bonzini /* SCBStatus is readonly. */
144049ab747fSPaolo Bonzini if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
144149ab747fSPaolo Bonzini s->mem[addr] = val;
144249ab747fSPaolo Bonzini }
144349ab747fSPaolo Bonzini
144449ab747fSPaolo Bonzini switch (addr) {
144549ab747fSPaolo Bonzini case SCBStatus:
144649ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
144749ab747fSPaolo Bonzini break;
144849ab747fSPaolo Bonzini case SCBAck:
144949ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
145049ab747fSPaolo Bonzini eepro100_acknowledge(s);
145149ab747fSPaolo Bonzini break;
145249ab747fSPaolo Bonzini case SCBCmd:
145349ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
145449ab747fSPaolo Bonzini eepro100_write_command(s, val);
145549ab747fSPaolo Bonzini break;
145649ab747fSPaolo Bonzini case SCBIntmask:
145749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
145849ab747fSPaolo Bonzini if (val & BIT(1)) {
145949ab747fSPaolo Bonzini eepro100_swi_interrupt(s);
146049ab747fSPaolo Bonzini }
146149ab747fSPaolo Bonzini eepro100_interrupt(s, 0);
146249ab747fSPaolo Bonzini break;
146349ab747fSPaolo Bonzini case SCBPointer:
146449ab747fSPaolo Bonzini case SCBPointer + 1:
146549ab747fSPaolo Bonzini case SCBPointer + 2:
146649ab747fSPaolo Bonzini case SCBPointer + 3:
146749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
146849ab747fSPaolo Bonzini break;
146949ab747fSPaolo Bonzini case SCBPort:
147049ab747fSPaolo Bonzini case SCBPort + 1:
147149ab747fSPaolo Bonzini case SCBPort + 2:
147249ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
147349ab747fSPaolo Bonzini break;
147449ab747fSPaolo Bonzini case SCBPort + 3:
147549ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
147649ab747fSPaolo Bonzini eepro100_write_port(s);
147749ab747fSPaolo Bonzini break;
147849ab747fSPaolo Bonzini case SCBFlow: /* does not exist on 82557 */
147949ab747fSPaolo Bonzini case SCBFlow + 1:
148049ab747fSPaolo Bonzini case SCBFlow + 2:
148149ab747fSPaolo Bonzini case SCBpmdr: /* does not exist on 82557 */
148249ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
148349ab747fSPaolo Bonzini break;
148449ab747fSPaolo Bonzini case SCBeeprom:
148549ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
148649ab747fSPaolo Bonzini eepro100_write_eeprom(s->eeprom, val);
148749ab747fSPaolo Bonzini break;
148849ab747fSPaolo Bonzini case SCBCtrlMDI:
148949ab747fSPaolo Bonzini case SCBCtrlMDI + 1:
149049ab747fSPaolo Bonzini case SCBCtrlMDI + 2:
149149ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
149249ab747fSPaolo Bonzini break;
149349ab747fSPaolo Bonzini case SCBCtrlMDI + 3:
149449ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
149549ab747fSPaolo Bonzini eepro100_write_mdi(s);
149649ab747fSPaolo Bonzini break;
149749ab747fSPaolo Bonzini default:
149849ab747fSPaolo Bonzini logout("addr=%s val=0x%02x\n", regname(addr), val);
149949ab747fSPaolo Bonzini missing("unknown byte write");
150049ab747fSPaolo Bonzini }
150149ab747fSPaolo Bonzini }
150249ab747fSPaolo Bonzini
eepro100_write2(EEPRO100State * s,uint32_t addr,uint16_t val)150349ab747fSPaolo Bonzini static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
150449ab747fSPaolo Bonzini {
150549ab747fSPaolo Bonzini /* SCBStatus is readonly. */
150649ab747fSPaolo Bonzini if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
150749ab747fSPaolo Bonzini e100_write_reg2(s, addr, val);
150849ab747fSPaolo Bonzini }
150949ab747fSPaolo Bonzini
151049ab747fSPaolo Bonzini switch (addr) {
151149ab747fSPaolo Bonzini case SCBStatus:
151249ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
151349ab747fSPaolo Bonzini s->mem[SCBAck] = (val >> 8);
151449ab747fSPaolo Bonzini eepro100_acknowledge(s);
151549ab747fSPaolo Bonzini break;
151649ab747fSPaolo Bonzini case SCBCmd:
151749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
151849ab747fSPaolo Bonzini eepro100_write_command(s, val);
151949ab747fSPaolo Bonzini eepro100_write1(s, SCBIntmask, val >> 8);
152049ab747fSPaolo Bonzini break;
152149ab747fSPaolo Bonzini case SCBPointer:
152249ab747fSPaolo Bonzini case SCBPointer + 2:
152349ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
152449ab747fSPaolo Bonzini break;
152549ab747fSPaolo Bonzini case SCBPort:
152649ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
152749ab747fSPaolo Bonzini break;
152849ab747fSPaolo Bonzini case SCBPort + 2:
152949ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
153049ab747fSPaolo Bonzini eepro100_write_port(s);
153149ab747fSPaolo Bonzini break;
153249ab747fSPaolo Bonzini case SCBeeprom:
153349ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
153449ab747fSPaolo Bonzini eepro100_write_eeprom(s->eeprom, val);
153549ab747fSPaolo Bonzini break;
153649ab747fSPaolo Bonzini case SCBCtrlMDI:
153749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
153849ab747fSPaolo Bonzini break;
153949ab747fSPaolo Bonzini case SCBCtrlMDI + 2:
154049ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
154149ab747fSPaolo Bonzini eepro100_write_mdi(s);
154249ab747fSPaolo Bonzini break;
154349ab747fSPaolo Bonzini default:
154449ab747fSPaolo Bonzini logout("addr=%s val=0x%04x\n", regname(addr), val);
154549ab747fSPaolo Bonzini missing("unknown word write");
154649ab747fSPaolo Bonzini }
154749ab747fSPaolo Bonzini }
154849ab747fSPaolo Bonzini
eepro100_write4(EEPRO100State * s,uint32_t addr,uint32_t val)154949ab747fSPaolo Bonzini static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
155049ab747fSPaolo Bonzini {
155149ab747fSPaolo Bonzini if (addr <= sizeof(s->mem) - sizeof(val)) {
155249ab747fSPaolo Bonzini e100_write_reg4(s, addr, val);
155349ab747fSPaolo Bonzini }
155449ab747fSPaolo Bonzini
155549ab747fSPaolo Bonzini switch (addr) {
155649ab747fSPaolo Bonzini case SCBPointer:
155749ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
155849ab747fSPaolo Bonzini break;
155949ab747fSPaolo Bonzini case SCBPort:
156049ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
156149ab747fSPaolo Bonzini eepro100_write_port(s);
156249ab747fSPaolo Bonzini break;
156349ab747fSPaolo Bonzini case SCBflash:
156449ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
156549ab747fSPaolo Bonzini val = val >> 16;
156649ab747fSPaolo Bonzini eepro100_write_eeprom(s->eeprom, val);
156749ab747fSPaolo Bonzini break;
156849ab747fSPaolo Bonzini case SCBCtrlMDI:
156949ab747fSPaolo Bonzini TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
157049ab747fSPaolo Bonzini eepro100_write_mdi(s);
157149ab747fSPaolo Bonzini break;
157249ab747fSPaolo Bonzini default:
157349ab747fSPaolo Bonzini logout("addr=%s val=0x%08x\n", regname(addr), val);
157449ab747fSPaolo Bonzini missing("unknown longword write");
157549ab747fSPaolo Bonzini }
157649ab747fSPaolo Bonzini }
157749ab747fSPaolo Bonzini
eepro100_read(void * opaque,hwaddr addr,unsigned size)157849ab747fSPaolo Bonzini static uint64_t eepro100_read(void *opaque, hwaddr addr,
157949ab747fSPaolo Bonzini unsigned size)
158049ab747fSPaolo Bonzini {
158149ab747fSPaolo Bonzini EEPRO100State *s = opaque;
158249ab747fSPaolo Bonzini
158349ab747fSPaolo Bonzini switch (size) {
158449ab747fSPaolo Bonzini case 1: return eepro100_read1(s, addr);
158549ab747fSPaolo Bonzini case 2: return eepro100_read2(s, addr);
158649ab747fSPaolo Bonzini case 4: return eepro100_read4(s, addr);
158749ab747fSPaolo Bonzini default: abort();
158849ab747fSPaolo Bonzini }
158949ab747fSPaolo Bonzini }
159049ab747fSPaolo Bonzini
eepro100_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)159149ab747fSPaolo Bonzini static void eepro100_write(void *opaque, hwaddr addr,
159249ab747fSPaolo Bonzini uint64_t data, unsigned size)
159349ab747fSPaolo Bonzini {
159449ab747fSPaolo Bonzini EEPRO100State *s = opaque;
159549ab747fSPaolo Bonzini
159649ab747fSPaolo Bonzini switch (size) {
159749ab747fSPaolo Bonzini case 1:
159849ab747fSPaolo Bonzini eepro100_write1(s, addr, data);
159949ab747fSPaolo Bonzini break;
160049ab747fSPaolo Bonzini case 2:
160149ab747fSPaolo Bonzini eepro100_write2(s, addr, data);
160249ab747fSPaolo Bonzini break;
160349ab747fSPaolo Bonzini case 4:
160449ab747fSPaolo Bonzini eepro100_write4(s, addr, data);
160549ab747fSPaolo Bonzini break;
160649ab747fSPaolo Bonzini default:
160749ab747fSPaolo Bonzini abort();
160849ab747fSPaolo Bonzini }
160949ab747fSPaolo Bonzini }
161049ab747fSPaolo Bonzini
161149ab747fSPaolo Bonzini static const MemoryRegionOps eepro100_ops = {
161249ab747fSPaolo Bonzini .read = eepro100_read,
161349ab747fSPaolo Bonzini .write = eepro100_write,
161449ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
161549ab747fSPaolo Bonzini };
161649ab747fSPaolo Bonzini
nic_receive(NetClientState * nc,const uint8_t * buf,size_t size)161749ab747fSPaolo Bonzini static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
161849ab747fSPaolo Bonzini {
161949ab747fSPaolo Bonzini /* TODO:
162049ab747fSPaolo Bonzini * - Magic packets should set bit 30 in power management driver register.
162149ab747fSPaolo Bonzini * - Interesting packets should set bit 29 in power management driver register.
162249ab747fSPaolo Bonzini */
1623a423a1b5SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
162449ab747fSPaolo Bonzini EEPRO100State *s = qemu_get_nic_opaque(nc);
162549ab747fSPaolo Bonzini uint16_t rfd_status = 0xa000;
162649ab747fSPaolo Bonzini #if defined(CONFIG_PAD_RECEIVED_FRAMES)
162749ab747fSPaolo Bonzini uint8_t min_buf[60];
162849ab747fSPaolo Bonzini #endif
162949ab747fSPaolo Bonzini static const uint8_t broadcast_macaddr[6] =
163049ab747fSPaolo Bonzini { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
163149ab747fSPaolo Bonzini
163249ab747fSPaolo Bonzini #if defined(CONFIG_PAD_RECEIVED_FRAMES)
163349ab747fSPaolo Bonzini /* Pad to minimum Ethernet frame length */
163449ab747fSPaolo Bonzini if (size < sizeof(min_buf)) {
163549ab747fSPaolo Bonzini memcpy(min_buf, buf, size);
163649ab747fSPaolo Bonzini memset(&min_buf[size], 0, sizeof(min_buf) - size);
163749ab747fSPaolo Bonzini buf = min_buf;
163849ab747fSPaolo Bonzini size = sizeof(min_buf);
163949ab747fSPaolo Bonzini }
164049ab747fSPaolo Bonzini #endif
164149ab747fSPaolo Bonzini
164249ab747fSPaolo Bonzini if (s->configuration[8] & 0x80) {
164349ab747fSPaolo Bonzini /* CSMA is disabled. */
164449ab747fSPaolo Bonzini logout("%p received while CSMA is disabled\n", s);
164549ab747fSPaolo Bonzini return -1;
164649ab747fSPaolo Bonzini #if !defined(CONFIG_PAD_RECEIVED_FRAMES)
164749ab747fSPaolo Bonzini } else if (size < 64 && (s->configuration[7] & BIT(0))) {
164849ab747fSPaolo Bonzini /* Short frame and configuration byte 7/0 (discard short receive) set:
164949ab747fSPaolo Bonzini * Short frame is discarded */
165049ab747fSPaolo Bonzini logout("%p received short frame (%zu byte)\n", s, size);
165149ab747fSPaolo Bonzini s->statistics.rx_short_frame_errors++;
165249ab747fSPaolo Bonzini return -1;
165349ab747fSPaolo Bonzini #endif
165449ab747fSPaolo Bonzini } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
165549ab747fSPaolo Bonzini /* Long frame and configuration byte 18/3 (long receive ok) not set:
165649ab747fSPaolo Bonzini * Long frames are discarded. */
165749ab747fSPaolo Bonzini logout("%p received long frame (%zu byte), ignored\n", s, size);
165849ab747fSPaolo Bonzini return -1;
165949ab747fSPaolo Bonzini } else if (memcmp(buf, s->conf.macaddr.a, 6) == 0) { /* !!! */
166049ab747fSPaolo Bonzini /* Frame matches individual address. */
166149ab747fSPaolo Bonzini /* TODO: check configuration byte 15/4 (ignore U/L). */
166249ab747fSPaolo Bonzini TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
166349ab747fSPaolo Bonzini } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
166449ab747fSPaolo Bonzini /* Broadcast frame. */
166549ab747fSPaolo Bonzini TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
166649ab747fSPaolo Bonzini rfd_status |= 0x0002;
166749ab747fSPaolo Bonzini } else if (buf[0] & 0x01) {
166849ab747fSPaolo Bonzini /* Multicast frame. */
166949ab747fSPaolo Bonzini TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size)));
167049ab747fSPaolo Bonzini if (s->configuration[21] & BIT(3)) {
167149ab747fSPaolo Bonzini /* Multicast all bit is set, receive all multicast frames. */
167249ab747fSPaolo Bonzini } else {
16737c0348bdSMark Cave-Ayland unsigned mcast_idx = (net_crc32(buf, ETH_ALEN) & BITS(7, 2)) >> 2;
167449ab747fSPaolo Bonzini assert(mcast_idx < 64);
167549ab747fSPaolo Bonzini if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
167649ab747fSPaolo Bonzini /* Multicast frame is allowed in hash table. */
167749ab747fSPaolo Bonzini } else if (s->configuration[15] & BIT(0)) {
167849ab747fSPaolo Bonzini /* Promiscuous: receive all. */
167949ab747fSPaolo Bonzini rfd_status |= 0x0004;
168049ab747fSPaolo Bonzini } else {
168149ab747fSPaolo Bonzini TRACE(RXTX, logout("%p multicast ignored\n", s));
168249ab747fSPaolo Bonzini return -1;
168349ab747fSPaolo Bonzini }
168449ab747fSPaolo Bonzini }
168549ab747fSPaolo Bonzini /* TODO: Next not for promiscuous mode? */
168649ab747fSPaolo Bonzini rfd_status |= 0x0002;
168749ab747fSPaolo Bonzini } else if (s->configuration[15] & BIT(0)) {
168849ab747fSPaolo Bonzini /* Promiscuous: receive all. */
168949ab747fSPaolo Bonzini TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
169049ab747fSPaolo Bonzini rfd_status |= 0x0004;
169149ab747fSPaolo Bonzini } else if (s->configuration[20] & BIT(6)) {
169249ab747fSPaolo Bonzini /* Multiple IA bit set. */
1693d00d6d00SMark Cave-Ayland unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
169449ab747fSPaolo Bonzini assert(mcast_idx < 64);
169549ab747fSPaolo Bonzini if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
169649ab747fSPaolo Bonzini TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
169749ab747fSPaolo Bonzini } else {
169849ab747fSPaolo Bonzini TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
169949ab747fSPaolo Bonzini return -1;
170049ab747fSPaolo Bonzini }
170149ab747fSPaolo Bonzini } else {
170249ab747fSPaolo Bonzini TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
170349ab747fSPaolo Bonzini nic_dump(buf, size)));
170449ab747fSPaolo Bonzini return size;
170549ab747fSPaolo Bonzini }
170649ab747fSPaolo Bonzini
170749ab747fSPaolo Bonzini if (get_ru_state(s) != ru_ready) {
170849ab747fSPaolo Bonzini /* No resources available. */
170949ab747fSPaolo Bonzini logout("no resources, state=%u\n", get_ru_state(s));
171049ab747fSPaolo Bonzini /* TODO: RNR interrupt only at first failed frame? */
171149ab747fSPaolo Bonzini eepro100_rnr_interrupt(s);
171249ab747fSPaolo Bonzini s->statistics.rx_resource_errors++;
171349ab747fSPaolo Bonzini #if 0
171449ab747fSPaolo Bonzini assert(!"no resources");
171549ab747fSPaolo Bonzini #endif
171649ab747fSPaolo Bonzini return -1;
171749ab747fSPaolo Bonzini }
171849ab747fSPaolo Bonzini /* !!! */
171949ab747fSPaolo Bonzini eepro100_rx_t rx;
172049ab747fSPaolo Bonzini pci_dma_read(&s->dev, s->ru_base + s->ru_offset,
172149ab747fSPaolo Bonzini &rx, sizeof(eepro100_rx_t));
172249ab747fSPaolo Bonzini uint16_t rfd_command = le16_to_cpu(rx.command);
172349ab747fSPaolo Bonzini uint16_t rfd_size = le16_to_cpu(rx.size);
172449ab747fSPaolo Bonzini
172549ab747fSPaolo Bonzini if (size > rfd_size) {
172649ab747fSPaolo Bonzini logout("Receive buffer (%" PRId16 " bytes) too small for data "
172749ab747fSPaolo Bonzini "(%zu bytes); data truncated\n", rfd_size, size);
172849ab747fSPaolo Bonzini size = rfd_size;
172949ab747fSPaolo Bonzini }
173049ab747fSPaolo Bonzini #if !defined(CONFIG_PAD_RECEIVED_FRAMES)
173149ab747fSPaolo Bonzini if (size < 64) {
173249ab747fSPaolo Bonzini rfd_status |= 0x0080;
173349ab747fSPaolo Bonzini }
173449ab747fSPaolo Bonzini #endif
173549ab747fSPaolo Bonzini TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
173649ab747fSPaolo Bonzini rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
173749ab747fSPaolo Bonzini stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
1738a423a1b5SPhilippe Mathieu-Daudé offsetof(eepro100_rx_t, status), rfd_status, attrs);
173949ab747fSPaolo Bonzini stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
1740a423a1b5SPhilippe Mathieu-Daudé offsetof(eepro100_rx_t, count), size, attrs);
174149ab747fSPaolo Bonzini /* Early receive interrupt not supported. */
174249ab747fSPaolo Bonzini #if 0
174349ab747fSPaolo Bonzini eepro100_er_interrupt(s);
174449ab747fSPaolo Bonzini #endif
174549ab747fSPaolo Bonzini /* Receive CRC Transfer not supported. */
174649ab747fSPaolo Bonzini if (s->configuration[18] & BIT(2)) {
174749ab747fSPaolo Bonzini missing("Receive CRC Transfer");
174849ab747fSPaolo Bonzini return -1;
174949ab747fSPaolo Bonzini }
175049ab747fSPaolo Bonzini /* TODO: check stripping enable bit. */
175149ab747fSPaolo Bonzini #if 0
175249ab747fSPaolo Bonzini assert(!(s->configuration[17] & BIT(0)));
175349ab747fSPaolo Bonzini #endif
175449ab747fSPaolo Bonzini pci_dma_write(&s->dev, s->ru_base + s->ru_offset +
175549ab747fSPaolo Bonzini sizeof(eepro100_rx_t), buf, size);
175649ab747fSPaolo Bonzini s->statistics.rx_good_frames++;
175749ab747fSPaolo Bonzini eepro100_fr_interrupt(s);
175849ab747fSPaolo Bonzini s->ru_offset = le32_to_cpu(rx.link);
175949ab747fSPaolo Bonzini if (rfd_command & COMMAND_EL) {
176049ab747fSPaolo Bonzini /* EL bit is set, so this was the last frame. */
176149ab747fSPaolo Bonzini logout("receive: Running out of frames\n");
176249ab747fSPaolo Bonzini set_ru_state(s, ru_no_resources);
176349ab747fSPaolo Bonzini eepro100_rnr_interrupt(s);
176449ab747fSPaolo Bonzini }
176549ab747fSPaolo Bonzini if (rfd_command & COMMAND_S) {
176649ab747fSPaolo Bonzini /* S bit is set. */
176749ab747fSPaolo Bonzini set_ru_state(s, ru_suspended);
176849ab747fSPaolo Bonzini }
176949ab747fSPaolo Bonzini return size;
177049ab747fSPaolo Bonzini }
177149ab747fSPaolo Bonzini
177249ab747fSPaolo Bonzini static const VMStateDescription vmstate_eepro100 = {
177349ab747fSPaolo Bonzini .version_id = 3,
177449ab747fSPaolo Bonzini .minimum_version_id = 2,
1775*1de81b42SRichard Henderson .fields = (const VMStateField[]) {
177649ab747fSPaolo Bonzini VMSTATE_PCI_DEVICE(dev, EEPRO100State),
177749ab747fSPaolo Bonzini VMSTATE_UNUSED(32),
177849ab747fSPaolo Bonzini VMSTATE_BUFFER(mult, EEPRO100State),
177949ab747fSPaolo Bonzini VMSTATE_BUFFER(mem, EEPRO100State),
178049ab747fSPaolo Bonzini /* Save all members of struct between scb_stat and mem. */
178149ab747fSPaolo Bonzini VMSTATE_UINT8(scb_stat, EEPRO100State),
178249ab747fSPaolo Bonzini VMSTATE_UINT8(int_stat, EEPRO100State),
178349ab747fSPaolo Bonzini VMSTATE_UNUSED(3*4),
178449ab747fSPaolo Bonzini VMSTATE_MACADDR(conf.macaddr, EEPRO100State),
178549ab747fSPaolo Bonzini VMSTATE_UNUSED(19*4),
178649ab747fSPaolo Bonzini VMSTATE_UINT16_ARRAY(mdimem, EEPRO100State, 32),
178749ab747fSPaolo Bonzini /* The eeprom should be saved and restored by its own routines. */
178849ab747fSPaolo Bonzini VMSTATE_UINT32(device, EEPRO100State),
178949ab747fSPaolo Bonzini /* TODO check device. */
179049ab747fSPaolo Bonzini VMSTATE_UINT32(cu_base, EEPRO100State),
179149ab747fSPaolo Bonzini VMSTATE_UINT32(cu_offset, EEPRO100State),
179249ab747fSPaolo Bonzini VMSTATE_UINT32(ru_base, EEPRO100State),
179349ab747fSPaolo Bonzini VMSTATE_UINT32(ru_offset, EEPRO100State),
179449ab747fSPaolo Bonzini VMSTATE_UINT32(statsaddr, EEPRO100State),
179549ab747fSPaolo Bonzini /* Save eepro100_stats_t statistics. */
179649ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State),
179749ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State),
179849ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State),
179949ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_underruns, EEPRO100State),
180049ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_lost_crs, EEPRO100State),
180149ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_deferred, EEPRO100State),
180249ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_single_collisions, EEPRO100State),
180349ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_multiple_collisions, EEPRO100State),
180449ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.tx_total_collisions, EEPRO100State),
180549ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_good_frames, EEPRO100State),
180649ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_crc_errors, EEPRO100State),
180749ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_alignment_errors, EEPRO100State),
180849ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_resource_errors, EEPRO100State),
180949ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_overrun_errors, EEPRO100State),
181049ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_cdt_errors, EEPRO100State),
181149ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.rx_short_frame_errors, EEPRO100State),
181249ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.fc_xmt_pause, EEPRO100State),
181349ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.fc_rcv_pause, EEPRO100State),
181449ab747fSPaolo Bonzini VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
181549ab747fSPaolo Bonzini VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
181649ab747fSPaolo Bonzini VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
181749ab747fSPaolo Bonzini /* Configuration bytes. */
181849ab747fSPaolo Bonzini VMSTATE_BUFFER(configuration, EEPRO100State),
181949ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
182049ab747fSPaolo Bonzini }
182149ab747fSPaolo Bonzini };
182249ab747fSPaolo Bonzini
pci_nic_uninit(PCIDevice * pci_dev)182349ab747fSPaolo Bonzini static void pci_nic_uninit(PCIDevice *pci_dev)
182449ab747fSPaolo Bonzini {
182549ab747fSPaolo Bonzini EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
182649ab747fSPaolo Bonzini
18273cad405bSMarc-André Lureau vmstate_unregister(VMSTATE_IF(&pci_dev->qdev), s->vmstate, s);
18282634ab7fSLi Qiang g_free(s->vmstate);
182949ab747fSPaolo Bonzini eeprom93xx_free(&pci_dev->qdev, s->eeprom);
183049ab747fSPaolo Bonzini qemu_del_nic(s->nic);
183149ab747fSPaolo Bonzini }
183249ab747fSPaolo Bonzini
183349ab747fSPaolo Bonzini static NetClientInfo net_eepro100_info = {
1834f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC,
183549ab747fSPaolo Bonzini .size = sizeof(NICState),
183649ab747fSPaolo Bonzini .receive = nic_receive,
183749ab747fSPaolo Bonzini };
183849ab747fSPaolo Bonzini
e100_nic_realize(PCIDevice * pci_dev,Error ** errp)18399af21dbeSMarkus Armbruster static void e100_nic_realize(PCIDevice *pci_dev, Error **errp)
184049ab747fSPaolo Bonzini {
184149ab747fSPaolo Bonzini EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
184249ab747fSPaolo Bonzini E100PCIDeviceInfo *info = eepro100_get_class(s);
18439a7c2a59SMao Zhongyi Error *local_err = NULL;
184449ab747fSPaolo Bonzini
184549ab747fSPaolo Bonzini TRACE(OTHER, logout("\n"));
184649ab747fSPaolo Bonzini
184749ab747fSPaolo Bonzini s->device = info->device;
184849ab747fSPaolo Bonzini
18499a7c2a59SMao Zhongyi e100_pci_reset(s, &local_err);
18509a7c2a59SMao Zhongyi if (local_err) {
18519a7c2a59SMao Zhongyi error_propagate(errp, local_err);
18529a7c2a59SMao Zhongyi return;
18539a7c2a59SMao Zhongyi }
185449ab747fSPaolo Bonzini
185549ab747fSPaolo Bonzini /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
185649ab747fSPaolo Bonzini * i82559 and later support 64 or 256 word EEPROM. */
185749ab747fSPaolo Bonzini s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
185849ab747fSPaolo Bonzini
185949ab747fSPaolo Bonzini /* Handler for memory-mapped I/O */
1860eedfac6fSPaolo Bonzini memory_region_init_io(&s->mmio_bar, OBJECT(s), &eepro100_ops, s,
1861eedfac6fSPaolo Bonzini "eepro100-mmio", PCI_MEM_SIZE);
186249ab747fSPaolo Bonzini pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio_bar);
1863eedfac6fSPaolo Bonzini memory_region_init_io(&s->io_bar, OBJECT(s), &eepro100_ops, s,
1864eedfac6fSPaolo Bonzini "eepro100-io", PCI_IO_SIZE);
186549ab747fSPaolo Bonzini pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
186649ab747fSPaolo Bonzini /* FIXME: flash aliases to mmio?! */
1867eedfac6fSPaolo Bonzini memory_region_init_io(&s->flash_bar, OBJECT(s), &eepro100_ops, s,
1868eedfac6fSPaolo Bonzini "eepro100-flash", PCI_FLASH_SIZE);
186949ab747fSPaolo Bonzini pci_register_bar(&s->dev, 2, 0, &s->flash_bar);
187049ab747fSPaolo Bonzini
187149ab747fSPaolo Bonzini qemu_macaddr_default_if_unset(&s->conf.macaddr);
187249ab747fSPaolo Bonzini logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
187349ab747fSPaolo Bonzini
187449ab747fSPaolo Bonzini nic_reset(s);
187549ab747fSPaolo Bonzini
187649ab747fSPaolo Bonzini s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
18777d0fefdfSAkihiko Odaki object_get_typename(OBJECT(pci_dev)),
18787d0fefdfSAkihiko Odaki pci_dev->qdev.id,
18797d0fefdfSAkihiko Odaki &pci_dev->qdev.mem_reentrancy_guard, s);
188049ab747fSPaolo Bonzini
188149ab747fSPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
188249ab747fSPaolo Bonzini TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str));
188349ab747fSPaolo Bonzini
188449ab747fSPaolo Bonzini qemu_register_reset(nic_reset, s);
188549ab747fSPaolo Bonzini
1886e4d67e4fSMarc-André Lureau s->vmstate = g_memdup(&vmstate_eepro100, sizeof(vmstate_eepro100));
188749ab747fSPaolo Bonzini s->vmstate->name = qemu_get_queue(s->nic)->model;
188899b16e8eSJuan Quintela vmstate_register_any(VMSTATE_IF(&pci_dev->qdev), s->vmstate, s);
188949ab747fSPaolo Bonzini }
189049ab747fSPaolo Bonzini
eepro100_instance_init(Object * obj)18917317bb17SGonglei static void eepro100_instance_init(Object *obj)
18927317bb17SGonglei {
18937317bb17SGonglei EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, PCI_DEVICE(obj));
18947317bb17SGonglei device_add_bootindex_property(obj, &s->conf.bootindex,
18957317bb17SGonglei "bootindex", "/ethernet-phy@0",
189640c2281cSMarkus Armbruster DEVICE(s));
18977317bb17SGonglei }
18987317bb17SGonglei
189949ab747fSPaolo Bonzini static E100PCIDeviceInfo e100_devices[] = {
190049ab747fSPaolo Bonzini {
190149ab747fSPaolo Bonzini .name = "i82550",
190249ab747fSPaolo Bonzini .desc = "Intel i82550 Ethernet",
190349ab747fSPaolo Bonzini .device = i82550,
190449ab747fSPaolo Bonzini /* TODO: check device id. */
190549ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82551IT,
190649ab747fSPaolo Bonzini /* Revision ID: 0x0c, 0x0d, 0x0e. */
190749ab747fSPaolo Bonzini .revision = 0x0e,
190849ab747fSPaolo Bonzini /* TODO: check size of statistical counters. */
190949ab747fSPaolo Bonzini .stats_size = 80,
191049ab747fSPaolo Bonzini /* TODO: check extended tcb support. */
191149ab747fSPaolo Bonzini .has_extended_tcb_support = true,
191249ab747fSPaolo Bonzini .power_management = true,
191349ab747fSPaolo Bonzini },{
191449ab747fSPaolo Bonzini .name = "i82551",
191549ab747fSPaolo Bonzini .desc = "Intel i82551 Ethernet",
191649ab747fSPaolo Bonzini .device = i82551,
191749ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82551IT,
191849ab747fSPaolo Bonzini /* Revision ID: 0x0f, 0x10. */
191949ab747fSPaolo Bonzini .revision = 0x0f,
192049ab747fSPaolo Bonzini /* TODO: check size of statistical counters. */
192149ab747fSPaolo Bonzini .stats_size = 80,
192249ab747fSPaolo Bonzini .has_extended_tcb_support = true,
192349ab747fSPaolo Bonzini .power_management = true,
192449ab747fSPaolo Bonzini },{
192549ab747fSPaolo Bonzini .name = "i82557a",
192649ab747fSPaolo Bonzini .desc = "Intel i82557A Ethernet",
192749ab747fSPaolo Bonzini .device = i82557A,
192849ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
192949ab747fSPaolo Bonzini .revision = 0x01,
193049ab747fSPaolo Bonzini .power_management = false,
193149ab747fSPaolo Bonzini },{
193249ab747fSPaolo Bonzini .name = "i82557b",
193349ab747fSPaolo Bonzini .desc = "Intel i82557B Ethernet",
193449ab747fSPaolo Bonzini .device = i82557B,
193549ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
193649ab747fSPaolo Bonzini .revision = 0x02,
193749ab747fSPaolo Bonzini .power_management = false,
193849ab747fSPaolo Bonzini },{
193949ab747fSPaolo Bonzini .name = "i82557c",
194049ab747fSPaolo Bonzini .desc = "Intel i82557C Ethernet",
194149ab747fSPaolo Bonzini .device = i82557C,
194249ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
194349ab747fSPaolo Bonzini .revision = 0x03,
194449ab747fSPaolo Bonzini .power_management = false,
194549ab747fSPaolo Bonzini },{
194649ab747fSPaolo Bonzini .name = "i82558a",
194749ab747fSPaolo Bonzini .desc = "Intel i82558A Ethernet",
194849ab747fSPaolo Bonzini .device = i82558A,
194949ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
195049ab747fSPaolo Bonzini .revision = 0x04,
195149ab747fSPaolo Bonzini .stats_size = 76,
195249ab747fSPaolo Bonzini .has_extended_tcb_support = true,
195349ab747fSPaolo Bonzini .power_management = true,
195449ab747fSPaolo Bonzini },{
195549ab747fSPaolo Bonzini .name = "i82558b",
195649ab747fSPaolo Bonzini .desc = "Intel i82558B Ethernet",
195749ab747fSPaolo Bonzini .device = i82558B,
195849ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
195949ab747fSPaolo Bonzini .revision = 0x05,
196049ab747fSPaolo Bonzini .stats_size = 76,
196149ab747fSPaolo Bonzini .has_extended_tcb_support = true,
196249ab747fSPaolo Bonzini .power_management = true,
196349ab747fSPaolo Bonzini },{
196449ab747fSPaolo Bonzini .name = "i82559a",
196549ab747fSPaolo Bonzini .desc = "Intel i82559A Ethernet",
196649ab747fSPaolo Bonzini .device = i82559A,
196749ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
196849ab747fSPaolo Bonzini .revision = 0x06,
196949ab747fSPaolo Bonzini .stats_size = 80,
197049ab747fSPaolo Bonzini .has_extended_tcb_support = true,
197149ab747fSPaolo Bonzini .power_management = true,
197249ab747fSPaolo Bonzini },{
197349ab747fSPaolo Bonzini .name = "i82559b",
197449ab747fSPaolo Bonzini .desc = "Intel i82559B Ethernet",
197549ab747fSPaolo Bonzini .device = i82559B,
197649ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
197749ab747fSPaolo Bonzini .revision = 0x07,
197849ab747fSPaolo Bonzini .stats_size = 80,
197949ab747fSPaolo Bonzini .has_extended_tcb_support = true,
198049ab747fSPaolo Bonzini .power_management = true,
198149ab747fSPaolo Bonzini },{
198249ab747fSPaolo Bonzini .name = "i82559c",
198349ab747fSPaolo Bonzini .desc = "Intel i82559C Ethernet",
198449ab747fSPaolo Bonzini .device = i82559C,
198549ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82557,
198649ab747fSPaolo Bonzini #if 0
198749ab747fSPaolo Bonzini .revision = 0x08,
198849ab747fSPaolo Bonzini #endif
198949ab747fSPaolo Bonzini /* TODO: Windows wants revision id 0x0c. */
199049ab747fSPaolo Bonzini .revision = 0x0c,
199149ab747fSPaolo Bonzini #if EEPROM_SIZE > 0
199249ab747fSPaolo Bonzini .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
199349ab747fSPaolo Bonzini .subsystem_id = 0x0040,
199449ab747fSPaolo Bonzini #endif
199549ab747fSPaolo Bonzini .stats_size = 80,
199649ab747fSPaolo Bonzini .has_extended_tcb_support = true,
199749ab747fSPaolo Bonzini .power_management = true,
199849ab747fSPaolo Bonzini },{
199949ab747fSPaolo Bonzini .name = "i82559er",
200049ab747fSPaolo Bonzini .desc = "Intel i82559ER Ethernet",
200149ab747fSPaolo Bonzini .device = i82559ER,
200249ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82551IT,
200349ab747fSPaolo Bonzini .revision = 0x09,
200449ab747fSPaolo Bonzini .stats_size = 80,
200549ab747fSPaolo Bonzini .has_extended_tcb_support = true,
200649ab747fSPaolo Bonzini .power_management = true,
200749ab747fSPaolo Bonzini },{
200849ab747fSPaolo Bonzini .name = "i82562",
200949ab747fSPaolo Bonzini .desc = "Intel i82562 Ethernet",
201049ab747fSPaolo Bonzini .device = i82562,
201149ab747fSPaolo Bonzini /* TODO: check device id. */
201249ab747fSPaolo Bonzini .device_id = PCI_DEVICE_ID_INTEL_82551IT,
201349ab747fSPaolo Bonzini /* TODO: wrong revision id. */
201449ab747fSPaolo Bonzini .revision = 0x0e,
201549ab747fSPaolo Bonzini .stats_size = 80,
201649ab747fSPaolo Bonzini .has_extended_tcb_support = true,
201749ab747fSPaolo Bonzini .power_management = true,
201849ab747fSPaolo Bonzini },{
201949ab747fSPaolo Bonzini /* Toshiba Tecra 8200. */
202049ab747fSPaolo Bonzini .name = "i82801",
202149ab747fSPaolo Bonzini .desc = "Intel i82801 Ethernet",
202249ab747fSPaolo Bonzini .device = i82801,
202349ab747fSPaolo Bonzini .device_id = 0x2449,
202449ab747fSPaolo Bonzini .revision = 0x03,
202549ab747fSPaolo Bonzini .stats_size = 80,
202649ab747fSPaolo Bonzini .has_extended_tcb_support = true,
202749ab747fSPaolo Bonzini .power_management = true,
202849ab747fSPaolo Bonzini }
202949ab747fSPaolo Bonzini };
203049ab747fSPaolo Bonzini
eepro100_get_class_by_name(const char * typename)203149ab747fSPaolo Bonzini static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
203249ab747fSPaolo Bonzini {
203349ab747fSPaolo Bonzini E100PCIDeviceInfo *info = NULL;
203449ab747fSPaolo Bonzini int i;
203549ab747fSPaolo Bonzini
203649ab747fSPaolo Bonzini /* This is admittedly awkward but also temporary. QOM allows for
203749ab747fSPaolo Bonzini * parameterized typing and for subclassing both of which would suitable
203849ab747fSPaolo Bonzini * handle what's going on here. But class_data is already being used as
203949ab747fSPaolo Bonzini * a stop-gap hack to allow incremental qdev conversion so we cannot use it
204049ab747fSPaolo Bonzini * right now. Once we merge the final QOM series, we can come back here and
204149ab747fSPaolo Bonzini * do this in a much more elegant fashion.
204249ab747fSPaolo Bonzini */
204349ab747fSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
204449ab747fSPaolo Bonzini if (strcmp(e100_devices[i].name, typename) == 0) {
204549ab747fSPaolo Bonzini info = &e100_devices[i];
204649ab747fSPaolo Bonzini break;
204749ab747fSPaolo Bonzini }
204849ab747fSPaolo Bonzini }
204949ab747fSPaolo Bonzini assert(info != NULL);
205049ab747fSPaolo Bonzini
205149ab747fSPaolo Bonzini return info;
205249ab747fSPaolo Bonzini }
205349ab747fSPaolo Bonzini
eepro100_get_class(EEPRO100State * s)205449ab747fSPaolo Bonzini static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
205549ab747fSPaolo Bonzini {
205649ab747fSPaolo Bonzini return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
205749ab747fSPaolo Bonzini }
205849ab747fSPaolo Bonzini
205949ab747fSPaolo Bonzini static Property e100_properties[] = {
206049ab747fSPaolo Bonzini DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
206149ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
206249ab747fSPaolo Bonzini };
206349ab747fSPaolo Bonzini
eepro100_class_init(ObjectClass * klass,void * data)206449ab747fSPaolo Bonzini static void eepro100_class_init(ObjectClass *klass, void *data)
206549ab747fSPaolo Bonzini {
206649ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
206749ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
206849ab747fSPaolo Bonzini E100PCIDeviceInfo *info;
206949ab747fSPaolo Bonzini
207049ab747fSPaolo Bonzini info = eepro100_get_class_by_name(object_class_get_name(klass));
207149ab747fSPaolo Bonzini
2072125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
20734f67d30bSMarc-André Lureau device_class_set_props(dc, e100_properties);
207449ab747fSPaolo Bonzini dc->desc = info->desc;
207549ab747fSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_INTEL;
207649ab747fSPaolo Bonzini k->class_id = PCI_CLASS_NETWORK_ETHERNET;
207749ab747fSPaolo Bonzini k->romfile = "pxe-eepro100.rom";
20789af21dbeSMarkus Armbruster k->realize = e100_nic_realize;
207949ab747fSPaolo Bonzini k->exit = pci_nic_uninit;
208049ab747fSPaolo Bonzini k->device_id = info->device_id;
208149ab747fSPaolo Bonzini k->revision = info->revision;
208249ab747fSPaolo Bonzini k->subsystem_vendor_id = info->subsystem_vendor_id;
208349ab747fSPaolo Bonzini k->subsystem_id = info->subsystem_id;
208449ab747fSPaolo Bonzini }
208549ab747fSPaolo Bonzini
eepro100_register_types(void)208649ab747fSPaolo Bonzini static void eepro100_register_types(void)
208749ab747fSPaolo Bonzini {
208849ab747fSPaolo Bonzini size_t i;
208949ab747fSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
209049ab747fSPaolo Bonzini TypeInfo type_info = {};
209149ab747fSPaolo Bonzini E100PCIDeviceInfo *info = &e100_devices[i];
209249ab747fSPaolo Bonzini
209349ab747fSPaolo Bonzini type_info.name = info->name;
209449ab747fSPaolo Bonzini type_info.parent = TYPE_PCI_DEVICE;
209549ab747fSPaolo Bonzini type_info.class_init = eepro100_class_init;
209649ab747fSPaolo Bonzini type_info.instance_size = sizeof(EEPRO100State);
20977317bb17SGonglei type_info.instance_init = eepro100_instance_init;
2098fd3b02c8SEduardo Habkost type_info.interfaces = (InterfaceInfo[]) {
2099fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
2100fd3b02c8SEduardo Habkost { },
2101fd3b02c8SEduardo Habkost };
210249ab747fSPaolo Bonzini
210349ab747fSPaolo Bonzini type_register(&type_info);
210449ab747fSPaolo Bonzini }
210549ab747fSPaolo Bonzini }
210649ab747fSPaolo Bonzini
210749ab747fSPaolo Bonzini type_init(eepro100_register_types)
2108