📄 eepro100.c.svn-base
字号:
/* * QEMU i8255x (PRO100) emulation * * Copyright (c) 2006-2007 Stefan Weil * * Portions of the code are copies from grub / etherboot eepro100.c * and linux e100.c. * * 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 * * Tested features (i82559): * PXE boot (i386) no valid link * Linux networking (i386) ok * * Untested: * non-i386 platforms * Windows networking * * References: * * Intel 8255x 10/100 Mbps Ethernet Controller Family * Open Source Software Developer Manual */#if defined(TARGET_I386)# warning "PXE boot still not working!"#endif#include <assert.h>#include <stddef.h> /* offsetof */#include "hw.h"#include "pci.h"#include "net.h"#include "eeprom93xx.h"/* Common declarations for all PCI devices. */#define PCI_VENDOR_ID 0x00 /* 16 bits */#define PCI_DEVICE_ID 0x02 /* 16 bits */#define PCI_COMMAND 0x04 /* 16 bits */#define PCI_STATUS 0x06 /* 16 bits */#define PCI_REVISION_ID 0x08 /* 8 bits */#define PCI_CLASS_CODE 0x0b /* 8 bits */#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */#define PCI_HEADER_TYPE 0x0e /* 8 bits */#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */#define PCI_CONFIG_8(offset, value) \ (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))#define KiB 1024/* debug EEPRO100 card *///~ #define DEBUG_EEPRO100#ifdef DEBUG_EEPRO100#define logout(fmt, args...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ##args)#else#define logout(fmt, args...) ((void)0)#endif/* Set flags to 0 to disable debug output. */#define MDI 0#define TRACE(flag, command) ((flag) ? (command) : (void)0)#define missing(text) assert(!"feature is missing in this emulation: " text)#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 EEPROM_SIZE 64#define PCI_MEM_SIZE (4 * KiB)#define PCI_IO_SIZE 64#define PCI_FLASH_SIZE (128 * KiB)#define BIT(n) (1 << (n))#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)/* The SCB accepts the following controls for the Tx and Rx units: */#define CU_NOP 0x0000 /* No operation. */#define CU_START 0x0010 /* CU start. */#define CU_RESUME 0x0020 /* CU resume. */#define CU_STATSADDR 0x0040 /* Load dump counters address. */#define CU_SHOWSTATS 0x0050 /* Dump statistical counters. */#define CU_CMD_BASE 0x0060 /* Load CU base address. */#define CU_DUMPSTATS 0x0070 /* Dump and reset statistical counters. */#define CU_SRESUME 0x00a0 /* CU static resume. */#define RU_NOP 0x0000#define RX_START 0x0001#define RX_RESUME 0x0002#define RX_ABORT 0x0004#define RX_ADDR_LOAD 0x0006#define RX_RESUMENR 0x0007#define INT_MASK 0x0100#define DRVR_INT 0x0200 /* Driver generated interrupt. */typedef unsigned char bool;/* Offsets to the various registers. All accesses need not be longword aligned. */enum speedo_offsets { SCBStatus = 0, SCBAck = 1, SCBCmd = 2, /* Rx/Command Unit command and status. */ SCBIntmask = 3, SCBPointer = 4, /* General purpose pointer. */ SCBPort = 8, /* Misc. commands and operands. */ SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ SCBCtrlMDI = 16, /* MDI interface control. */ SCBEarlyRx = 20, /* Early receive byte count. */ SCBFlow = 24,};/* A speedo3 transmit buffer descriptor with two buffers... */typedef struct { uint16_t status; uint16_t command; uint32_t link; /* void * */ uint32_t tx_desc_addr; /* transmit buffer decsriptor array address. */ uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */ uint8_t tx_threshold; /* transmit threshold */ uint8_t tbd_count; /* TBD number */ //~ /* This constitutes two "TBD" entries: hdr and data */ //~ uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */ //~ int32_t tx_buf_size0; /* Length of Tx hdr. */ //~ uint32_t tx_buf_addr1; /* void *, data to be transmitted. */ //~ int32_t tx_buf_size1; /* Length of Tx data. */} eepro100_tx_t;/* Receive frame descriptor. */typedef struct { int16_t status; uint16_t command; uint32_t link; /* struct RxFD * */ uint32_t rx_buf_addr; /* void * */ uint16_t count; uint16_t size; char packet[MAX_ETH_FRAME_SIZE + 4];} eepro100_rx_t;typedef struct { uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions, tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, tx_multiple_collisions, tx_total_collisions; uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors, rx_resource_errors, rx_overrun_errors, rx_cdt_errors, rx_short_frame_errors; uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; uint16_t xmt_tco_frames, rcv_tco_frames; uint32_t complete;} eepro100_stats_t;typedef enum { cu_idle = 0, cu_suspended = 1, cu_active = 2, cu_lpq_active = 2, cu_hqp_active = 3} cu_state_t;typedef enum { ru_idle = 0, ru_suspended = 1, ru_no_resources = 2, ru_ready = 4} ru_state_t;#if defined(__BIG_ENDIAN_BITFIELD)#define X(a,b) b,a#else#define X(a,b) a,b#endiftypedef struct {#if 1 uint8_t cmd; uint32_t start; uint32_t stop; uint8_t boundary; uint8_t tsr; uint8_t tpsr; uint16_t tcnt; uint16_t rcnt; uint32_t rsar; uint8_t rsr; uint8_t rxcr; uint8_t isr; uint8_t dcfg; uint8_t imr; uint8_t phys[6]; /* mac address */ uint8_t curpag; uint8_t mult[8]; /* multicast mask array */ int mmio_index; PCIDevice *pci_dev; VLANClientState *vc;#endif uint8_t scb_stat; /* SCB stat/ack byte */ uint8_t int_stat; /* PCI interrupt status */ uint32_t region[3]; /* PCI region addresses */ uint8_t macaddr[6]; uint32_t statcounter[19]; uint16_t mdimem[32]; eeprom_t *eeprom; uint32_t device; /* device variant */ uint32_t pointer; /* (cu_base + cu_offset) address the next command block in the command block list. */ uint32_t cu_base; /* CU base address */ uint32_t cu_offset; /* CU address offset */ /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */ uint32_t ru_base; /* RU base address */ uint32_t ru_offset; /* RU address offset */ uint32_t statsaddr; /* pointer to eepro100_stats_t */ eepro100_stats_t statistics; /* statistical counters */#if 0 uint16_t status;#endif /* Configuration bytes. */ uint8_t configuration[22]; /* Data in mem is always in the byte order of the controller (le). */ uint8_t mem[PCI_MEM_SIZE];} EEPRO100State;/* Default values for MDI (PHY) registers */static const uint16_t eepro100_mdi_default[] = { /* MDI Registers 0 - 6, 7 */ 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000, /* MDI Registers 8 - 15 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* MDI Registers 16 - 31 */ 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,};/* Readonly mask for MDI (PHY) registers */static const uint16_t eepro100_mdi_mask[] = { 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,};#define POLYNOMIAL 0x04c11db6/* From FreeBSD *//* XXX: optimize */static int compute_mcast_idx(const uint8_t * ep){ uint32_t crc; int carry, i, j; uint8_t b; crc = 0xffffffff; for (i = 0; i < 6; i++) { b = *ep++; for (j = 0; j < 8; j++) { carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); crc <<= 1; b >>= 1; if (carry) crc = ((crc ^ POLYNOMIAL) | carry); } } return (crc >> 26);}#if defined(DEBUG_EEPRO100)static const char *nic_dump(const uint8_t * buf, unsigned size){ static char dump[3 * 16 + 1]; char *p = &dump[0]; if (size > 16) size = 16; while (size-- > 0) { p += sprintf(p, " %02x", *buf++); } return dump;}#endif /* DEBUG_EEPRO100 */enum scb_stat_ack { stat_ack_not_ours = 0x00, stat_ack_sw_gen = 0x04, stat_ack_rnr = 0x10, stat_ack_cu_idle = 0x20, stat_ack_frame_rx = 0x40, stat_ack_cu_cmd_done = 0x80, stat_ack_not_present = 0xFF, stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx), stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),};static void disable_interrupt(EEPRO100State * s){ if (s->int_stat) { logout("interrupt disabled\n"); qemu_irq_lower(s->pci_dev->irq[0]); s->int_stat = 0; }}static void enable_interrupt(EEPRO100State * s){ if (!s->int_stat) { logout("interrupt enabled\n"); qemu_irq_raise(s->pci_dev->irq[0]); s->int_stat = 1; }}static void eepro100_acknowledge(EEPRO100State * s){ s->scb_stat &= ~s->mem[SCBAck]; s->mem[SCBAck] = s->scb_stat; if (s->scb_stat == 0) { disable_interrupt(s); }}static void eepro100_interrupt(EEPRO100State * s, uint8_t stat){ uint8_t mask = ~s->mem[SCBIntmask]; s->mem[SCBAck] |= stat; stat = s->scb_stat = s->mem[SCBAck]; stat &= (mask | 0x0f); //~ stat &= (~s->mem[SCBIntmask] | 0x0xf); if (stat && (mask & 0x01)) { /* SCB mask and SCB Bit M do not disable interrupt. */ enable_interrupt(s); } else if (s->int_stat) { disable_interrupt(s); }}static void eepro100_cx_interrupt(EEPRO100State * s){ /* CU completed action command. */ /* Transmit not ok (82557 only, not in emulation). */ eepro100_interrupt(s, 0x80);}static void eepro100_cna_interrupt(EEPRO100State * s){ /* CU left the active state. */ eepro100_interrupt(s, 0x20);}static void eepro100_fr_interrupt(EEPRO100State * s){ /* RU received a complete frame. */ eepro100_interrupt(s, 0x40);}#if 0static void eepro100_rnr_interrupt(EEPRO100State * s){ /* RU is not ready. */ eepro100_interrupt(s, 0x10);}#endifstatic void eepro100_mdi_interrupt(EEPRO100State * s){ /* MDI completed read or write cycle. */ eepro100_interrupt(s, 0x08);}static void eepro100_swi_interrupt(EEPRO100State * s){ /* Software has requested an interrupt. */ eepro100_interrupt(s, 0x04);}#if 0static void eepro100_fcp_interrupt(EEPRO100State * s){ /* Flow control pause interrupt (82558 and later). */ eepro100_interrupt(s, 0x01);}#endifstatic void pci_reset(EEPRO100State * s){ uint32_t device = s->device; uint8_t *pci_conf = s->pci_dev->config; logout("%p\n", s); /* PCI Vendor ID */ PCI_CONFIG_16(PCI_VENDOR_ID, 0x8086); /* PCI Device ID */ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209); /* PCI Command */ PCI_CONFIG_16(PCI_COMMAND, 0x0000); /* PCI Status */ PCI_CONFIG_16(PCI_STATUS, 0x2800); /* PCI Revision ID */ PCI_CONFIG_8(PCI_REVISION_ID, 0x08); /* PCI Class Code */ PCI_CONFIG_8(0x09, 0x00); PCI_CONFIG_8(PCI_SUBCLASS_CODE, 0x00); // ethernet network controller PCI_CONFIG_8(PCI_CLASS_CODE, 0x02); // network controller /* PCI Cache Line Size */ /* check cache line size!!! */ //~ PCI_CONFIG_8(0x0c, 0x00); /* PCI Latency Timer */ PCI_CONFIG_8(0x0d, 0x20); // latency timer = 32 clocks /* PCI Header Type */ /* BIST (built-in self test) */#if defined(TARGET_I386)// !!! workaround for buggy bios//~ #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0#endif#if 0 /* PCI Base Address Registers */ /* CSR Memory Mapped Base Address */ PCI_CONFIG_32(PCI_BASE_ADDRESS_0, PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH); /* CSR I/O Mapped Base Address */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -