代码主体部分已经完成,主要测试了IO读写、LOOPBACK模式、自发自收模式、网络模式。具体原理可以参见网卡的DataSheet和Linux驱动代码。 头文件: /* * TestAM79C97x.h * * Created on: 2010-2-4 * Author: Administrator */ #ifndef TESTAM79C97X_H_ #define TESTAM79C97X_H_ #include <stdlib.h> #include <hw/pci.h> #include <string.h> #include <hw/inout.h> #include <sys/neutrino.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <sys/mman.h> #include "TestDebug.h" /* * I/O map in 16-bit mode. To switch to 32-bit mode, * you need to perform a 32-bit write to the RDP register * (writing a 0 is recommended). */ #define PCN_IO16_APROM00 0x00 #define PCN_IO16_APROM01 0x02 #define PCN_IO16_APROM02 0x04 #define PCN_IO16_APROM03 0x06 #define PCN_IO16_APROM04 0x08 #define PCN_IO16_APROM05 0x0A #define PCN_IO16_APROM06 0x0C #define PCN_IO16_APROM07 0x0E #define PCN_IO16_RDP 0x10 #define PCN_IO16_RAP 0x12 #define PCN_IO16_RESET 0x14 #define PCN_IO16_BDP 0x16 /* * I/O map in 32-bit mode. */ #define PCN_IO32_APROM00 0x00 #define PCN_IO32_APROM01 0x04 #define PCN_IO32_APROM02 0x08 #define PCN_IO32_APROM03 0x0C #define PCN_IO32_RDP 0x10 #define PCN_IO32_RAP 0x14 #define PCN_IO32_RESET 0x18 #define PCN_IO32_BDP 0x1C /* * CSR registers */ #define PCN_CSR_CSR 0x00 #define PCN_CSR_IAB0 0x01 #define PCN_CSR_IAB1 0x02 #define PCN_CSR_IMR 0x03 #define PCN_CSR_TFEAT 0x04 #define PCN_CSR_EXTCTL1 0x05 #define PCN_CSR_DTBLLEN 0x06 #define PCN_CSR_EXTCTL2 0x07 #define PCN_CSR_MAR0 0x08 #define PCN_CSR_MAR1 0x09 #define PCN_CSR_MAR2 0x0A #define PCN_CSR_MAR3 0x0B #define PCN_CSR_PAR0 0x0C #define PCN_CSR_PAR1 0x0D #define PCN_CSR_PAR2 0x0E #define PCN_CSR_MODE 0x0F #define PCN_CSR_RXADDR0 0x18 #define PCN_CSR_RXADDR1 0x19 #define PCN_CSR_TXADDR0 0x1E #define PCN_CSR_TXADDR1 0x1F #define PCN_CSR_TXPOLL 0x2F #define PCN_CSR_RXPOLL 0x31 #define PCN_CSR_RXRINGLEN 0x4C #define PCN_CSR_TXRINGLEN 0x4E #define PCN_CSR_DMACTL 0x50 #define PCN_CSR_BUSTIMER 0x52 #define PCN_CSR_MEMERRTIMEO 0x64 #define PCN_CSR_ONNOWMISC 0x74 #define PCN_CSR_ADVFEAT 0x7A #define PCN_CSR_MACCFG 0x7D #define PCN_CSR_CHIPID0 0x58 #define PCN_CSR_CHIPID1 0x59 /* * Control and status register (CSR0) */ #define PCN_CSR_INIT 0x0001 #define PCN_CSR_START 0x0002 #define PCN_CSR_STOP 0x0004 #define PCN_CSR_TX 0x0008 #define PCN_CSR_TXON 0x0010 #define PCN_CSR_RXON 0x0020 #define PCN_CSR_INTEN 0x0040 #define PCN_CSR_INTR 0x0080 #define PCN_CSR_IDONE 0x0100 #define PCN_CSR_TINT 0x0200 #define PCN_CSR_RINT 0x0400 #define PCN_CSR_MERR 0x0800 #define PCN_CSR_MISS 0x1000 #define PCN_CSR_CERR 0x2000 #define PCN_CSR_ERR 0x8000 /* * Interrupt masks and deferral control (CSR3) */ #define PCN_IMR_BSWAP 0x0004 #define PCN_IMR_ENMBA 0x0008 /* enable modified backoff alg */ #define PCN_IMR_DXMT2PD 0x0010 #define PCN_IMR_LAPPEN 0x0020 /* lookahead packet processing enb */ #define PCN_IMR_DXSUFLO 0x0040 /* disable TX stop on underflow */ #define PCN_IMR_IDONE 0x0100 #define PCN_IMR_TINT 0x0200 #define PCN_IMR_RINT 0x0400 #define PCN_IMR_MERR 0x0800 #define PCN_IMR_MISS 0x1000 /* * Test and features control (CSR4) */ #define PCN_TFEAT_TXSTRTMASK 0x0004 #define PCN_TFEAT_TXSTRT 0x0008 #define PCN_TFEAT_RXCCOFLOWM 0x0010 /* Rx collision counter oflow */ #define PCN_TFEAT_RXCCOFLOW 0x0020 #define PCN_TFEAT_UINT 0x0040 #define PCN_TFEAT_UINTREQ 0x0080 #define PCN_TFEAT_MISSOFLOWM 0x0100 #define PCN_TFEAT_MISSOFLOW 0x0200 #define PCN_TFEAT_STRIP_FCS 0x0400 #define PCN_TFEAT_PAD_TX 0x0800 #define PCN_TFEAT_TXDPOLL 0x1000 #define PCN_TFEAT_DMAPLUS 0x4000 /* * Extended control and interrupt 1 (CSR5) */ #define PCN_EXTCTL1_SPND 0x0001 /* suspend */ #define PCN_EXTCTL1_MPMODE 0x0002 /* magic packet mode */ #define PCN_EXTCTL1_MPENB 0x0004 /* magic packet enable */ #define PCN_EXTCTL1_MPINTEN 0x0008 /* magic packet interrupt enable */ #define PCN_EXTCTL1_MPINT 0x0010 /* magic packet interrupt */ #define PCN_EXTCTL1_MPPLBA 0x0020 /* magic packet phys. logical bcast */ #define PCN_EXTCTL1_EXDEFEN 0x0040 /* excessive deferral interrupt enb. */ #define PCN_EXTCTL1_EXDEF 0x0080 /* excessive deferral interrupt */ #define PCN_EXTCTL1_SINTEN 0x0400 /* system interrupt enable */ #define PCN_EXTCTL1_SINT 0x0800 /* system interrupt */ #define PCN_EXTCTL1_LTINTEN 0x4000 /* last TX interrupt enb */ #define PCN_EXTCTL1_TXOKINTD 0x8000 /* TX OK interrupt disable */ /* * RX/TX descriptor len (CSR6) */ #define PCN_DTBLLEN_RLEN 0x0F00 #define PCN_DTBLLEN_TLEN 0xF000 /* * Extended control and interrupt 2 (CSR7) */ #define PCN_EXTCTL2_MIIPDTINTE 0x0001 #define PCN_EXTCTL2_MIIPDTINT 0x0002 #define PCN_EXTCTL2_MCCIINTE 0x0004 #define PCN_EXTCTL2_MCCIINT 0x0008 #define PCN_EXTCTL2_MCCINTE 0x0010 #define PCN_EXTCTL2_MCCINT 0x0020 #define PCN_EXTCTL2_MAPINTE 0x0040 #define PCN_EXTCTL2_MAPINT 0x0080 #define PCN_EXTCTL2_MREINTE 0x0100 #define PCN_EXTCTL2_MREINT 0x0200 #define PCN_EXTCTL2_STINTE 0x0400 #define PCN_EXTCTL2_STINT 0x0800 #define PCN_EXTCTL2_RXDPOLL 0x1000 #define PCN_EXTCTL2_RDMD 0x2000 #define PCN_EXTCTL2_RXFRTG 0x4000 #define PCN_EXTCTL2_FASTSPNDE 0x8000 /* * Mode (CSR15) */ #define PCN_MODE_RXD 0x0001 /* RX disable */ #define PCN_MODE_TXD 0x0002 /* TX disable */ #define PCN_MODE_LOOP 0x0004 /* loopback enable */ #define PCN_MODE_TXCRCD 0x0008 #define PCN_MODE_FORCECOLL 0x0010 #define PCN_MODE_RETRYD 0x0020 #define PCN_MODE_INTLOOP 0x0040 #define PCN_MODE_PORTSEL 0x0180 #define PCN_MODE_RXVPAD 0x2000 #define PCN_MODE_RXNOBROAD 0x4000 #define PCN_MODE_PROMISC 0x8000 /* Settings for PCN_MODE_PORTSEL when ASEL (BCR2[1]) is 0 */ #define PCN_PORT_AUI 0x0000 #define PCN_PORT_10BASET 0x0080 #define PCN_PORT_GPSI 0x0100 #define PCN_PORT_MII 0x0180 /* * Chip ID values. */ /* CSR88-89: Chip ID masks */ #define AMD_MASK 0x003 #define PART_MASK 0xffff #define Am79C971 0x2623 #define Am79C972 0x2624 #define Am79C973 0x2625 #define Am79C978 0x2626 #define Am79C975 0x2627 #define Am79C976 0x2628 /* * Advanced feature control (CSR122) */ #define PCN_AFC_RXALIGN 0x0001 /* * BCR (bus control) registers */ #define PCN_BCR_MMRA 0x00 /* Master Mode Read Active */ #define PCN_BCR_MMW 0x01 /* Master Mode Write Active */ #define PCN_BCR_MISCCFG 0x02 #define PCN_BCR_LED0 0x04 #define PCN_BCR_LED1 0x05 #define PCN_BCR_LED2 0x06 #define PCN_BCR_LED3 0x07 #define PCN_BCR_DUPLEX 0x09 #define PCN_BCR_BUSCTL 0x12 #define PCN_BCR_EECTL 0x13 #define PCN_BCR_SSTYLE 0x14 #define PCN_BCR_PCILAT 0x16 #define PCN_BCR_PCISUBVENID 0x17 #define PCN_BCR_PCISUBSYSID 0x18 #define PCN_BCR_SRAMSIZE 0x19 #define PCN_BCR_SRAMBOUND 0x1A #define PCN_BCR_SRAMCTL 0x1B #define PCN_BCR_MIICTL 0x20 #define PCN_BCR_MIIADDR 0x21 #define PCN_BCR_MIIDATA 0x22 #define PCN_BCR_PCIVENID 0x23 #define PCN_BCR_PCIPCAP 0x24 #define PCN_BCR_DATA0 0x25 #define PCN_BCR_DATA1 0x26 #define PCN_BCR_DATA2 0x27 #define PCN_BCR_DATA3 0x28 #define PCN_BCR_DATA4 0x29 #define PCN_BCR_DATA5 0x2A #define PCN_BCR_DATA6 0x2B #define PCN_BCR_DATA7 0x2C #define PCN_BCR_ONNOWPAT0 0x2D #define PCN_BCR_ONNOWPAT1 0x2E #define PCN_BCR_ONNOWPAT2 0x2F #define PCN_BCR_PHYSEL 0x31 /* * Miscellaneous Configuration (BCR2) */ #define PCN_MISC_TMAULOOP 1<<14 /* T-MAU Loopback packet enable. */ #define PCN_MISC_LEDPE 1<<12 /* LED Program Enable */ #define PCN_MISC_APROMWE 1<<8 /* Address PROM Write Enable */ #define PCN_MISC_INTLEVEL 1<<7 /* Interrupt level */ #define PCN_MISC_EADISEL 1<<3 /* EADI Select */ #define PCN_MISC_AWAKE 1<<2 /* Power saving mode select */ #define PCN_MISC_ASEL 1<<1 /* Auto Select */ #define PCN_MISC_XMAUSEL 1<<0 /* Reserved. */ /* * Full duplex control (BCR9) */ #define PCN_DUPLEX_FDEN 0x0001 /* Full-duplex enable */ #define PCN_DUPLEX_AUI 0x0002 /* AUI full-duplex */ #define PCN_DUPLEX_FDRPAD 0x0004 /* Full-duplex runt pkt accept dis. */ /* * Burst and bus control register (BCR18) */ #define PCN_BUSCTL_BWRITE 0x0020 #define PCN_BUSCTL_BREAD 0x0040 #define PCN_BUSCTL_DWIO 0x0080 #define PCN_BUSCTL_EXTREQ 0x0100 #define PCN_BUSCTL_MEMCMD 0x0200 #define PCN_BUSCTL_NOUFLOW 0x0800 #define PCN_BUSCTL_ROMTMG 0xF000 /* * EEPROM control (BCR19) */ #define PCN_EECTL_EDATA 0x0001 #define PCN_EECTL_ECLK 0x0002 #define PCN_EECTL_EECS 0x0004 #define PCN_EECTL_EEN 0x0100 #define PCN_EECTL_EEDET 0x2000 #define PCN_EECTL_PREAD 0x4000 #define PCN_EECTL_PVALID 0x8000 /* * Software style (BCR20) */ #define PCN_SSTYLE_APERREN 0x0400 /* advanced parity error checking */ #define PCN_SSTYLE_SSIZE32 0x0100 #define PCN_SSTYLE_SWSTYLE 0x00FF #define PCN_SWSTYLE_LANCE 0x0000 #define PCN_SWSTYLE_PCNETPCI 0x0102 #define PCN_SWSTYLE_PCNETPCI_BURST 0x0103 /* * MII control and status (BCR32) */ #define PCN_MIICTL_MIILP 0x0002 /* MII internal loopback */ #define PCN_MIICTL_XPHYSP 0x0008 /* external PHY speed */ #define PCN_MIICTL_XPHYFD 0x0010 /* external PHY full duplex */ #define PCN_MIICTL_XPHYANE 0x0020 /* external phy auto-neg enable */ #define PCN_MIICTL_XPHYRST 0x0040 /* external PHY reset */ #define PCN_MIICTL_DANAS 0x0080 /* disable auto-neg auto-setup */ #define PCN_MIICTL_APDW 0x0700 /* auto-poll dwell time */ #define PCN_MIICTL_APEP 0x0100 /* auto-poll external PHY */ #define PCN_MIICTL_FMDC 0x3000 /* data clock speed */ #define PCN_MIICTL_MIIPD 0x4000 /* PHY detect */ #define PCN_MIICTL_ANTST 0x8000 /* Manufacturing test */ /* * MII address register (BCR33) */ #define PCN_MIIADDR_REGAD 0x001F #define PCN_MIIADDR_PHYAD 0x03E0 /* addresses of internal PHYs */ #define PCN_PHYAD_100BTX 30 #define PCN_PHYAD_10BT 31 /* * MII data register (BCR34) */ #define PCN_MIIDATA_MIIMD 0xFFFF /* * PHY selection (BCR49) (HomePNA NIC only) */ #define PCN_PHYSEL_PHYSEL 0x0003 #define PCN_PHYSEL_DEFAULT 0x0300 #define PCN_PHYSEL_PCNET 0x8000 #define PCN_PHY_10BT 0x0000 #define PCN_PHY_HOMEPNA 0x0001 #define PCN_PHY_EXTERNAL 0x0002 //struct pcn_rx_desc { // u_int16_t pcn_rxlen; // u_int16_t pcn_rsvd0; // u_int16_t pcn_bufsz; // u_int16_t pcn_rxstat; // u_int32_t pcn_rbaddr; // u_int32_t pcn_uspace; //}; #define PCN_RXSTAT_BPE 0x0080 /* bus parity error */ #define PCN_RXSTAT_ENP 0x0100 /* end of packet */ #define PCN_RXSTAT_STP 0x0200 /* start of packet */ #define PCN_RXSTAT_BUFF 0x0400 /* buffer error */ #define PCN_RXSTAT_CRC 0x0800 /* CRC error */ #define PCN_RXSTAT_OFLOW 0x1000 /* rx overrun */ #define PCN_RXSTAT_FRAM 0x2000 /* framing error */ #define PCN_RXSTAT_ERR 0x4000 /* error summary */ #define PCN_RXSTAT_OWN 0x8000 #define PCN_RXLEN_MBO 0xF000 #define PCN_RXLEN_BUFSZ 0x0FFF #define PCN_OWN_RXDESC(x) (((x)->pcn_rxstat & PCN_RXSTAT_OWN) == 0) //struct pcn_tx_desc { // u_int32_t pcn_txstat; // u_int32_t pcn_txctl; // u_int32_t pcn_tbaddr; // u_int32_t pcn_uspace; //}; #define PCN_TXSTAT_TRC 0x0000000F /* transmit retries */ #define PCN_TXSTAT_RTRY 0x04000000 /* retry */ #define PCN_TXSTAT_LCAR 0x08000000 /* lost carrier */ #define PCN_TXSTAT_LCOL 0x10000000 /* late collision */ #define PCN_TXSTAT_EXDEF 0x20000000 /* excessive deferrals */ #define PCN_TXSTAT_UFLOW 0x40000000 /* transmit underrun */ #define PCN_TXSTAT_BUFF 0x80000000 /* buffer error */ #define PCN_TXCTL_OWN 0x80000000 #define PCN_TXCTL_ERR 0x40000000 /* error summary */ #define PCN_TXCTL_ADD_FCS 0x20000000 /* add FCS to pkt */ #define PCN_TXCTL_MORE_LTINT 0x10000000 #define PCN_TXCTL_ONE 0x08000000 #define PCN_TXCTL_DEF 0x04000000 #define PCN_TXCTL_STP 0x02000000 #define PCN_TXCTL_ENP 0x01000000 #define PCN_TXCTL_BPE 0x00800000 #define PCN_TXCTL_MBO 0x0000F000 #define PCN_TXCTL_BUFSZ 0x00000FFF #define PCN_OWN_TXDESC(x) (((x)->pcn_txctl & PCN_TXCTL_OWN) == 0) #define PCN_RX_LIST_CNT 64 #define PCN_TX_LIST_CNT 256 //struct pcn_list_data { // struct pcn_rx_desc pcn_rx_list[PCN_RX_LIST_CNT]; // struct pcn_tx_desc pcn_tx_list[PCN_TX_LIST_CNT]; //}; // //struct pcn_ring_data { // struct mbuf *pcn_rx_chain[PCN_RX_LIST_CNT]; // struct mbuf *pcn_tx_chain[PCN_TX_LIST_CNT]; // int pcn_rx_prod; // int pcn_tx_prod; // int pcn_tx_cons; // int pcn_tx_cnt; //}; /* * AMD PCI vendor ID. */ #define PCN_VENDORID 0x1022 /* * AMD PCnet/PCI device IDs */ #define PCN_DEVICEID_PCNET 0x2000 #define PCN_DEVICEID_HOME 0x2001 //struct pcn_type { // u_int16_t pcn_vid; // u_int16_t pcn_did; // const char *pcn_name; //}; // //struct pcn_softc { // struct ifnet *pcn_ifp; // bus_space_handle_t pcn_bhandle; // bus_space_tag_t pcn_btag; // struct resource *pcn_res; // struct resource *pcn_irq; // void *pcn_intrhand; // device_t pcn_miibus; // u_int8_t pcn_link; // int8_t pcn_extphyaddr; // int8_t pcn_inst_10bt; // int pcn_if_flags; // int pcn_type; // struct pcn_list_data *pcn_ldata; // struct pcn_ring_data pcn_cdata; // struct callout pcn_stat_callout; // struct mtx pcn_mtx; //}; #define PCN_LOCK(_sc) mtx_lock(&(_sc)->pcn_mtx) #define PCN_UNLOCK(_sc) mtx_unlock(&(_sc)->pcn_mtx) #define PCN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->pcn_mtx, MA_OWNED) /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) / bus_space_write_4(sc->pcn_btag, sc->pcn_bhandle, reg, val) #define CSR_READ_4(sc, reg) / bus_space_read_4(sc->pcn_btag, sc->pcn_bhandle, reg) #define CSR_WRITE_2(sc, reg, val) / bus_space_write_2(sc->pcn_btag, sc->pcn_bhandle, reg, val) #define CSR_READ_2(sc, reg) / bus_space_read_2(sc->pcn_btag, sc->pcn_bhandle, reg) #define PCN_TIMEOUT 1000 #define ETHER_ALIGN 2 #define PCN_RXLEN 1536 #define PCN_MIN_FRAMELEN 60 #define PCN_INC(x, y) (x) = (x + 1) % y /* * PCI low memory base and low I/O base register, and * other PCI registers. */ #define PCN_PCI_VENDOR_ID 0x00 #define PCN_PCI_DEVICE_ID 0x02 #define PCN_PCI_COMMAND 0x04 #define PCN_PCI_STATUS 0x06 #define PCN_PCI_REVID 0x08 #define PCN_PCI_CLASSCODE 0x09 #define PCN_PCI_CACHELEN 0x0C #define PCN_PCI_LATENCY_TIMER 0x0D #define PCN_PCI_HEADER_TYPE 0x0E #define PCN_PCI_LOIO 0x10 #define PCN_PCI_LOMEM 0x14 #define PCN_PCI_BIOSROM 0x30 #define PCN_PCI_INTLINE 0x3C #define PCN_PCI_INTPIN 0x3D #define PCN_PCI_MINGNT 0x3E #define PCN_PCI_MINLAT 0x3F #define PCN_PCI_RESETOPT 0x48 #define PCN_PCI_EEPROM_DATA 0x4C /* power management registers */ #define PCN_PCI_CAPID 0x50 /* 8 bits */ #define PCN_PCI_NEXTPTR 0x51 /* 8 bits */ #define PCN_PCI_PWRMGMTCAP 0x52 /* 16 bits */ #define PCN_PCI_PWRMGMTCTRL 0x54 /* 16 bits */ #define PCN_PSTATE_MASK 0x0003 #define PCN_PSTATE_D0 0x0000 #define PCN_PSTATE_D1 0x0001 #define PCN_PSTATE_D2 0x0002 #define PCN_PSTATE_D3 0x0003 #define PCN_PME_EN 0x0010 #define PCN_PME_STATUS 0x8000 /// #define PARTID_Am79c960 0x0003 #define PARTID_Am79c961 0x2260 #define PARTID_Am79c961A 0x2261 #define PARTID_Am79c965 0x2430 /* yes, these... */ #define PARTID_Am79c970 0x2430 /* ...are the same */ #define PARTID_Am79c970A 0x2621 #define PARTID_Am79c971 0x2623 #define PARTID_Am79c972 0x2624 #define PARTID_Am79c973 0x2625 #define PARTID_Am79c978 0x2626 #define PARTID_Am79c975 0x2627 #define PARTID_Am79c976 0x2628 /* * Description of a PCnet-PCI variant. Used to select media access * method, mostly, and to print a nice description of the chip. */ struct pcn_variant { const char *pcv_desc; uint16_t pcv_chipid; }; static const struct pcn_variant pcn_v[] = { { "Am79c970 PCnet-PCI", PARTID_Am79c970 }, { "Am79c970A PCnet-PCI II", PARTID_Am79c970A }, { "Am79c971 PCnet-FAST", PARTID_Am79c971 }, { "Am79c972 PCnet-FAST+", PARTID_Am79c972 }, { "Am79c973 PCnet-FAST III", PARTID_Am79c973 }, { "Am79c975 PCnet-FAST III", PARTID_Am79c975 }, { "Unknown PCnet-PCI variant", 0 }, }; #define CHIPID_PARTID(x) (((x) >> 12) & 0xffff) /* * Control and Status Register addresses */ #define LE_CSR0 0x0000 /* Control and status register */ #define LE_CSR1 0x0001 /* low address of init block */ #define LE_CSR2 0x0002 /* high address of init block */ #define LE_CSR3 0x0003 /* Bus master and control */ #define LE_CSR4 0x0004 /* Test and features control */ #define LE_CSR5 0x0005 /* Extended control and Interrupt 1 */ #define LE_CSR6 0x0006 /* Rx/Tx Descriptor table length */ #define LE_CSR7 0x0007 /* Extended control and interrupt 2 */ #define LE_CSR8 0x0008 /* Logical Address Filter 0 */ #define LE_CSR9 0x0009 /* Logical Address Filter 1 */ #define LE_CSR10 0x000a /* Logical Address Filter 2 */ #define LE_CSR11 0x000b /* Logical Address Filter 3 */ #define LE_CSR12 0x000c /* Physical Address 0 */ #define LE_CSR13 0x000d /* Physical Address 1 */ #define LE_CSR14 0x000e /* Physical Address 2 */ #define LE_CSR15 0x000f /* Mode */ #define LE_CSR16 0x0010 /* Initialization Block addr lower */ #define LE_CSR17 0x0011 /* Initialization Block addr upper */ #define LE_CSR18 0x0012 /* Current Rx Buffer addr lower */ #define LE_CSR19 0x0013 /* Current Rx Buffer addr upper */ #define LE_CSR20 0x0014 /* Current Tx Buffer addr lower */ #define LE_CSR21 0x0015 /* Current Tx Buffer addr upper */ #define LE_CSR22 0x0016 /* Next Rx Buffer addr lower */ #define LE_CSR23 0x0017 /* Next Rx Buffer addr upper */ #define LE_CSR24 0x0018 /* Base addr of Rx ring lower */ #define LE_CSR25 0x0019 /* Base addr of Rx ring upper */ #define LE_CSR26 0x001a /* Next Rx Desc addr lower */ #define LE_CSR27 0x001b /* Next Rx Desc addr upper */ #define LE_CSR28 0x001c /* Current Rx Desc addr lower */ #define LE_CSR29 0x001d /* Current Rx Desc addr upper */ #define LE_CSR30 0x001e /* Base addr of Tx ring lower */ #define LE_CSR31 0x001f /* Base addr of Tx ring upper */ #define LE_CSR32 0x0020 /* Next Tx Desc addr lower */ #define LE_CSR33 0x0021 /* Next Tx Desc addr upper */ #define LE_CSR34 0x0022 /* Current Tx Desc addr lower */ #define LE_CSR35 0x0023 /* Current Tx Desc addr upper */ #define LE_CSR36 0x0024 /* Next Next Rx Desc addr lower */ #define LE_CSR37 0x0025 /* Next Next Rx Desc addr upper */ #define LE_CSR38 0x0026 /* Next Next Tx Desc addr lower */ #define LE_CSR39 0x0027 /* Next Next Tx Desc adddr upper */ #define LE_CSR40 0x0028 /* Current Rx Byte Count */ #define LE_CSR41 0x0029 /* Current Rx Status */ #define LE_CSR42 0x002a /* Current Tx Byte Count */ #define LE_CSR43 0x002b /* Current Tx Status */ #define LE_CSR44 0x002c /* Next Rx Byte Count */ #define LE_CSR45 0x002d /* Next Rx Status */ #define LE_CSR46 0x002e /* Tx Poll Time Counter */ #define LE_CSR47 0x002f /* Tx Polling Interval */ #define LE_CSR48 0x0030 /* Rx Poll Time Counter */ #define LE_CSR49 0x0031 /* Rx Polling Interval */ #define LE_CSR58 0x003a /* Software Style */ #define LE_CSR60 0x003c /* Previous Tx Desc addr lower */ #define LE_CSR61 0x003d /* Previous Tx Desc addr upper */ #define LE_CSR62 0x003e /* Previous Tx Byte Count */ #define LE_CSR63 0x003f /* Previous Tx Status */ #define LE_CSR64 0x0040 /* Next Tx Buffer addr lower */ #define LE_CSR65 0x0041 /* Next Tx Buffer addr upper */ #define LE_CSR66 0x0042 /* Next Tx Byte Count */ #define LE_CSR67 0x0043 /* Next Tx Status */ #define LE_CSR72 0x0048 /* Receive Ring Counter */ #define LE_CSR74 0x004a /* Transmit Ring Counter */ #define LE_CSR76 0x004c /* Receive Ring Length */ #define LE_CSR78 0x004e /* Transmit Ring Length */ #define LE_CSR80 0x0050 /* DMA Transfer Counter and FIFO Threshold Control */ #define LE_CSR82 0x0052 /* Tx Desc addr Pointer lower */ #define LE_CSR84 0x0054 /* DMA addr register lower */ #define LE_CSR85 0x0055 /* DMA addr register upper */ #define LE_CSR86 0x0056 /* Buffer Byte Counter */ #define LE_CSR88 0x0058 /* Chip ID Register lower */ #define LE_CSR89 0x0059 /* Chip ID Register upper */ #define LE_CSR92 0x005c /* Ring Length Conversion */ #define LE_CSR100 0x0064 /* Bus Timeout */ #define LE_CSR112 0x0070 /* Missed Frame Count */ #define LE_CSR114 0x0072 /* Receive Collision Count */ #define LE_CSR116 0x0074 /* OnNow Power Mode Register */ #define LE_CSR122 0x007a /* Advanced Feature Control */ #define LE_CSR124 0x007c /* Test Register 1 */ #define LE_CSR125 0x007d /* MAC Enhanced Configuration Control */ /* Control and status register 0 (csr0) */ #define LE_C0_ERR 0x8000 /* error summary */ #define LE_C0_BABL 0x4000 /* transmitter timeout error */ #define LE_C0_CERR 0x2000 /* collision */ #define LE_C0_MISS 0x1000 /* missed a packet */ #define LE_C0_MERR 0x0800 /* memory error */ #define LE_C0_RINT 0x0400 /* receiver interrupt */ #define LE_C0_TINT 0x0200 /* transmitter interrupt */ #define LE_C0_IDON 0x0100 /* initialization done */ #define LE_C0_INTR 0x0080 /* interrupt condition */ #define LE_C0_INEA 0x0040 /* interrupt enable */ #define LE_C0_RXON 0x0020 /* receiver on */ #define LE_C0_TXON 0x0010 /* transmitter on */ #define LE_C0_TDMD 0x0008 /* transmit demand */ #define LE_C0_STOP 0x0004 /* disable all external activity */ #define LE_C0_STRT 0x0002 /* enable external activity */ #define LE_C0_INIT 0x0001 /* begin initialization */ /* Control and status register 3 (csr3) */ #define LE_C3_BABLM 0x4000 /* babble mask */ #define LE_C3_MISSM 0x1000 /* missed frame mask */ #define LE_C3_MERRM 0x0800 /* memory error mask */ #define LE_C3_RINTM 0x0400 /* receive interrupt mask */ #define LE_C3_TINTM 0x0200 /* transmit interrupt mask */ #define LE_C3_IDONM 0x0100 /* initialization done mask */ #define LE_C3_DXSUFLO 0x0040 /* disable tx stop on underflow */ #define LE_C3_LAPPEN 0x0020 /* look ahead packet processing enbl */ #define LE_C3_DXMT2PD 0x0010 /* disable tx two part deferral */ #define LE_C3_EMBA 0x0008 /* enable modified backoff algorithm */ #define LE_C3_BSWP 0x0004 /* byte swap */ #define LE_C3_ACON 0x0002 /* ALE control, eh? */ #define LE_C3_BCON 0x0001 /* byte control */ /* Control and status register 4 (csr4) */ #define LE_C4_EN124 0x8000 /* enable CSR124 */ #define LE_C4_DMAPLUS 0x4000 /* always set (PCnet-PCI) */ #define LE_C4_TIMER 0x2000 /* enable bus activity timer */ #define LE_C4_TXDPOLL 0x1000 /* disable transmit polling */ #define LE_C4_APAD_XMT 0x0800 /* auto pad transmit */ #define LE_C4_ASTRP_RCV 0x0400 /* auto strip receive */ #define LE_C4_MFCO 0x0200 /* missed frame counter overflow */ #define LE_C4_MFCOM 0x0100 /* missed frame coutner overflow mask */ #define LE_C4_UINTCMD 0x0080 /* user interrupt command */ #define LE_C4_UINT 0x0040 /* user interrupt */ #define LE_C4_RCVCCO 0x0020 /* receive collision counter overflow */ #define LE_C4_RCVCCOM 0x0010 /* receive collision counter overflow mask */ #define LE_C4_TXSTRT 0x0008 /* transmit start status */ #define LE_C4_TXSTRTM 0x0004 /* transmit start mask */ /* Control and status register 5 (csr5) */ #define LE_C5_TOKINTD 0x8000 /* transmit ok interrupt disable */ #define LE_C5_LTINTEN 0x4000 /* last transmit interrupt enable */ #define LE_C5_SINT 0x0800 /* system interrupt */ #define LE_C5_SINTE 0x0400 /* system interrupt enable */ #define LE_C5_EXDINT 0x0080 /* excessive deferral interrupt */ #define LE_C5_EXDINTE 0x0040 /* excessive deferral interrupt enbl */ #define LE_C5_MPPLBA 0x0020 /* magic packet physical logical broadcast accept */ #define LE_C5_MPINT 0x0010 /* magic packet interrupt */ #define LE_C5_MPINTE 0x0008 /* magic packet interrupt enable */ #define LE_C5_MPEN 0x0004 /* magic packet enable */ #define LE_C5_MPMODE 0x0002 /* magic packet mode */ #define LE_C5_SPND 0x0001 /* suspend */ /* Control and status register 6 (csr6) */ #define LE_C6_TLEN 0xf000 /* TLEN from init block */ #define LE_C6_RLEN 0x0f00 /* RLEN from init block */ /* Control and status register 7 (csr7) */ #define LE_C7_FASTSPNDE 0x8000 /* fast suspend enable */ #define LE_C7_RDMD 0x2000 /* receive demand */ #define LE_C7_RDXPOLL 0x1000 /* receive disable polling */ #define LE_C7_STINT 0x0800 /* software timer interrupt */ #define LE_C7_STINTE 0x0400 /* software timer interrupt enable */ #define LE_C7_MREINT 0x0200 /* PHY management read error intr */ #define LE_C7_MREINTE 0x0100 /* PHY management read error intr enable */ #define LE_C7_MAPINT 0x0080 /* PHY management auto-poll intr */ #define LE_C7_MAPINTE 0x0040 /* PHY management auto-poll intr enable */ #define LE_C7_MCCINT 0x0020 /* PHY management command complete interrupt */ #define LE_C7_MCCINTE 0x0010 /* PHY management command complete interrupt enable */ #define LE_C7_MCCIINT 0x0008 /* PHY management command complete internal interrupt */ #define LE_C7_MCCIINTE 0x0004 /* PHY management command complete internal interrupt enable */ #define LE_C7_MIIPDTINT 0x0002 /* PHY management detect transition interrupt */ #define LE_C7_MIIPDTINTE 0x0001 /* PHY management detect transition interrupt enable */ /* Control and status register 15 (csr15) */ #define LE_C15_PROM 0x8000 /* promiscuous mode */ #define LE_C15_DRCVBC 0x4000 /* disable Rx of broadcast */ #define LE_C15_DRCVPA 0x2000 /* disable Rx of physical address */ #define LE_C15_DLNKTST 0x1000 /* disable link status */ #define LE_C15_DAPC 0x0800 /* disable auto-polarity correction */ #define LE_C15_MENDECL 0x0400 /* MENDEC Loopback mode */ #define LE_C15_LRT 0x0200 /* low receive threshold (TMAU) */ #define LE_C15_TSEL 0x0200 /* transmit mode select (AUI) */ #define LE_C15_PORTSEL(x) ((x) << 7) /* port select */ #define LE_C15_INTL 0x0040 /* internal loopback */ #define LE_C15_DRTY 0x0020 /* disable retry */ #define LE_C15_FCOLL 0x0010 /* force collision */ #define LE_C15_DXMTFCS 0x0008 /* disable Tx FCS (ADD_FCS overrides) */ #define LE_C15_LOOP 0x0004 /* loopback enable */ #define LE_C15_DTX 0x0002 /* disable transmit */ #define LE_C15_DRX 0x0001 /* disable receiver */ #define LE_C80_RCVFW(x) ((x) << 12) #define LE_C80_XMTSP(x) ((x) << 10) #define LE_C80_XMTFW(x) ((x) << 8) /* * Bus Configuration Register addresses */ #define LE_BCR0 0x0000 /* Master Mode Read Active */ #define LE_BCR1 0x0001 /* Master Mode Write Active */ #define LE_BCR2 0x0002 /* Misc. Configuration */ #define LE_BCR4 0x0004 /* LED0 Status */ #define LE_BCR5 0x0005 /* LED1 Status */ #define LE_BCR6 0x0006 /* LED2 Status */ #define LE_BCR7 0x0007 /* LED3 Status */ #define LE_BCR9 0x0009 /* Full-duplex Control */ #define LE_BCR16 0x0010 /* I/O Base Address lower */ #define LE_BCR17 0x0011 /* I/O Base Address upper */ #define LE_BCR18 0x0012 /* Burst and Bus Control Register */ #define LE_BCR19 0x0013 /* EEPROM Control and Status */ #define LE_BCR20 0x0014 /* Software Style */ #define LE_BCR22 0x0016 /* PCI Latency Register */ #define LE_BCR23 0x0017 /* PCI Subsystem Vendor ID */ #define LE_BCR24 0x0018 /* PCI Subsystem ID */ #define LE_BCR25 0x0019 /* SRAM Size Register */ #define LE_BCR26 0x001a /* SRAM Boundary Register */ #define LE_BCR27 0x001b /* SRAM Interface Control Register */ #define LE_BCR28 0x001c /* Exp. Bus Port Addr lower */ #define LE_BCR29 0x001d /* Exp. Bus Port Addr upper */ #define LE_BCR30 0x001e /* Exp. Bus Data Port */ #define LE_BCR31 0x001f /* Software Timer Register */ #define LE_BCR32 0x0020 /* PHY Control and Status Register */ #define LE_BCR33 0x0021 /* PHY Address Register */ #define LE_BCR34 0x0022 /* PHY Management Data Register */ #define LE_BCR35 0x0023 /* PCI Vendor ID Register */ #define LE_BCR36 0x0024 /* PCI Power Management Cap. Alias */ #define LE_BCR37 0x0025 /* PCI DATA0 Alias */ #define LE_BCR38 0x0026 /* PCI DATA1 Alias */ #define LE_BCR39 0x0027 /* PCI DATA2 Alias */ #define LE_BCR40 0x0028 /* PCI DATA3 Alias */ #define LE_BCR41 0x0029 /* PCI DATA4 Alias */ #define LE_BCR42 0x002a /* PCI DATA5 Alias */ #define LE_BCR43 0x002b /* PCI DATA6 Alias */ #define LE_BCR44 0x002c /* PCI DATA7 Alias */ #define LE_BCR45 0x002d /* OnNow Pattern Matching 1 */ #define LE_BCR46 0x002e /* OnNow Pattern Matching 2 */ #define LE_BCR47 0x002f /* OnNow Pattern Matching 3 */ #define LE_BCR48 0x0030 /* LED4 Status */ #define LE_BCR49 0x0031 /* PHY Select */ /* bus configuration register 2 (bcr2) */ #define LE_B2_PHYSSELEN 0x2000 /* enable writes to BCR18[4:3] */ #define LE_B2_LEDPE 0x1000 /* LED program enable */ #define LE_B2_APROMWE 0x0100 /* Address PROM Write Enable */ #define LE_B2_INTLEVEL 0x0080 /* 1 == edge triggered */ #define LE_B2_DXCVRCTL 0x0020 /* DXCVR control */ #define LE_B2_DXCVRPOL 0x0010 /* DXCVR polarity */ #define LE_B2_EADISEL 0x0008 /* EADI select */ #define LE_B2_AWAKE 0x0004 /* power saving mode select */ #define LE_B2_ASEL 0x0002 /* auto-select PORTSEL */ #define LE_B2_XMAUSEL 0x0001 /* reserved location */ /* bus configuration register 18 (bcr18) */ #define LE_B18_ROMTMG 0xf000 /* expansion rom timing */ #define LE_B18_NOUFLO 0x0800 /* no underflow on transmit */ #define LE_B18_MEMCMD 0x0200 /* memory read multiple enable */ #define LE_B18_EXTREQ 0x0100 /* extended request */ #define LE_B18_DWIO 0x0080 /* double-word I/O */ #define LE_B18_BREADE 0x0040 /* burst read enable */ #define LE_B18_BWRITE 0x0020 /* burst write enable */ #define LE_B18_PHYSEL1 0x0010 /* PHYSEL 1 */ #define LE_B18_PHYSEL0 0x0008 /* PHYSEL 0 */ /* 00 ex ROM/Flash */ /* 01 EADI/MII snoop */ /* 10 reserved */ /* 11 reserved */ #define LE_B18_LINBC 0x0007 /* reserved locations */ /* bus configuration register 20 (bcr20) */ #define LE_B20_APERREN 0x0400 /* Advanced parity error handling */ #define LE_B20_CSRPCNET 0x0200 /* PCnet-style CSRs (0 = ILACC) */ #define LE_B20_SSIZE32 0x0100 /* Software Size 32-bit */ #define LE_B20_SSTYLE 0x0007 /* Software Style */ #define LE_B20_SSTYLE_LANCE 0 /* LANCE/PCnet-ISA (16-bit) */ #define LE_B20_SSTYPE_ILACC 1 /* ILACC (32-bit) */ #define LE_B20_SSTYLE_PCNETPCI2 2 /* PCnet-PCI (32-bit) */ #define LE_B20_SSTYLE_PCNETPCI3 3 /* PCnet-PCI II (32-bit) */ /* bus configuration register 32 (bcr32) */ #define LE_B32_ANTST 0x8000 /* reserved for manuf. tests */ #define LE_B32_MIIPD 0x4000 /* MII PHY Detect (manuf. tests) */ #define LE_B32_FMDC 0x3000 /* fast management data clock */ #define LE_B32_APEP 0x0800 /* auto-poll PHY */ #define LE_B32_APDW 0x0700 /* auto-poll dwell time */ #define LE_B32_DANAS 0x0080 /* disable autonegotiation */ #define LE_B32_XPHYRST 0x0040 /* PHY reset */ #define LE_B32_XPHYANE 0x0020 /* PHY autonegotiation enable */ #define LE_B32_XPHYFD 0x0010 /* PHY full-duplex */ #define LE_B32_XPHYSP 0x0008 /* PHY speed */ #define LE_B32_MIIILP 0x0002 /* MII internal loopback */ /// /* * Receive message descriptor */ struct lermd { uint32_t rmd0; uint32_t rmd1; uint32_t rmd2; int32_t rmd3; }; /* * Transmit message descriptor */ struct letmd { uint32_t tmd0; uint32_t tmd1; uint32_t tmd2; int32_t tmd3; }; /* * Initialization block */ struct leinit { uint32_t init_mode; /* +0x0000 */ uint32_t init_padr[2]; /* +0x0002 */ uint16_t init_ladrf[4]; /* +0x0008 */ uint32_t init_rdra; /* +0x0010 */ uint32_t init_tdra; /* +0x0014 */ int32_t pad; /* Pad to 8 ints. */ }; /* * Description of Rx FIFO watermarks for various revisions. */ static const char * const pcn_79c970_rcvfw[] = { "16 bytes", "64 bytes", "128 bytes", NULL, }; static const char * const pcn_79c971_rcvfw[] = { "16 bytes", "64 bytes", "112 bytes", NULL, }; /* * Description of Tx start points for various revisions. */ static const char * const pcn_79c970_xmtsp[] = { "8 bytes", "64 bytes", "128 bytes", "248 bytes", }; static const char * const pcn_79c971_xmtsp[] = { "20 bytes", "64 bytes", "128 bytes", "248 bytes", }; static const char * const pcn_79c971_xmtsp_sram[] = { "44 bytes", "64 bytes", "128 bytes", "store-and-forward", }; /* * Description of Tx FIFO watermarks for various revisions. */ static const char * const pcn_79c970_xmtfw[] = { "16 bytes", "64 bytes", "128 bytes", NULL, }; static const char * const pcn_79c971_xmtfw[] = { "16 bytes", "64 bytes", "108 bytes", NULL, }; /* * Transmit descriptor list size. This is arbitrary, but allocate * enough descriptors for 128 pending transmissions, and 4 segments * per packet. This MUST work out to a power of 2. * * NOTE: We can't have any more than 512 Tx descriptors, SO BE CAREFUL! * * So we play a little trick here. We give each packet up to 16 * DMA segments, but only allocate the max of 512 descriptors. The * transmit logic can deal with this, we just are hoping to sneak by. */ #define PCN_NTXSEGS 16 #define PCN_NTXSEGS_VMWARE 8 /* bug in VMware's emulation */ #define PCN_TXQUEUELEN 128 #define PCN_TXQUEUELEN_MASK (PCN_TXQUEUELEN - 1) #define PCN_NTXDESC 512 #define PCN_NTXDESC_MASK (PCN_NTXDESC - 1) #define PCN_NEXTTX(x) (((x) + 1) & PCN_NTXDESC_MASK) #define PCN_NEXTTXS(x) (((x) + 1) & PCN_TXQUEUELEN_MASK) /* Tx interrupt every N + 1 packets. */ #define PCN_TXINTR_MASK 7 /* * Receive descriptor list size. We have one Rx buffer per incoming * packet, so this logic is a little simpler. */ #define PCN_NRXDESC 128 #define PCN_NRXDESC_MASK (PCN_NRXDESC - 1) #define PCN_NEXTRX(x) (((x) + 1) & PCN_NRXDESC_MASK) /* * Control structures are DMA'd to the PCnet chip. We allocate them in * a single clump that maps to a single DMA segment to make several things * easier. */ struct pcn_control_data { /* The transmit descriptors. */ struct letmd pcd_txdescs[PCN_NTXDESC]; /* The receive descriptors. */ struct lermd pcd_rxdescs[PCN_NRXDESC]; /* The init block. */ struct leinit pcd_initblock; }; #define PCN_CDOFF(x) offsetof(struct pcn_control_data, x) #define PCN_CDTXOFF(x) PCN_CDOFF(pcd_txdescs[(x)]) #define PCN_CDRXOFF(x) PCN_CDOFF(pcd_rxdescs[(x)]) #define PCN_CDINITOFF PCN_CDOFF(pcd_initblock) /// #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define OFFSET_VENDOR_ID 0x00 #define OFFSET_DEVICE_ID 0x02 #define OFFSET_COMMAND 0x04 #define OFFSET_IO_BASE_ADDR 0x10 #define OFFSET_MM_IO_BASE_ADDR 0x14 /* Offsets from base I/O address. */ #define PCNET32_WIO_RDP 0x10 #define PCNET32_WIO_RAP 0x12 #define PCNET32_WIO_BDP 0x16 /* I/O Map In DWord I/O Mode (DWIO = 1) Offset No. of Bytes Register 00h - 0Fh 16 APROM 10h 4 RDP 14h 4 RAP (shared by RDP and BDP) 18h 4 Reset Register 1Ch 4 BDP */ #define PCNET32_DWIO_RDP 0x10 #define PCNET32_DWIO_RAP 0x14 #define PCNET32_DWIO_BDP 0x1C #define MAX_ADDR_LEN 32 #define TX_RING_SIZE 16 #define RX_RING_SIZE 16 typedef uint64_t dma_addr_t; /* * IP报文 */ #define IP_MAC_LEN 0x06 struct packet_header { unsigned char des_mac[IP_MAC_LEN]; unsigned char src_mac[IP_MAC_LEN]; unsigned char proto_type[2]; /* 报文协议类型,IP协议是0x0800 */ }; struct ip_header { unsigned char ip_version; /* 该字节高位是IP包版本,IP 4是0x04 低位是IP包报文头长度,一般是0x05 所以合起来是0x45 */ unsigned char svr_field; /* service field,一般使用0x00 */ uint16_t total_len; /* 数据包总长度 */ uint16_t id; /* 数据包ID */ uint16_t flags; /* 数据包flag */ unsigned char time_to_live; unsigned char protocol; /* 协议类型,UDP是0x11 */ uint16_t check_sum; /* 数据包校验和 */ unsigned char src_ip[4]; /* 源地址,222.1.9.1是 0xDE 0x01 0x09 0x01 */ unsigned char des_ip[4]; /* 目的地址 */ }; /* * 网络协议包 */ #define MAX_BUF_LEN 1486 struct ip_packet { struct packet_header p_hdr; struct ip_header ip_hdr; unsigned char buf[MAX_BUF_LEN]; /* 协议所允许的IP报文最大长度为 */ }; #define IP_PACKET_LEN (sizeof(struct ip_header) + MAX_BUF_LEN) #define MAX_PACKET_LEN (sizeof(struct packet_header) + sizeof(struct ip_header) + MAX_BUF_LEN) /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { unsigned int base; unsigned short buf_length; /* two`s complement of length */ unsigned short status; unsigned int msg_length; unsigned int reserved; }; struct pcnet32_tx_head { unsigned int base; unsigned short length; /* two`s complement of length */ unsigned short status; unsigned int misc; unsigned int reserved; }; /* csr1和csr2组成的32位指针指向一个init block的地址 */ /* The PCNET32 32-Bit initialization block, described in datasheet. */ struct pcnet32_init_block { unsigned short mode; unsigned short tlen_rlen; /* Receive ring length,B4-B7位有效,环的长度 */ /* Send ring length,B12-B15位有效,环的长度 */ unsigned char phys_addr[6]; /* PADR是指physical address register,保存于csr12-csr14 */ /* 每个csr的低16位保存16位地址,一共保存了48位地址(64位地址中仅有低48位有效 */ unsigned short reserved; unsigned int filter[2]; /* LADRF是指Logical Address Filter,保存于csr8-csr11 */ /* 每个csr的低16位保存16位地址,一共保存了64位地址 */ /* Receive and transmit ring base, along with extra bits. */ unsigned int rx_ring; unsigned int tx_ring; int32_t pad; /* Pad to 8 ints. */ }; //#define IFNAMSIZ 16 // //struct net_device { // /* // * This is the first field of the "visible" part of this structure // * (i.e. as seen by users in the "Space.c" file). It is the name // * the interface. // */ // char name[IFNAMSIZ]; // unsigned long port; /* device I/O address */ // /* Interface address info. */ // unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */ // // unsigned long base_addr; /* device I/O address */ // unsigned char dev_addr[6]; /* hw address, (before bcast // because most packets are // unicast) */ // unsigned char addr_len; /* hardware address length */ // unsigned int irq; /* device IRQ number */ //}; // //struct sk_buff { // /* These two members must be first. */ // struct sk_buff *next; // struct sk_buff *prev; // // unsigned char *head, *data; // struct net_device *dev; //}; // //struct mii_if_info { // unsigned int full_duplex :1; /* is full duplex? */ // int phy_id_mask; // int reg_num_mask; // // struct net_device *dev; // // int phy_id; // int advertising; // unsigned int force_media :1; /* is autoneg. disabled? */ // unsigned int supports_gmii :1; /* are GMII registers supported? */ // // int (*mdio_read)(struct net_device *dev, int phy_id, int location); // void (*mdio_write)(struct net_device *dev, int phy_id, int location, // int val); //}; // //struct list_head { // struct list_head *next, *prev; //}; // //struct napi_struct { // /* The poll_list must only be managed by the entity which // * changes the state of the NAPI_STATE_SCHED bit. This means // * whoever atomically sets that bit can add this napi_struct // * to the per-cpu poll_list, and whoever clears that bit // * can remove from the list right before clearing the bit. // */ // struct list_head poll_list; // // unsigned long state; // int weight; // int (*poll)(struct napi_struct *, int); // unsigned int gro_count; // // struct net_device *dev; // struct list_head dev_list; // struct sk_buff *gro_list; // struct sk_buff *skb; //}; // ///* // * 每个设备对应的私有变量 // */ //struct pcnet32_private { // const char *name; // struct net_device *dev; // struct pcnet32_init_block *init_block; // unsigned int rx_ring_size; /* current rx ring size */ // unsigned int tx_ring_size; /* current tx ring size */ // unsigned int rx_mod_mask; /* rx ring modular mask */ // unsigned int tx_mod_mask; /* tx ring modular mask */ // unsigned short rx_len_bits; // unsigned short tx_len_bits; // struct mii_if_info mii_if; // // /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ // struct pcnet32_rx_head *rx_ring; // struct pcnet32_tx_head *tx_ring; // dma_addr_t init_dma_addr;/* DMA address of beginning of the init block, // returned by pci_alloc_consistent */ // /* The saved address of a sent-in-place packet/buffer, for skfree(). */ // struct sk_buff **tx_skbuff; // struct sk_buff **rx_skbuff; // dma_addr_t *tx_dma_addr; // dma_addr_t *rx_dma_addr; // unsigned int cur_rx, cur_tx; /* The next free ring entry */ // dma_addr_t rx_ring_dma_addr; // dma_addr_t tx_ring_dma_addr; // unsigned int dirty_rx, /* ring entries to be freed. */ // dirty_tx; // // struct napi_struct napi; // char tx_full; // char phycount; /* number of phys found */ // int options; // uint32_t msg_enable; /* debug message level */ // // /* each bit indicates an available PHY */ // uint32_t phymask; // unsigned int shared_irq :1, /* shared irq possible */ // dxsuflo :1, /* disable transmit stop on uflo */ // mii :1; /* mii port available */ // struct net_device *next; // struct napi_struct napi; // unsigned short chip_version; /* which variant this is */ //}; /* * 测试数据 */ /* An additional parameter that may be passed in... */ //static int debug = 0xFFFFFFFF; //static int pcnet32_debug = 0; //static struct pcnet32_private lp_list[10]; #define tx_header_len 1 #define rx_header_len 1 #define PCNET32_LOG_TX_BUFFERS tx_header_len //4 #define PCNET32_LOG_RX_BUFFERS rx_header_len //5 // virtual address unsigned char * p_tx_buf; unsigned char * p_rx_buf; // physical address off_t tx_buf_dma_addr; off_t rx_buf_dma_addr; // virtual address struct pcnet32_tx_head* p_tx_ring; struct pcnet32_rx_head* p_rx_ring; // physical address off_t tx_ring_dma_addr; off_t rx_ring_dma_addr; unsigned long netAM79C97x_test(unsigned long device, unsigned long cmd); #endif /* TESTAM79C97X_H_ */ 实现: /* * TestAM79C97x.c * * Created on: 2010-2-4 * Author: Administrator */ /* * 名词解释 * CSR Control and Status Registers,AM79C972控制和状态寄存器 * BCR Bus Configuration Registers,驱动电路控制寄存器 * * RAP Register Address Port,CSR和BCR共用的寄存器端口 * RDP Register Data Port,存取CSR的寄存器端口 * BDP BCR Data Port,存取BCR的寄存器端口 * * APROM Address PROM * BIU bus interface unit */ #include "TestAM79C97x.h" /* * 16bit read/write */ uint16_t pcnet32_wio_read_csr(unsigned long port, int index) { out16(port + PCN_IO16_RAP, index); return in16(port + PCN_IO16_RDP); } //void pcnet32_wio_write_csr(unsigned long port, int index, uint16_t val) { // out16(port + PCNET32_WIO_RAP, index); // out16(port + PCNET32_WIO_RDP, val); //} // //uint16_t pcnet32_wio_read_bcr(unsigned long port, int index) { // out16(port + PCNET32_WIO_RAP, index); // return in16(port + PCNET32_WIO_BDP); //} // //void pcnet32_wio_write_bcr(unsigned long port, int index, uint16_t val) { // out16(port + PCNET32_WIO_RAP, index); // out16(port + PCNET32_WIO_BDP, val); //} // //uint16_t pcnet32_wio_read_rap(unsigned long port) { // return in16(port + PCNET32_WIO_RAP); //} // //void pcnet32_wio_write_rap(unsigned long port, uint16_t val) { // out16(port + PCNET32_WIO_RAP, val); //} // #define PCNET32_WIO_RESET 0x14 void pcnet32_wio_reset(unsigned long port) { in16(port + PCNET32_WIO_RESET); } // //int pcnet32_wio_check(unsigned long port) { // out16(port + PCNET32_WIO_RAP, 88); // return (in16(port + PCNET32_WIO_RAP) == 88); //} /* * 32bit read/write */ uint32_t pcnet32_dwio_read_csr(unsigned long port, int index) { out32(port + PCN_IO32_RAP, index); return in32(port + PCN_IO32_RDP); } void pcnet32_dwio_write_csr(unsigned long port, int index, uint32_t val) { out32(port + PCN_IO32_RAP, index); out32(port + PCN_IO32_RDP, val); } uint32_t pcnet32_dwio_read_bcr(unsigned long port, int index) { out32(port + PCN_IO32_RAP, index); return in32(port + PCN_IO32_BDP); } void pcnet32_dwio_write_bcr(unsigned long port, int index, uint32_t val) { out32(port + PCN_IO32_RAP, index); out32(port + PCN_IO32_BDP, val); } //uint16_t pcnet32_dwio_read_rap(unsigned long port) { // return (in32(port + PCNET32_DWIO_RAP) & 0xffff); //} // //void pcnet32_dwio_write_rap(unsigned long port, uint16_t val) { // out32(port + PCNET32_DWIO_RAP, val); //} // #define PCNET32_DWIO_RESET 0x18 void pcnet32_dwio_reset(unsigned long port) { in32(port + PCNET32_DWIO_RESET); } // //int pcnet32_dwio_check(unsigned long port) { // out32(port + PCNET32_DWIO_RAP, 88); // return ((in32(port + PCNET32_DWIO_RAP) & 0xffff) == 88); //} static void pcn_reset(unsigned long port) { /* Stop the chip. */ pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); /* * Issue a reset by reading from the RESET register. * Note that we don't know if the chip is operating in * 16-bit or 32-bit mode at this point, so we attempt * to reset the chip both ways. If one fails, the other * will succeed. */ pcnet32_wio_reset(port); pcnet32_dwio_reset(port); /* Wait a little while for the chip to get its brains in order. */ delay(100); /* Select 32-bit (DWIO) mode */ out32(port + PCN_IO32_RDP, 0); /* switch pcnet32 to 32bit mode */ pcnet32_dwio_write_bcr(port, LE_BCR20, LE_B20_SSTYLE_PCNETPCI2); return; } /* * get MAC address */ unsigned long pcnet32_get_mac(unsigned long port, unsigned char* p_mac) { int res = DEVICE_ERROR; uint32_t u32_mac; /* * 读取MAC地址并判断 * CSR12-CSR14 */ // u32_mac = pcnet32_dwio_read_csr(port, PCN_CSR_PAR0); // *p_mac = u32_mac & 0xFF; // p_mac++; // *p_mac = (u32_mac & 0xFF00) >> 8; // // u32_mac = pcnet32_dwio_read_csr(port, PCN_CSR_PAR1); // p_mac++; // *p_mac = u32_mac & 0xFF; // p_mac++; // *p_mac = (u32_mac & 0xFF00) >> 8; // // u32_mac = pcnet32_dwio_read_csr(port, PCN_CSR_PAR2); // p_mac++; // *p_mac = u32_mac & 0xFF; // p_mac++; // *p_mac = (u32_mac & 0xFF00) >> 8; *p_mac = in8(port); p_mac++; port++; *p_mac = in8(port); p_mac++; port++; *p_mac = in8(port); p_mac++; port++; *p_mac = in8(port); p_mac++; port++; *p_mac = in8(port); p_mac++; port++; *p_mac = in8(port); res = DEVICE_NO_ERROR; return res; } /* * create buffer */ void pcnet32_init_buf(unsigned char * buf, int len) { int i; for (i = 0; i < len; i++) { *(buf + i) = i; } return; } /* * calculate check sum */ uint16_t pcnet32_cal_checksum(unsigned short * buf, int len) { uint16_t check_sum = 0; while (len > 1) { check_sum += *buf++; len -= sizeof(unsigned short); } if (len) { check_sum += *(unsigned short *) buf; } check_sum = (check_sum >> 16) + (check_sum & 0xffff); check_sum += (check_sum >> 16); return ~check_sum; } /* * create test buffer */ void pcnet32_init_ip_packet(struct ip_packet * packet, int datalen) { pcnet32_init_buf(packet->buf, datalen); packet->ip_hdr.ip_version = 0x45; packet->ip_hdr.svr_field = 0x00; packet->ip_hdr.total_len = datalen + sizeof(struct ip_header); packet->ip_hdr.id = 0x0000; packet->ip_hdr.flags = 0x4000; packet->ip_hdr.time_to_live = 0x40; packet->ip_hdr.protocol = 0x11; packet->ip_hdr.check_sum = pcnet32_cal_checksum( (unsigned short *) (packet->buf), datalen); /* 192.168.0.111 */ packet->ip_hdr.src_ip[0] = 0xC0; packet->ip_hdr.src_ip[1] = 0xA8; packet->ip_hdr.src_ip[2] = 0x00; packet->ip_hdr.src_ip[3] = 0x6F; /* 192.168.0.123 */ packet->ip_hdr.des_ip[0] = 0xC0; packet->ip_hdr.des_ip[1] = 0xA8; packet->ip_hdr.des_ip[2] = 0x00; packet->ip_hdr.des_ip[3] = 0x7B; return; } void pcnet32_init_test_packet(struct ip_packet *packet, unsigned char *des_mac, unsigned char *src_mac, int datalen) { unsigned char * buf = (unsigned char *) packet; int i; // /* // * 清空包内容 // */ // memset(packet, 0, MAX_PACKET_LEN * tx_header_len); // // for (i = 0; i < IP_MAC_LEN; i++) // packet->p_hdr.des_mac[i] = *(des_mac + i); // // for (i = 0; i < IP_MAC_LEN; i++) // packet->p_hdr.src_mac[i] = *(src_mac + i); // // packet->p_hdr.proto_type[0] = 0x08; // packet->p_hdr.proto_type[1] = 0x00; // // /* // * 填充IP数据包 // */ // pcnet32_init_ip_packet(packet, datalen); buf[0] = 0xff; buf[1] = 0xff; buf[2] = 0xff; buf[3] = 0xff; buf[4] = 0xff; buf[5] = 0xff; buf[6] = src_mac[0]; buf[7] = src_mac[1]; buf[8] = src_mac[2]; buf[9] = src_mac[3]; buf[10] = src_mac[4]; buf[11] = src_mac[5]; buf[12] = 0x00; buf[13] = 64; // buf[14] = 0x00;//64; for (i = 0; i < 64; i++) buf[i + 14] = 00; return; } /* * 初始化发送和接收缓冲区环内容 */ unsigned long pcnet32_init_initblk(unsigned long port, struct pcnet32_init_block * p_init_block) { int i; unsigned short tx_len_bits; unsigned short rx_len_bits; unsigned char phys_addr[IP_MAC_LEN]; p_tx_ring = mmap(0, sizeof(struct pcnet32_tx_head) * tx_header_len, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_tx_ring, NOFD, sizeof(struct pcnet32_tx_head) * tx_header_len, &tx_ring_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_tx_ring, 0, sizeof(struct pcnet32_tx_head) * tx_header_len); p_rx_ring = mmap(0, sizeof(struct pcnet32_rx_head) * rx_header_len, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_rx_ring, NOFD, sizeof(struct pcnet32_rx_head) * rx_header_len, &rx_ring_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_rx_ring, 0, sizeof(struct pcnet32_rx_head) * rx_header_len); /* * initial tx ring */ p_tx_buf = mmap(0, MAX_PACKET_LEN * tx_header_len, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_tx_buf, NOFD, MAX_PACKET_LEN * tx_header_len, &tx_buf_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_tx_buf, 0, MAX_PACKET_LEN * tx_header_len); for (i = 0; i < tx_header_len; i++) { /* Initialize pcnet32_tx_head */ (p_tx_ring + i)->base = tx_buf_dma_addr + MAX_PACKET_LEN * i; (p_tx_ring + i)->length = 0 - (64 + 14);//MAX_PACKET_LEN; (p_tx_ring + i)->misc = 0; (p_tx_ring + i)->status = 0x8300; /* CPU owns buffer */ (p_tx_ring + i)->reserved = 0; } // /* Initialize CSR20. */ // pcnet32_dwio_write_csr(port, LE_CSR20, tx_buf_dma_addr & 0xffff); // /* Initialize CSR21. */ // pcnet32_dwio_write_csr(port, LE_CSR21, (tx_buf_dma_addr >> 16) & 0xffff); /* * initial rx ring */ p_rx_buf = mmap(0, MAX_PACKET_LEN * rx_header_len, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_rx_buf, NOFD, MAX_PACKET_LEN * rx_header_len, &rx_buf_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_rx_buf, 0, MAX_PACKET_LEN * rx_header_len); for (i = 0; i < rx_header_len; i++) { /* Initialize pcnet32_rx_head */ (p_rx_ring + i)->base = rx_buf_dma_addr + MAX_PACKET_LEN * i; (p_rx_ring + i)->buf_length = 2 - 1544;//MAX_PACKET_LEN; (p_rx_ring + i)->msg_length = 0; (p_rx_ring + i)->status = 0x8000; (p_rx_ring + i)->reserved = 0; } // /* Initialize CSR18. */ // pcnet32_dwio_write_csr(port, LE_CSR18, rx_buf_dma_addr & 0xffff); // /* Initialize CSR19. */ // pcnet32_dwio_write_csr(port, LE_CSR19, (rx_buf_dma_addr >> 16) & 0xffff); p_init_block->mode = (0x0003 << 7) | 0x8000; /* Disable Rx and Tx. */ tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); p_init_block->tlen_rlen = tx_len_bits | rx_len_bits; if (pcnet32_get_mac(port, phys_addr) != DEVICE_NO_ERROR) return DEVICE_ERROR; for (i = 0; i < IP_MAC_LEN; i++) p_init_block->phys_addr[i] = phys_addr[i]; p_init_block->filter[0] = 0x00000000; p_init_block->filter[1] = 0x00000000; p_init_block->tx_ring = tx_ring_dma_addr; p_init_block->rx_ring = rx_ring_dma_addr; return DEVICE_NO_ERROR; } unsigned long pcnet32_uninit_initblk(unsigned long port, struct pcnet32_init_block * init_block) { // free tx_ring munmap(p_tx_ring, sizeof(struct pcnet32_tx_head) * tx_header_len); munmap(p_tx_buf, MAX_PACKET_LEN * tx_header_len); // free rx_ring munmap(p_rx_ring, sizeof(struct pcnet32_rx_head) * rx_header_len); munmap(p_rx_buf, MAX_PACKET_LEN * rx_header_len); return DEVICE_NO_ERROR; } //void pcnet32_init_device(unsigned long port, struct net_device * dev) { // dev->addr_len = 6; // dev->port = port; //} // //static uint32_t netif_msg_init(int debug_value, int default_msg_enable_bits) { // /* use default */ // if (debug_value < 0 || debug_value >= (sizeof(uint32_t) * 8)) // return default_msg_enable_bits; // if (debug_value == 0) /* no output */ // return 0; // /* set low N bits */ // return (1 << debug_value) - 1; //} // //void * pci_alloc_consistent(int size, dma_addr_t *dma_addrp) { // void *cpu_addr; // // cpu_addr = (void *) malloc(size); // if (!cpu_addr) { // printf("pci_alloc_consistent: " // "get_free_pages failed from %p/n", __builtin_return_address(0)); // return NULL; // } // memset(cpu_addr, 0, size); // // *dma_addrp = (unsigned int) mmap(cpu_addr, size, PROT_READ | PROT_WRITE, // MAP_PHYS, NOFD, 0); // if (*dma_addrp == 0) { // return NULL; // } // // return cpu_addr; //} // //void * kcalloc(int len, int size) { // dma_addr_t * dma_addrp = NULL; // void *p = (void *) malloc(size * len); // if (!p) { // printf("alloc memory failed./n"); // return NULL; // } // memset(p, 0, size * len); // // *dma_addrp = (unsigned int) mmap(p, size, PROT_READ | PROT_WRITE, // MAP_PHYS, NOFD, 0); // if (*dma_addrp == 0) { // return NULL; // } // // return dma_addrp; //} // ///* if any allocation fails, caller must also call pcnet32_free_ring */ //static int pcnet32_alloc_ring(struct pcnet32_private *lp, struct net_device *dev) //{ // lp->tx_ring = pci_alloc_consistent(sizeof(struct pcnet32_tx_head) * // lp->tx_ring_size, // &lp->tx_ring_dma_addr); // if (lp->tx_ring == NULL) { // if (netif_msg_drv(lp)) // printf("%s: Consistent memory allocation failed./n", // dev->name); // return -ENOMEM; // } // // lp->rx_ring = pci_alloc_consistent(sizeof(struct pcnet32_rx_head) * // lp->rx_ring_size, // &lp->rx_ring_dma_addr); // if (lp->rx_ring == NULL) { // if (netif_msg_drv(lp)) // printf("%s: Consistent memory allocation failed./n", // dev->name); // return -ENOMEM; // } // // lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t)); // if (!lp->tx_dma_addr) { // if (netif_msg_drv(lp)) // printf("%s: Memory allocation failed./n", dev->name); // return -ENOMEM; // } // // lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t)); // if (!lp->rx_dma_addr) { // if (netif_msg_drv(lp)) // printf("%s: Memory allocation failed./n", dev->name); // return -ENOMEM; // } // // lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *)); // if (!lp->tx_skbuff) { // if (netif_msg_drv(lp)) // printf("%s: Memory allocation failed./n", dev->name); // return -ENOMEM; // } // // lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *)); // if (!lp->rx_skbuff) { // if (netif_msg_drv(lp)) // printf("%s: Memory allocation failed./n", dev->name); // return -ENOMEM; // } // // return 0; //} // ///** // * netdev_priv - access network device private data // * @dev: network device // * // * Get network device private data // */ //static inline void *netdev_priv(const struct net_device *dev) { // return (char *) dev + sizeof(struct net_device); //} // ///* This routine assumes that the lp->lock is held */ //static int mdio_read(struct net_device *dev, int phy_id, int reg_num) { // struct pcnet32_private *lp = netdev_priv(dev); // unsigned long ioaddr = dev->port; // uint16_t val_out; // // if (!lp->mii) // return 0; // // pcnet32_wio_write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); // val_out = pcnet32_wio_read_bcr(ioaddr, 34); // // return val_out; //} // ///* This routine assumes that the lp->lock is held */ //static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) { // struct pcnet32_private *lp = netdev_priv(dev); // unsigned long ioaddr = dev->port; // // if (!lp->mii) // return; // // pcnet32_wio_write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); // pcnet32_wio_write_bcr(ioaddr, 34, val); //} // //unsigned long pcnet32_probe(unsigned long port) { // char* chipname = ""; // int fdx, mii, fset, dxsuflo; // int i, media; // int chip_version; // // unsigned char dev_addr[IP_MAC_LEN]; // unsigned char promaddr[IP_MAC_LEN]; // int res = DEVICE_ERROR; // uint16_t tmp; // // // /* // // * 此段测试16/32位操作 // // */ // // pcnet32_wio_reset(port); // // tmp = pcnet32_wio_read_csr(port, CSR0); // // if ((tmp == 4) && (pcnet32_wio_check(port))) { // // printf("16Bit Operation;/n"); // // } else { // // return res; // // } // // // // chip_version = pcnet32_wio_read_csr(port, 88) | (pcnet32_wio_read_csr(port, // // 89) << 16); // // printf("PCnet chip version is %#x./n", chip_version); // // if ((chip_version & 0xfff) != 0x003) { // // return res; // // } // // /* initialize variables */ // // fdx = mii = fset = dxsuflo = 0; // // chip_version = (chip_version >> 12) & 0xffff; // // switch (chip_version) { // // case 0x2420: // // chipname = "PCnet/PCI 79C970"; /* PCI */ // // break; // // case 0x2430: // if (shared) // chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ // else // chipname = "PCnet/32 79C965"; /* 486/VL bus */ // // break; // // case 0x2621: // // chipname = "PCnet/PCI II 79C970A"; /* PCI */ // // fdx = 1; // // break; // // case 0x2623: // // chipname = "PCnet/FAST 79C971"; /* PCI */ // // fdx = 1; // // mii = 1; // // fset = 1; // // break; // // case 0x2624: // // chipname = "PCnet/FAST+ 79C972"; /* PCI */ // // fdx = 1; // // mii = 1; // // fset = 1; // // break; // // case 0x2625: // // chipname = "PCnet/FAST III 79C973"; /* PCI */ // // fdx = 1; // // mii = 1; // // break; // // case 0x2626: // chipname = "PCnet/Home 79C978"; /* PCI */ // fdx = 1; // /* // * This is based on specs published at www.amd.com. This section // * assumes that a card with a 79C978 wants to go into standard // * ethernet mode. The 79C978 can also go into 1Mb HomePNA mode, // * and the module option homepna=1 can select this instead. // */ // media = a->read_bcr(ioaddr, 49); // media &= ~3; /* default to 10Mb ethernet */ // if (cards_found < MAX_UNITS && homepna[cards_found]) // media |= 1; /* switch to home wiring mode */ // if (pcnet32_debug & NETIF_MSG_PROBE) // printk(KERN_DEBUG PFX "media set to %sMbit mode./n", // (media & 1) ? "1" : "10"); // a->write_bcr(ioaddr, 49, media); // // break; // // case 0x2627: // // chipname = "PCnet/FAST III 79C975"; /* PCI */ // // fdx = 1; // // mii = 1; // // break; // // case 0x2628: // // chipname = "PCnet/PRO 79C976"; // // fdx = 1; // // mii = 1; // // break; // // default: // // printf("PCnet version %#x, no PCnet32 chip./n", // // chip_version); // // return res; // // } // // // // /* // // * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit // // * starting until the packet is loaded. Strike one for reliability, lose // // * one for latency - although on PCI this isnt a big loss. Older chips // // * have FIFO's smaller than a packet, so you can't do this. // // * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn. // // */ // // // // if (fset) { // // pcnet32_wio_write_bcr(port, 18, (pcnet32_wio_read_bcr(port, 18) // // | 0x0860)); // // pcnet32_wio_write_csr(port, 80, (pcnet32_wio_read_csr(port, 80) // // & 0x0C00) | 0x0c00); // // dxsuflo = 1; // // } // // // // /* In most chips, after a chip reset, the ethernet address is read from the // // * station address PROM at the base address and programmed into the // // * "Physical Address Registers" CSR12-14. // // * As a precautionary measure, we read the PROM values and complain if // // * they disagree with the CSRs. If they miscompare, and the PROM addr // // * is valid, then the PROM addr is used. // // */ // // for (i = 0; i < 3; i++) { // // unsigned int val; // // val = pcnet32_wio_read_csr(port, i + 12) & 0x0ffff; // // /* There may be endianness issues here. */ // // dev_addr[2 * i] = val & 0x0ff; // // dev_addr[2 * i + 1] = (val >> 8) & 0x0ff; // // } // // // // /* read PROM address and compare with CSR address */ // // for (i = 0; i < 6; i++) // // promaddr[i] = in8(port + i); // // // // if (memcmp(promaddr, dev_addr, 6)) { // // printf(" warning: CSR address invalid,/n"); // // memcpy(dev_addr, promaddr, 6); // // } // // // // printf(" %pM", dev_addr); // // /* Version 0x2623 and 0x2624 */ // // if (((chip_version + 1) & 0xfffe) == 0x2624) { // // i = pcnet32_wio_read_csr(port, 80) & 0x0C00; /* Check tx_start_pt */ // // printf(" tx_start_pt(0x%04x):", i); // // switch (i >> 10) { // // case 0: // // printf(" 20 bytes,"); // // break; // // case 1: // // printf(" 64 bytes,"); // // break; // // case 2: // // printf(" 128 bytes,"); // // break; // // case 3: // // printf("~220 bytes,"); // // break; // // } // // i = pcnet32_wio_read_bcr(port, 18); /* Check Burst/Bus control */ // // printf(" BCR18(%x):", i & 0xffff); // // if (i & (1 << 5)) // // printf("BurstWrEn "); // // if (i & (1 << 6)) // // printf("BurstRdEn "); // // if (i & (1 << 7)) // // printf("DWordIO "); // // if (i & (1 << 11)) // // printf("NoUFlow "); // // i = pcnet32_wio_read_bcr(port, 25); // // printf(" SRAMSIZE=0x%04x,", i << 8); // // i = pcnet32_wio_read_bcr(port, 26); // // printf(" SRAM_BND=0x%04x,", i << 8); // // i = pcnet32_wio_read_bcr(port, 27); // // if (i & (1 << 14)) // // printf("LowLatRx"); // // printf("/n"); // // } // // // // /* // // * 初始化init block // // */ // // // lp->name = chipname; // lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ // lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ // lp->tx_mod_mask = lp->tx_ring_size - 1; // lp->rx_mod_mask = lp->rx_ring_size - 1; // lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); // lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); // // lp->mii_if.full_duplex = fdx; // lp->mii_if.phy_id_mask = 0x1f; // lp->mii_if.reg_num_mask = 0x1f; // lp->mii_if.dev = lp->dev; // lp->mii_if.mdio_read = mdio_read; // lp->mii_if.mdio_write = mdio_write; // // lp->dxsuflo = dxsuflo; // lp->mii = mii; // lp->chip_version = chip_version; // lp->msg_enable = pcnet32_debug; // lp->options = options_mapping[options[idx]]; // // /* napi.weight is used in both the napi and non-napi cases */ // lp->napi.weight = lp->rx_ring_size / 2; // // // netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2); // // if (fdx && !(lp->options & PCNET32_PORT_ASEL)) // lp->options |= PCNET32_PORT_FD; // // /* prior to register_netdev, dev->name is not yet correct */ // if (pcnet32_alloc_ring(lp, lp->dev)) { // ret = -ENOMEM; // goto err_release_region; // } // // /* detect special T1/E1 WAN card by checking for MAC address */ // if (lp->dev->dev_addr[0] == 0x00 && lp->dev->dev_addr[1] == 0xe0 // && lp->dev->dev_addr[2] == 0x75) // lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; // // lp->init_block->mode = 0x0003; /* Disable Rx and Tx. */ // lp->init_block->tlen_rlen = lp->tx_len_bits | lp->rx_len_bits; // for (i = 0; i < 6; i++) // lp->init_block->phys_addr[i] = lp->dev->dev_addr[i]; // lp->init_block->filter[0] = 0x00000000; // lp->init_block->filter[1] = 0x00000000; // lp->init_block->rx_ring = lp->rx_ring_dma_addr; // lp->init_block->tx_ring = lp->tx_ring_dma_addr; // // /* switch pcnet32 to 32bit mode */ // pcnet32_wio_write_bcr(port, 20, 2); // // pcnet32_wio_write_csr(port, 1, (lp->init_dma_addr & 0xffff)); // pcnet32_wio_write_csr(port, 2, (lp->init_dma_addr >> 16)); // // if (lp->dev) { /* use the IRQ provided by PCI */ // // lp->dev->irq = pdev->irq; // if (pcnet32_debug & NETIF_MSG_PROBE) // printf(" assigned IRQ %d./n", lp->dev->irq); // } else { // // unsigned long irq_mask = probe_irq_on(); // // /* // * To auto-IRQ we enable the initialization-done and DMA error // * interrupts. For ISA boards we get a DMA error, but VLB and PCI // * boards will work. // */ // /* Trigger an initialization just for the interrupt. */ // pcnet32_wio_write_csr(port, CSR0, CSR0_INTEN | CSR0_INIT); // // mdelay(1); // // // lp->dev->irq = probe_irq_off(irq_mask); // if (!lp->dev->irq) { // if (pcnet32_debug & NETIF_MSG_PROBE) // printf(", failed to detect IRQ line./n"); // ret = -ENODEV; // // goto err_free_ring; // } // if (pcnet32_debug & NETIF_MSG_PROBE) // printf(", probed IRQ %d./n", lp->dev->irq); // } // // /* Set the mii phy_id so that we can query the link state */ // if (lp->mii) { // /* lp->phycount and lp->phymask are set to 0 by memset above */ // // lp->mii_if.phy_id = ((pcnet32_wio_read_bcr(port, 33)) >> 5) & 0x1f; // /* scan for PHYs */ // for (i = 0; i < PCNET32_MAX_PHYS; i++) { // unsigned short id1, id2; // // id1 = mdio_read(lp->dev, i, MII_PHYSID1); // if (id1 == 0xffff) // continue; // id2 = mdio_read(lp->dev, i, MII_PHYSID2); // if (id2 == 0xffff) // continue; // if (i == 31 && ((chip_version + 1) & 0xfffe) == 0x2624) // continue; /* 79C971 & 79C972 have phantom phy at id 31 */ // lp->phycount++; // lp->phymask |= (1 << i); // lp->mii_if.phy_id = i; // if (pcnet32_debug & NETIF_MSG_PROBE) // printf("Found PHY %04x:%04x at address %d./n", id1, id2, i); // } // pcnet32_wio_write_bcr(port, 33, (lp->mii_if.phy_id) << 5); // if (lp->phycount > 1) { // lp->options |= PCNET32_PORT_MII; // } // } // // /* The PCNET32-specific entries in the device structure. */ // // lp->dev->netdev_ops = &pcnet32_netdev_ops; // // lp->dev->ethtool_ops = &pcnet32_ethtool_ops; // // if (lp->dev) { // // pci_set_drvdata(pdev, lp->dev); // ; // } else { // // lp->next = pcnet32_dev; // // pcnet32_dev = lp->dev; // } // // if (pcnet32_debug & NETIF_MSG_PROBE) // printf("%s: registered as %s/n", lp->dev->name, lp->name); // // /* enable LED writes */ // pcnet32_wio_write_bcr(port, 2, pcnet32_wio_read_bcr(port, 2) | 0x1000); // // err_release_region: ; // return DEVICE_NO_ERROR; //} //unsigned long pcnet32_restart(unsigned long port, unsigned int csr0_bits) { // // int i; // // // /* wait for stop */ // // for (i = 0; i < 100; i++) // // if (pcnet32_dwio_read_csr(base_addr, CSR0) & CSR0_STOP) // // break; // // // // if (i >= 100) // // printf("pcnet32_restart timed out waiting for stop./n"); // // // // /* ReInit Ring */ // // pcnet32_dwio_write_csr(ioaddr, CSR0, CSR0_INIT); // // i = 0; // // while (i++ < 1000) // // if (pcnet32_dwio_read_csr(ioaddr, CSR0) & CSR0_IDON) // // break; // // // // pcnet32_dwio_write_csr(ioaddr, CSR0, csr0_bits); // return 0; //} /* * 分四部分测试代码,分别是: * I/O测试 * loopback模式测试 * 自测试 * 外部连接测试 */ unsigned long netAM79C97x_io_test(unsigned long port) { int res = DEVICE_ERROR; unsigned char mac[IP_MAC_LEN]; res = pcnet32_get_mac(port, mac); if ((mac[0] == 0x00) && (mac[1] == 0x20) && (mac[2] == 0xCE) && (mac[3] == 0xC4) && (mac[4] == 0x88) && (mac[5] == 0x1C)) res = DEVICE_NO_ERROR; return res; } unsigned long netAM79C97x_loop_test(unsigned long port) { int res = DEVICE_ERROR; int datalen = 64; unsigned char src_mac[IP_MAC_LEN]; unsigned char des_mac[IP_MAC_LEN]; struct pcnet32_init_block *p_init_block; off_t init_dma_addr; int i; pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_INIT); i = 0; while (i++ < 1000) if (pcnet32_dwio_read_csr(port, LE_CSR0) & LE_C0_IDON) break; pcnet32_dwio_write_csr(port, LE_CSR0, 0x0000); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); /* * initialize init block */ p_init_block = mmap(0, sizeof(struct pcnet32_init_block), PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_init_block, NOFD, sizeof(struct pcnet32_init_block), &init_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_init_block, 0, sizeof(struct pcnet32_init_block)); if (pcnet32_init_initblk(port, p_init_block) == DEVICE_ERROR) return DEVICE_ERROR; /* * test tx code */ pcnet32_get_mac(port, src_mac); for (i = 0; i < 6; i++) des_mac[i] = 0xFF; pcnet32_init_test_packet((struct ip_packet *) p_tx_buf, des_mac, src_mac, datalen); /* * Send the init block to the chip, and wait for it * to be processed. */ pcnet32_dwio_write_csr(port, LE_CSR1, init_dma_addr & 0xffff); pcnet32_dwio_write_csr(port, LE_CSR2, (init_dma_addr >> 16) & 0xffff); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_INIT); // LE_C0_STRT | delay(100); for (i = 0; i < 10000; i++) { if (pcnet32_dwio_read_csr(port, LE_CSR0) & LE_C0_IDON) break; delay(100); } if (i == 10000) { printf("timeout processing init block/n"); goto out; } /* set internal loopback in BCR32 */ pcnet32_dwio_write_bcr(port, LE_BCR32, pcnet32_dwio_read_bcr(port, 32) | 0x0002); /* set int loopback in CSR15 */ pcnet32_dwio_write_csr(port, LE_CSR15, (pcnet32_dwio_read_csr(port, LE_CSR15) & 0xfffc) | 0x0044); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STRT); /* 检查接收ring状态 */ int teststatus = 0x8000; /* Check status of descriptors */ int ticks = 0; while ((p_rx_ring->status & teststatus) && (ticks < 200)) { delay(10); ticks++; } if (ticks == 200) { printf("Desc failed to reset!/n"); goto out; } pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); out: /* * uninitialize init block */ pcnet32_uninit_initblk(port, p_init_block); munmap(p_init_block, sizeof(struct pcnet32_init_block)); res = DEVICE_NO_ERROR; return res; } unsigned long netAM79C97x_self_test(unsigned long port) { int res = DEVICE_ERROR; int datalen = 64; unsigned char src_mac[IP_MAC_LEN]; unsigned char des_mac[IP_MAC_LEN]; struct pcnet32_init_block *p_init_block; off_t init_dma_addr; int i; pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_INIT); i = 0; while (i++ < 1000) if (pcnet32_dwio_read_csr(port, LE_CSR0) & LE_C0_IDON) break; pcnet32_dwio_write_csr(port, LE_CSR0, 0x0000); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); /* * initialize init block */ p_init_block = mmap(0, sizeof(struct pcnet32_init_block), PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_init_block, NOFD, sizeof(struct pcnet32_init_block), &init_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_init_block, 0, sizeof(struct pcnet32_init_block)); if (pcnet32_init_initblk(port, p_init_block) == DEVICE_ERROR) return DEVICE_ERROR; /* * test tx code */ pcnet32_get_mac(port, src_mac); des_mac[0] == 0xFF; des_mac[1] == 0xFF; des_mac[2] == 0xFF; des_mac[3] == 0xFF; des_mac[4] == 0xFF; des_mac[5] == 0xFF; // des_mac[0] == 0x00; // des_mac[1] == 0x20; // des_mac[2] == 0xCE; // des_mac[3] == 0xC4; // des_mac[4] == 0x88; // des_mac[5] == 0x1C; pcnet32_init_test_packet((struct ip_packet *) p_tx_buf, des_mac, src_mac, datalen); /* * Send the init block to the chip, and wait for it * to be processed. */ pcnet32_dwio_write_csr(port, LE_CSR1, init_dma_addr & 0xffff); pcnet32_dwio_write_csr(port, LE_CSR2, (init_dma_addr >> 16) & 0xffff); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_INIT); // LE_C0_STRT | delay(100); for (i = 0; i < 10000; i++) { if (pcnet32_dwio_read_csr(port, LE_CSR0) & LE_C0_IDON) break; delay(100); } if (i == 10000) { printf("timeout processing init block/n"); goto out; } // /* set internal loopback in BCR32 */ // pcnet32_dwio_write_bcr(port, LE_BCR32, pcnet32_dwio_read_bcr(port, 32) // | 0x0002); // /* set int loopback in CSR15 */ // pcnet32_dwio_write_csr(port, LE_CSR15, (pcnet32_dwio_read_csr(port, // LE_CSR15) & 0xfffc) | 0x0044); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STRT); /* 检查接收ring状态 */ int teststatus = 0x8000; /* Check status of descriptors */ int ticks = 0; while ((p_rx_ring->status & teststatus) && (ticks < 200)) { delay(10); ticks++; } if (ticks == 200) { printf("Desc failed to reset!/n"); goto out; } pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); out: /* * uninitialize init block */ pcnet32_uninit_initblk(port, p_init_block); munmap(p_init_block, sizeof(struct pcnet32_init_block)); res = DEVICE_NO_ERROR; return res; } ///* the pcnet32 has been issued a stop or reset. Wait for the stop bit // * then flush the pending transmit operations, re-initialize the ring, // * and tell the chip to initialize. // */ //void pcnet32_restart(unsigned long port, unsigned int csr0_bits) //{ // int i; // // /* wait for stop */ // for (i = 0; i < 100; i++) // if (pcnet32_wio_read_csr(port, CSR0) & CSR0_STOP) // break; // // /* ReInit Ring */ // pcnet32_wio_write_csr(port, CSR0, CSR0_INIT); // i = 0; // while (i++ < 1000) // if (pcnet32_wio_read_csr(port, CSR0) & CSR0_IDON) // break; // // pcnet32_wio_write_csr(port, CSR0, csr0_bits); //} struct pcn_variant * pcn_lookup_variant(uint16_t chipid) { struct pcn_variant *pcv; for (pcv = pcn_v; pcv->pcv_chipid != 0; pcv++) { if (chipid == pcv->pcv_chipid) return (pcv); } /* * This covers unknown chips, which we simply treat like * a generic PCnet-FAST. */ return (pcv); } unsigned long pcn_init(unsigned long port) { int res = DEVICE_ERROR; uint32_t reg = 0; uint32_t chipid; struct pcn_variant* sc_variant; int sc_rcvfw; int sc_xmtsp; int sc_xmtfw; const char * const *sc_xmtsp_desc; /* Tx start point info */ const char * const *sc_xmtfw_desc; /* Tx FIFO watermark info */ const char * const *sc_rcvfw_desc; /* Rx FIFO watermark info */ if (netAM79C97x_io_test(port) == DEVICE_ERROR) return res; /* * Now that the device is mapped, attempt to figure out what * kind of chip we have. Note that IDL has all 32 bits of * the chip ID when we're in 32-bit mode. */ chipid = pcnet32_dwio_read_csr(port, LE_CSR88); printf("chipid %x/n", chipid); sc_variant = pcn_lookup_variant(CHIPID_PARTID(chipid)); switch (sc_variant->pcv_chipid) { case PARTID_Am79c970: case PARTID_Am79c970A: sc_rcvfw_desc = pcn_79c970_rcvfw; sc_xmtsp_desc = pcn_79c970_xmtsp; sc_xmtfw_desc = pcn_79c970_xmtfw; break; case PARTID_Am79c972: sc_rcvfw_desc = pcn_79c971_rcvfw; /* * Read BCR25 to determine how much SRAM is * on the board. If > 0, then we the chip * uses different Start Point thresholds. * * Note BCR25 and BCR26 are loaded from the * EEPROM on RST, and unaffected by S_RESET, * so we don't really have to worry about * them except for this. */ reg = pcnet32_dwio_read_bcr(port, LE_BCR25) & 0x00ff; if (reg != 0) sc_xmtsp_desc = pcn_79c971_xmtsp_sram; else sc_xmtsp_desc = pcn_79c971_xmtsp; sc_xmtfw_desc = pcn_79c971_xmtfw; break; default: return DEVICE_ERROR; } /* * Set up defaults -- see the tables above for what these * values mean. * * XXX How should we tune RCVFW and XMTFW? */ sc_rcvfw = 1; /* minimum for full-duplex */ sc_xmtsp = 1; sc_xmtfw = 0; /* * On the Am79c970, select SSTYLE 2, and SSTYLE 3 on everything * else. * * XXX It'd be really nice to use SSTYLE 2 on all the chips, * because the structure layout is compatible with ILACC, * but the burst mode is only available in SSTYLE 3, and * burst mode should provide some performance enhancement. */ pcnet32_dwio_write_bcr(port, LE_BCR20, LE_B20_SSIZE32 | LE_B20_SSTYLE_PCNETPCI3); /* * If we have MII, simply select MII in the MODE register, * and clear ASEL. Otherwise, let ASEL stand (for now), * and leave PORTSEL alone (it is ignored with ASEL is set). */ pcnet32_dwio_write_bcr(port, LE_BCR2, pcnet32_dwio_read_bcr(port, LE_BCR2) & ~LE_B2_ASEL); /* * Disable MII auto-negotiation. We handle that in * our own MII layer. */ pcnet32_dwio_write_bcr(port, LE_BCR32, pcnet32_dwio_read_bcr(port, LE_BCR32) & (~LE_B32_DANAS)); /* Initialize CSR3. */ pcnet32_dwio_write_csr(port, LE_CSR3, LE_C3_MISSM | LE_C3_IDONM); //| LE_C3_DXSUFLO);//????????????????????????????????????? /* Initialize CSR4. */ pcnet32_dwio_write_csr(port, LE_CSR4, LE_C4_DMAPLUS | LE_C4_APAD_XMT | LE_C4_MFCOM | LE_C4_RCVCCOM | LE_C4_TXSTRTM); /* Initialize CSR5. */ pcnet32_dwio_write_csr(port, LE_CSR5, LE_C5_LTINTEN | LE_C5_SINTE); /* * If we have an Am79c971 or greater, initialize CSR7. * * XXX Might be nice to use the MII auto-poll interrupt someday. */ pcnet32_dwio_write_csr(port, LE_CSR7, LE_C7_FASTSPNDE); /* * On the Am79c970A and greater, initialize BCR18 to * enable burst mode. * * Also enable the "no underflow" option on the Am79c971 and * higher, which prevents the chip from generating transmit * underflows, yet sill provides decent performance. Note if * chip is not connected to external SRAM, then we still have * to handle underflow errors (the NOUFLO bit is ignored in * that case). */ reg = pcnet32_dwio_read_bcr(port, LE_BCR18); reg |= LE_B18_BREADE | LE_B18_BWRITE | LE_B18_NOUFLO; pcnet32_dwio_write_bcr(port, LE_BCR18, reg); /* * Initialize CSR80 (FIFO thresholds for Tx and Rx). */ pcnet32_dwio_write_csr(port, LE_CSR80, LE_C80_RCVFW(sc_rcvfw) | LE_C80_XMTSP(sc_xmtsp) | LE_C80_XMTFW(sc_xmtfw)); return DEVICE_NO_ERROR; } unsigned long netAM79C97x_comm_test(unsigned long port) { int res = DEVICE_ERROR; int datalen = 64; unsigned char src_mac[IP_MAC_LEN]; unsigned char des_mac[IP_MAC_LEN]; struct pcnet32_init_block *p_init_block; off_t init_dma_addr; int i; pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_INIT); i = 0; while (i++ < 1000) if (pcnet32_dwio_read_csr(port, LE_CSR0) & LE_C0_IDON) break; pcnet32_dwio_write_csr(port, LE_CSR0, 0x0000); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); /* * initialize init block */ p_init_block = mmap(0, sizeof(struct pcnet32_init_block), PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS | MAP_ANON, NOFD, 0); if (mem_offset(p_init_block, NOFD, sizeof(struct pcnet32_init_block), &init_dma_addr, NULL) == -1) return DEVICE_ERROR; memset(p_init_block, 0, sizeof(struct pcnet32_init_block)); if (pcnet32_init_initblk(port, p_init_block) == DEVICE_ERROR) return DEVICE_ERROR; /* * test tx code */ pcnet32_get_mac(port, src_mac); for (i = 0; i < 6; i++) des_mac[i] = 0xFF; pcnet32_init_test_packet((struct ip_packet *) p_tx_buf, des_mac, src_mac, datalen); // pcn_init(port); //pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); /* * Send the init block to the chip, and wait for it * to be processed. */ pcnet32_dwio_write_csr(port, LE_CSR1, init_dma_addr & 0xffff); pcnet32_dwio_write_csr(port, LE_CSR2, (init_dma_addr >> 16) & 0xffff); pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_INIT); // LE_C0_STRT | delay(100); for (i = 0; i < 10000; i++) { if (pcnet32_dwio_read_csr(port, LE_CSR0) & LE_C0_IDON) break; delay(100); } if (i == 10000) { printf("timeout processing init block/n"); goto out; } // if (msync(p_tx_ring, sizeof(struct pcnet32_tx_head) * tx_header_len, // MS_SYNC) != 0) // goto out; // if (msync(p_tx_buf, MAX_PACKET_LEN * tx_header_len, MS_SYNC) != 0) // goto out; // if (msync(p_rx_ring, sizeof(struct pcnet32_rx_head) * rx_header_len, // MS_SYNC) != 0) // goto out; // if (msync(p_rx_buf, MAX_PACKET_LEN * rx_header_len, MS_SYNC) != 0) // goto out; // if (msync(p_init_block, sizeof(struct pcnet32_init_block), MS_SYNC) != 0) // goto out; /* * INIT INIT assertion enables the Am79C972 controller to begin the * initialization procedure which reads in the initialization block * from memory. */ // pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); // res = pcnet32_dwio_read_csr(port, LE_CSR1) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR2) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR16) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR17) & 0xFFFF; // 以上代码经检查init block地址已经正确写入 // pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); // /* set internal loopback in BCR32 */ // pcnet32_dwio_write_bcr(port, LE_BCR32, pcnet32_dwio_read_bcr(port, 32) // | 0x0002); // /* set int loopback in CSR15 */ // pcnet32_dwio_write_csr(port, LE_CSR15, (pcnet32_dwio_read_csr(port, // LE_CSR15) & 0xfffc) | 0x0044); // pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STRT); // pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); // res = pcnet32_dwio_read_csr(port, LE_CSR15) & 0xFFFF; // // "rx_buf_dma_addr" // // Current Receive Buffer Address // res = pcnet32_dwio_read_csr(port, LE_CSR18) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR19) & 0xFFFF; // // "tx_buf_dma_addr" // // Current Transmit Buffer Address // res = pcnet32_dwio_read_csr(port, LE_CSR20) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR21) & 0xFFFF; // // // "rx_ring_dma_addr" // // Base Address of Receive Ring // res = pcnet32_dwio_read_csr(port, LE_CSR24) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR25) & 0xFFFF; // // Current Receive Descriptor Address // res = pcnet32_dwio_read_csr(port, LE_CSR28) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR29) & 0xFFFF; // // // "tx_ring_dma_addr" // // Base Address of Transmit Ring // res = pcnet32_dwio_read_csr(port, LE_CSR30) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR31) & 0xFFFF; // // Current Transmit Descriptor Address // res = pcnet32_dwio_read_csr(port, LE_CSR34) & 0xFFFF; // res = pcnet32_dwio_read_csr(port, LE_CSR35) & 0xFFFF; pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STRT); // /* Kick the transmitter. */ // pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_TDMD); // // res = pcnet32_dwio_read_csr(port, LE_CSR0); /* 检查接收ring状态 */ int teststatus = 0x8000; /* Check status of descriptors */ int ticks = 0; while ((p_rx_ring->status & teststatus) && (ticks < 200)) { delay(10); ticks++; } if (ticks == 200) { printf("Desc failed to reset!/n"); goto out; } pcnet32_dwio_write_csr(port, LE_CSR0, LE_C0_STOP); out: /* * uninitialize init block */ pcnet32_uninit_initblk(port, p_init_block); munmap(p_init_block, sizeof(struct pcnet32_init_block)); // int i; // uint16_t status; // // // /* // * probe函数对设备进行初始化工作 // */ // pcnet32_probe(port); // // /* // * open函数申请资源,启动硬件和开启监控线程。 // */ // // res = pcnet32_get_mac(port, wio_or_dwio, src_mac); // for (i = 0; i < 6; i++) // des_mac[i] = 0xFF; des_mac[0] = 0x00; des_mac[1] = 0x11; des_mac[2] = 0x11; des_mac[3] = 0xA9; des_mac[4] = 0x9A; des_mac[5] = 0x39; // pcnet32_init_test_packet((struct ip_packet *) p_tx_buf, // des_mac, src_mac, datalen); // // /* Default status -- will not enable Successful-TxDone // * interrupt when that option is available to us. // */ // status = 0x8300; // // /* Fill in a Tx ring entry */ // p_tx_ring->status = status; // // /* Trigger an immediate send poll. */ // pcnet32_wio_write_csr(port, CSR0, CSR0_INTEN | CSR0_TXPOLL); // // // res = DEVICE_NO_ERROR; return res; } unsigned long netAM79C97x_test(unsigned long device, unsigned long cmd) { unsigned bus[MAX_PATH]; unsigned dev_func[MAX_PATH]; int dev[MAX_PATH]; int device_num = 0; int i; int res = DEVICE_ERROR; unsigned long offset; unsigned long count; unsigned char buf[MAX_PATH]; uint16_t vendor_id; uint16_t device_id; // unsigned long command; unsigned long address; unsigned long port; // struct pci_dev_info inf; // void* hdl; //uint16_t tmp = 0; /* * 连接PCI server */ int hnd_pci = pci_attach(0); if (hnd_pci == -1) { return res; } /* * 查找有几个同类型的设备 */ for (i = 0; i < MAX_PATH; i++) { dev[i] = pci_find_device(PCI_DEVICE_ID_AMD_LANCE, PCI_VENDOR_ID_AMD, i, &bus[i], &dev_func[i]); if (dev[i] == PCI_DEVICE_NOT_FOUND) break; if (dev[i] == PCI_SUCCESS) device_num++; } /* * 对设备枚举 */ for (i = 0; i < device_num; i++) { /* * 读取Vendor ID */ offset = OFFSET_VENDOR_ID; count = 1; if (pci_read_config16(bus[i], dev_func[i], offset, count, buf) != PCI_SUCCESS) break; memcpy(&vendor_id, buf, sizeof(vendor_id)); if (vendor_id != PCI_VENDOR_ID_AMD) break; /* * 读取Device ID */ offset = OFFSET_DEVICE_ID; count = 1; if (pci_read_config16(bus[i], dev_func[i], offset, count, buf) != PCI_SUCCESS) break; memcpy(&device_id, buf, sizeof(device_id)); if (device_id != PCI_DEVICE_ID_AMD_LANCE) break; /* * 读取i/o base address */ offset = OFFSET_IO_BASE_ADDR; count = 1; if (pci_read_config32(bus[i], dev_func[i], offset, count, (char *)&address) != PCI_SUCCESS) break; port = PCI_IO_ADDR(address); // /* Make sure bus mastering is enabled. */ // offset = OFFSET_COMMAND; // count = 1; // if (pci_read_config32(bus[i], dev_func[i], offset, count, (char *)&command) // != PCI_SUCCESS) // break; // command |= PCI_COMMAND_MASTER_ENABLE; // pci_write_config32(bus[i], dev_func[i], offset, count, (char *)&command); // /* power up chip */ // if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, // NULL)) && error != EOPNOTSUPP) { // aprint_error_dev(self, "cannot activate %d/n", error); // return; // } /* Initialize the pci_dev_info structure */ // memset(&inf, 0, sizeof(inf)); // inf.VendorId = PCI_VENDOR_ID_AMD; // inf.DeviceId = PCI_DEVICE_ID_AMD_LANCE; // hdl = pci_attach_device(NULL, PCI_INIT_ALL, i, &inf); // if (hdl == NULL) { // fprintf(stderr, "Unable to locate adapter/n"); // } else { pcn_reset(port); /* * 下面开始测试内容,主要测试I/O、回环、自测试、连接测试 */ switch (cmd) { case TEST_AM79C972_IO: res = netAM79C97x_io_test(port); break; case TEST_AM79C972_LOOP: res = netAM79C97x_loop_test(port); break; case TEST_AM79C972_SELF: res = netAM79C97x_self_test(port); break; case TEST_AM79C972_COMM: res = netAM79C97x_comm_test(port); break; default: res = netAM79C97x_io_test(port); } /* Do something to the adapter */ // pci_detach_device(hdl); // } } /* * 断开与PCI server的连接 */ pci_detach(hnd_pci); return res; }