📄 e100.c
字号:
/* * QEMU E100(i82557) ethernet card emulation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Copyright (c) 2006-2007 Stefan Weil * Copyright (c) 2006-2007 Zhang Xin(xing.z.zhang@intel.com) * * Support OS: * x86 linux and windows * PAE linux and windows * x86_64 linux and windows * IA64 linux and windows * * Untested: * Big-endian machine * * References: * * Intel 8255x 10/100 Mbps Ethernet Controller Family * Open Source Software Developer Manual */#include <assert.h>#include "vl.h"enum{ E100_PCI_VENDOR_ID = 0x00, /* 16 bits */ E100_PCI_DEVICE_ID = 0x02, /* 16 bits */ E100_PCI_COMMAND = 0x04, /* 16 bits */ E100_PCI_STATUS = 0x06, /* 16 bits */ E100_PCI_REVISION_ID = 0x08, /* 8 bits */ E100_PCI_CLASS_CODE = 0x0b, /* 8 bits */ E100_PCI_SUBCLASS_CODE = 0x0a, /* 8 bits */ E100_PCI_HEADER_TYPE = 0x0e, /* 8 bits */ E100_PCI_BASE_ADDRESS_0 = 0x10, /* 32 bits */ E100_PCI_BASE_ADDRESS_1 = 0x14, /* 32 bits */ E100_PCI_BASE_ADDRESS_2 = 0x18, /* 32 bits */ E100_PCI_BASE_ADDRESS_3 = 0x1c, /* 32 bits */ E100_PCI_BASE_ADDRESS_4 = 0x20, /* 32 bits */ E100_PCI_BASE_ADDRESS_5 = 0x24 /* 32 bits */}PCI_CONFIGURE_SPACE;#define PCI_CONFIG_8(offset, value) \ (*(uint8_t *)&pci_conf[offset] = (value))#define PCI_CONFIG_16(offset, value) \ (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value))#define PCI_CONFIG_32(offset, value) \ (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value))// Alias for Control/Status register read/write#define CSR_STATUS scb_status#define CSR_CMD scb_cmd#define CSR_POINTER scb_pointer#define CSR_PORT port#define CSR_EEPROM eeprom_ctrl#define CSR_MDI mdi_ctrl#define CSR_PM pm_reg#define CSR(class, field) \ (s->pci_mem.csr.class.u.field)#define CSR_VAL(class) \ (s->pci_mem.csr.class.val)#define CSR_READ(x, type) \ ({ \ type t; \ memcpy(&t, &s->pci_mem.mem[x], sizeof(type)); \ t; \ })#define CSR_WRITE(x, val, type) \ ({ \ type t = val; \ memcpy(&s->pci_mem.mem[x], &t, sizeof(type)); \ })#define SET_CU_STATE(val) \ (CSR(CSR_STATUS, cus) = val)#define GET_CU_STATE \ (CSR(CSR_STATUS, cus))#define SET_RU_STATE(val) \ (CSR(CSR_STATUS, rus) = val)#define GET_RU_STATE \ (CSR(CSR_STATUS, rus))#define KiB 1024#define EEPROM_SIZE 64#define BIT(n) (1U << (n))/* debug E100 card *///#define DEBUG_E100#ifdef DEBUG_E100#define logout(fmt, args...) fprintf(stderr, "EE100\t%-28s" fmt, __func__, ##args)#else#define logout(fmt, args...) ((void)0)#endif#define MAX_ETH_FRAME_SIZE 1514/* This driver supports several different devices which are declared here. */#define i82551 0x82551#define i82557B 0x82557b#define i82557C 0x82557c#define i82558B 0x82558b#define i82559C 0x82559c#define i82559ER 0x82559e#define i82562 0x82562#define PCI_MEM_SIZE (4 * KiB)#define PCI_IO_SIZE (64)#define PCI_FLASH_SIZE (128 * KiB)enum{ OP_READ, OP_WRITE,} OPERTAION_DIRECTION;/* The SCB accepts the following controls for the Tx and Rx units: */enum{ CU_NOP = 0x0000, /* No operation */ CU_START = 0x0010, /* CU start */ CU_RESUME = 0x0020, /* CU resume */ CU_STATSADDR = 0x0040, /* Load dump counters address */ CU_SHOWSTATS = 0x0050, /* Dump statistical counters */ CU_CMD_BASE = 0x0060, /* Load CU base address */ CU_DUMPSTATS = 0x0070, /* Dump and reset statistical counters */ CU_S_RESUME = 0x00a0 /* CU static resume */}CONTROL_UNIT_COMMAND;enum{ RU_NOP = 0x0000, RU_START = 0x0001, RU_RESUME = 0x0002, RU_DMA_REDIRECT = 0x0003, RU_ABORT = 0x0004, RU_LOAD_HDS = 0x0005, RU_ADDR_LOAD = 0x0006, RU_RESUMENR = 0x0007,}RECEIVE_UNIT_COMMAND;/* SCB status word descriptions */enum{ CU_IDLE = 0, CU_SUSPENDED = 1, CU_LPQ_ACTIVE = 2, CU_HQP_ACTIVE = 3} CONTROL_UINT_STATE;enum{ RU_IDLE = 0, RU_SUSPENDED = 1, RU_NO_RESOURCES =2, RU_READY = 4} RECEIVE_UNIT_STATE;enum{ PORT_SOFTWARE_RESET = 0, PORT_SELF_TEST = 1, PORT_SELECTIVE_RESET = 2, PORT_DUMP = 3, PORT_DUMP_WAKE_UP = 7,}SCB_PORT_SELECTION_FUNCTION;enum{ CBL_NOP = 0, CBL_IASETUP = 1, CBL_CONFIGURE = 2, CBL_MULTCAST_ADDR_SETUP = 3, CBL_TRANSMIT = 4, CBL_LOAD_MICROCODE = 5, CBL_DUMP = 6, CBL_DIAGNOSE = 7,}CBL_COMMAND;enum{ SCB_STATUS = 0, /* SCB base + 0x00h, RU states + CU states + STAT/ACK */ SCB_ACK = 1, /* SCB ack/stat */ SCB_CMD = 2, /* RU command + CU command + S bit + M bit */ SCB_INTERRUPT_MASK = 3, /* Interrupts mask bits */ SCB_POINTER = 4, /* SCB general pointer, depending on command type */ SCB_PORT = 8, /* SCB port register */ SCB_EEPROM = 0xe, /* SCB eeprom control register */ SCB_MDI =0x10, /* SCB MDI control register */} CSR_OFFSETS;enum{ EEPROM_SK = 0x01, EEPROM_CS = 0x02, EEPROM_DI = 0x04, EEPROM_DO = 0x08,} EEPROM_CONTROL_REGISTER;enum{ EEPROM_READ = 0x2, EEPROM_WRITE = 0x1, EEPROM_ERASE = 0x3,} EEPROM_OPCODE;enum{ MDI_WRITE = 0x1, MDI_READ = 0x2,} MDI_OPCODE;enum{ INT_FCP = BIT(8), INT_SWI = BIT(10), INT_MDI = BIT(11), INT_RNR = BIT(12), INT_CNA = BIT(13), INT_FR = BIT(14), INT_CX_TNO = BIT(15),} E100_INTERRUPT;enum{ CSR_MEMORY_BASE, CSR_IO_BASE, FLASH_MEMORY_BASE, REGION_NUM}E100_PCI_MEMORY_REGION;typedef struct { uint32_t tx_good_frames, // Good frames transmitted tx_max_collisions, // Fatal frames -- had max collisions tx_late_collisions, // Fatal frames -- had a late coll. tx_underruns, // Transmit underruns (fatal or re-transmit) tx_lost_crs, // Frames transmitted without CRS tx_deferred, // Deferred transmits tx_single_collisions, // Transmits that had 1 and only 1 coll. tx_multiple_collisions,// Transmits that had multiple coll. tx_total_collisions, // Transmits that had 1+ collisions. rx_good_frames, // Good frames received rx_crc_errors, // Aligned frames that had a CRC error rx_alignment_errors, // Receives that had alignment errors rx_resource_errors, // Good frame dropped due to lack of resources rx_overrun_errors, // Overrun errors - bus was busy rx_cdt_errors, // Received frames that encountered coll. rx_short_frame_errors, // Received frames that were to short complete_word; // A005h indicates dump cmd completion, // A007h indicates dump and reset cmd completion.// TODO: Add specific field for i82558, i82559} __attribute__ ((packed)) e100_stats_t;#define EEPROM_I82557_ADDRBIT 6/* Below data is dumped from a real I82557 card */static const uint16_t eeprom_i82557[] ={ 0x300, 0xe147, 0x2fa4, 0x203, 0x0, 0x201, 0x4701, 0x0, 0x7414, 0x6207, 0x4082, 0xb, 0x8086, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x128, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc374,};static const uint8_t e100_pci_configure[] ={ 0x86, 0x80, 0x29, 0x12, 0x17, 0x00, 0x90, 0x02, 0x08, 0x00, 0x00, 0x02, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x80, 0x0b, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x08, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0xfe, 0x00, 0x40, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,};typedef struct{#define OPCODE 0xb#define ADDR 0xc#define DATA 0xd#define NOP 0xe#define EEPROM_RESET_ALL 0xfe#define EEPROM_SELECT_RESET 0xff uint8_t start_bit; uint8_t opcode; uint8_t address; uint16_t data; //This must be 16 bit represents a register in eeprom uint32_t val; uint32_t val_len; uint8_t val_type; // What data type is in DI. opcode?address?data? uint8_t cs; uint8_t sk; // This two fileds only be reset when device init uint16_t addr_len; uint16_t contents[256]; // 256 is enough to all device(i82557 ... i82559)} eeprom_t;// Control/Status register structuretypedef struct{ /* SCB status word */ union { uint16_t val; struct { uint8_t rs1:2; // Reserved uint8_t rus:4; // RU status uint8_t cus:2; // CU status uint8_t stat_ack; // Stat/ACK }u; }scb_status; /* SCB command word */ union { uint16_t val; struct { uint8_t ru_cmd:3; // RU command uint8_t rs1:1; // Reserved uint8_t cu_cmd:4; // CU command uint8_t m:1; // Interrup mask bit(1:mask all interrupt) uint8_t si:1; // Use for software cause interrupt uint8_t simb:6; // Specific interrupt mask bit }u; }scb_cmd; /* SCB general pointer */ union { uint32_t val; struct { uint32_t scb_ptr; }u; }scb_pointer; /* Port interface */ union { uint32_t val; struct { uint8_t opcode:4; // Op code for function selection uint32_t ptr:28; // Result pointer }u; }port; uint16_t rs1; // Reserved /* EEPROM control register */ union { uint16_t val; struct { uint8_t eesk:1; // Serial clock uint8_t eecs:1; // Chip select uint8_t eedi:1; // Serial data in uint8_t eedo:1; // Serial data out uint8_t rs1:4; // Reserved uint8_t data; }u; }eeprom_ctrl; /* MDI control register */ union { uint32_t val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -