w89c840.c File Reference

#include "etherboot.h"
#include "nic.h"
#include <gpxe/pci.h>
#include <gpxe/ethernet.h>

Go to the source code of this file.

Data Structures

struct  w840_rx_desc
struct  w840_tx_desc
struct  winbond_private

Defines

#define USE_IO_OPS
#define virt_to_le32desc(addr)   virt_to_bus(addr)
#define le32desc_to_virt(addr)   bus_to_virt(addr)
#define TX_RING_SIZE   2
#define RX_RING_SIZE   2
#define TX_FIFO_SIZE   (2048)
#define TX_BUG_FIFO_LIMIT   (TX_FIFO_SIZE-1514-16)
#define TX_TIMEOUT   (10*1000)
#define PKT_BUF_SZ   1536
#define W840_FLAGS   (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
#define readb   inb
#define readw   inw
#define readl   inl
#define writeb   outb
#define writew   outw
#define writel   outl
#define PRIV_ALIGN   15
#define PRIV_ALIGN_BYTES   32
#define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
#define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011
#define eeprom_delay(ee_addr)   readl(ee_addr)
#define mdio_delay(mdio_addr)   readl(mdio_addr)
#define MDIO_WRITE0   (MDIO_EnbOutput)
#define MDIO_WRITE1   (MDIO_DataOut | MDIO_EnbOutput)

Enumerations

enum  chip_capability_flags {
  HAS_MII_XCVR, HAS_CHIP_XCVR, CanHaveMII = 1, KendinPktDropBug = 2,
  CanHaveMII = 1, HasBrokenTx = 2
}
enum  w840_offsets {
  PCIBusCfg = 0x00, TxStartDemand = 0x04, RxStartDemand = 0x08, RxRingPtr = 0x0C,
  TxRingPtr = 0x10, IntrStatus = 0x14, NetworkConfig = 0x18, IntrEnable = 0x1C,
  RxMissed = 0x20, EECtrl = 0x24, MIICtrl = 0x24, BootRom = 0x28,
  GPTimer = 0x2C, CurRxDescAddr = 0x30, CurRxBufAddr = 0x34, MulticastFilter0 = 0x38,
  MulticastFilter1 = 0x3C, StationAddr = 0x40, CurTxDescAddr = 0x4C, CurTxBufAddr = 0x50
}
enum  intr_status_bits {
  RFCON = 0x00020000, RFCOFF = 0x00010000, LSCStatus = 0x00008000, ANCStatus = 0x00004000,
  FBE = 0x00002000, FBEMask = 0x00001800, ParityErr = 0x00000000, TargetErr = 0x00001000,
  MasterErr = 0x00000800, TUNF = 0x00000400, ROVF = 0x00000200, ETI = 0x00000100,
  ERI = 0x00000080, CNTOVF = 0x00000040, RBU = 0x00000020, TBU = 0x00000010,
  TI = 0x00000008, RI = 0x00000004, RxErr = 0x00000002, IntrSummary = 0x0001,
  IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008, IntrTxDone = 0x0004, IntrRxDone = 0x0010,
  IntrRxStart = 0x0020, IntrDrvRqst = 0x0040, StatsMax = 0x0080, LinkChange = 0x0100,
  IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400, IntrRxDone = 0x0001, IntrRxErr = 0x0004,
  IntrRxEmpty = 0x0020, IntrTxDone = 0x0002, IntrTxError = 0x0008, IntrTxUnderrun = 0x0210,
  IntrPCIErr = 0x0040, IntrStatsMax = 0x0080, IntrRxEarly = 0x0100, IntrRxOverflow = 0x0400,
  IntrRxDropped = 0x0800, IntrRxNoBuf = 0x1000, IntrTxAborted = 0x2000, IntrLinkChange = 0x4000,
  IntrRxWakeUp = 0x8000, IntrNormalSummary = 0x0003, IntrAbnormalSummary = 0xC260, IntrTxDescRace = 0x080000,
  IntrTxErrSummary = 0x082218, NormalIntr = 0x10000, AbnormalIntr = 0x8000, IntrPCIErr = 0x2000,
  TimerInt = 0x800, IntrRxDied = 0x100, RxNoBuf = 0x80, IntrRxDone = 0x40,
  TxFIFOUnderflow = 0x20, RxErrIntr = 0x10, TxIdle = 0x04, IntrTxStopped = 0x02,
  IntrTxDone = 0x01
}
enum  rx_mode_bits {
  RxModeMask = 0xe0, AcceptAllPhys = 0x80, AcceptBroadcast = 0x40, AcceptMulticast = 0x20,
  AcceptRunt = 0x08, ALP = 0x04, AcceptErr = 0x02, AcceptMyPhys = 0x00000000,
  RxEnable = 0x00000001, RxFlowCtrl = 0x00002000, TxEnable = 0x00040000, TxModeFDX = 0x00100000,
  TxThreshold = 0x00e00000, PS1000 = 0x00010000, PS10 = 0x00080000, FD = 0x00100000,
  AcceptErr = 0x20, AcceptRunt = 0x10, AcceptBroadcast = 0xC0000000, AcceptMulticast = 0x00200000,
  AcceptAllMulticast = 0x20000000, AcceptAllPhys = 0x10000000, AcceptMyPhys = 0x08000000, RxFilterEnable = 0x80000000,
  AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08, AcceptBroadcast = 0x04,
  AcceptMulticast = 0x02, AcceptMyPhys, AcceptErr = 0x80, AcceptRunt = 0x40,
  AcceptBroadcast = 0x20, AcceptMulticast = 0x10, AcceptAllPhys = 0x08, AcceptMyPhys = 0x02
}
enum  mii_reg_bits {
  MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput, MDIO_ShiftClk = 0x10000,
  MDIO_DataIn = 0x80000, MDIO_DataOut = 0x20000, MDIO_EnbOutput = 0x40000, MDIO_EnbIn = 0x00000
}
enum  desc_status_bits {
  DescOwn = 0x80000000, DescMore = 0x40000000, DescIntr = 0x20000000, DescNoCRC = 0x10000000,
  DescPktOK = 0x08000000, RxTooLong = 0x00400000, DescOwn = 0x8000, DescEndPacket = 0x4000,
  DescEndRing = 0x2000, LastFrag = 0x80000000, DescIntrOnTx = 0x8000, DescIntrOnDMADone = 0x80000000,
  DisableAlign = 0x00000001, DescOwnded = 0x80000000, RxDescFatalErr = 0x8000, RxWholePkt = 0x0300,
  DescOwn = 0x80000000, DescEndRing = 0x02000000, DescUseLink = 0x01000000, DescWholePkt = 0x60000000,
  DescStartPkt = 0x20000000, DescEndPkt = 0x40000000, DescIntr = 0x80000000
}
enum  EEPROM_Ctrl_Bits {
  EE_ShiftClk = 0x04, EE_DataIn = 0x01, EE_ChipSelect = 0x08, EE_DataOut = 0x02,
  EE_ShiftClk = 0x02, EE_Write0 = 0x801, EE_Write1 = 0x805, EE_ChipSelect = 0x801,
  EE_DataIn = 0x08
}
enum  EEPROM_Cmds {
  EE_WriteCmd = (5 << 6), EE_ReadCmd = (6 << 6), EE_EraseCmd = (7 << 6), EE_WriteCmd = (5 << 6),
  EE_ReadCmd = (6 << 6), EE_EraseCmd = (7 << 6)
}

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static int eeprom_read (long ioaddr, int location)
static int mdio_read (int base_address, int phy_id, int location)
static void check_duplex (void)
static void set_rx_mode (void)
static void init_ring (void)
static void w89c840_reset (struct nic *nic)
static int w89c840_poll (struct nic *nic, int retrieve)
static void w89c840_transmit (struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
static void w89c840_disable (struct nic *nic)
static void w89c840_irq (struct nic *nic __unused, irq_action_t action __unused)
 PCI_DRIVER (w89c840_driver, w89c840_nics, PCI_NO_CLASS)
static int w89c840_probe (struct nic *nic, struct pci_device *p)
static void mdio_sync (long mdio_addr)
 DRIVER ("W89C840F", nic_driver, pci_driver, w89c840_driver, w89c840_probe, w89c840_disable)

Variables

static const char * w89c840_version = "driver Version 0.94 - December 12, 2003"
static u32 driver_flags = CanHaveMII | HasBrokenTx
static struct winbond_private w840private
static int ioaddr
static unsigned short eeprom [0x40]
struct {
   char   rx_packet [PKT_BUF_SZ *RX_RING_SIZE]
   char   tx_packet [PKT_BUF_SZ *TX_RING_SIZE]
__shared
static struct nic_operations w89c840_operations
static struct pci_device_id w89c840_nics []
static char mii_preamble_required = 1


Define Documentation

#define USE_IO_OPS

Definition at line 80 of file w89c840.c.

#define virt_to_le32desc ( addr   )     virt_to_bus(addr)

Definition at line 90 of file w89c840.c.

#define le32desc_to_virt ( addr   )     bus_to_virt(addr)

Definition at line 91 of file w89c840.c.

#define TX_RING_SIZE   2

Definition at line 105 of file w89c840.c.

#define RX_RING_SIZE   2

Definition at line 106 of file w89c840.c.

#define TX_FIFO_SIZE   (2048)

Definition at line 112 of file w89c840.c.

#define TX_BUG_FIFO_LIMIT   (TX_FIFO_SIZE-1514-16)

Definition at line 113 of file w89c840.c.

Referenced by w89c840_transmit().

#define TX_TIMEOUT   (10*1000)

Definition at line 117 of file w89c840.c.

#define PKT_BUF_SZ   1536

Definition at line 119 of file w89c840.c.

#define W840_FLAGS   (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)

Definition at line 136 of file w89c840.c.

#define readb   inb

#define readw   inw

#define readl   inl

#define writeb   outb

#define writew   outw

#define writel   outl

#define PRIV_ALIGN   15

Definition at line 220 of file w89c840.c.

#define PRIV_ALIGN_BYTES   32

Definition at line 221 of file w89c840.c.

#define PCI_DEVICE_ID_WINBOND2_89C840   0x0840

Referenced by w89c840_probe().

#define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011

Referenced by w89c840_probe().

#define eeprom_delay ( ee_addr   )     readl(ee_addr)

Definition at line 731 of file w89c840.c.

#define mdio_delay ( mdio_addr   )     readl(mdio_addr)

Definition at line 781 of file w89c840.c.

#define MDIO_WRITE0   (MDIO_EnbOutput)

Definition at line 788 of file w89c840.c.

#define MDIO_WRITE1   (MDIO_DataOut | MDIO_EnbOutput)

Definition at line 789 of file w89c840.c.


Enumeration Type Documentation

Enumerator:
HAS_MII_XCVR 
HAS_CHIP_XCVR 
CanHaveMII 
KendinPktDropBug 
CanHaveMII 
HasBrokenTx 

Definition at line 133 of file w89c840.c.

00133 {CanHaveMII=1, HasBrokenTx=2};

Enumerator:
PCIBusCfg 
TxStartDemand 
RxStartDemand 
RxRingPtr 
TxRingPtr 
IntrStatus 
NetworkConfig 
IntrEnable 
RxMissed 
EECtrl 
MIICtrl 
BootRom 
GPTimer 
CurRxDescAddr 
CurRxBufAddr 
MulticastFilter0 
MulticastFilter1 
StationAddr 
CurTxDescAddr 
CurTxBufAddr 

Definition at line 168 of file w89c840.c.

00168                   {
00169     PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
00170     RxRingPtr=0x0C, TxRingPtr=0x10,
00171     IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
00172     RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
00173     CurRxDescAddr=0x30, CurRxBufAddr=0x34,            /* Debug use */
00174     MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
00175     CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
00176 };

Enumerator:
RFCON 
RFCOFF 
LSCStatus 
ANCStatus 
FBE 
FBEMask 
ParityErr 
TargetErr 
MasterErr 
TUNF 
ROVF 
ETI 
ERI 
CNTOVF 
RBU 
TBU 
TI 
RI 
RxErr 
IntrSummary 
IntrPCIErr 
IntrMACCtrl 
IntrTxDone 
IntrRxDone 
IntrRxStart 
IntrDrvRqst 
StatsMax 
LinkChange 
IntrTxDMADone 
IntrRxDMADone 
IntrRxDone 
IntrRxErr 
IntrRxEmpty 
IntrTxDone 
IntrTxError 
IntrTxUnderrun 
IntrPCIErr 
IntrStatsMax 
IntrRxEarly 
IntrRxOverflow 
IntrRxDropped 
IntrRxNoBuf 
IntrTxAborted 
IntrLinkChange 
IntrRxWakeUp 
IntrNormalSummary 
IntrAbnormalSummary 
IntrTxDescRace 
IntrTxErrSummary 
NormalIntr 
AbnormalIntr 
IntrPCIErr 
TimerInt 
IntrRxDied 
RxNoBuf 
IntrRxDone 
TxFIFOUnderflow 
RxErrIntr 
TxIdle 
IntrTxStopped 
IntrTxDone 

Definition at line 180 of file w89c840.c.

00180                       {
00181     NormalIntr=0x10000, AbnormalIntr=0x8000,
00182     IntrPCIErr=0x2000, TimerInt=0x800,
00183     IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
00184     TxFIFOUnderflow=0x20, RxErrIntr=0x10,
00185     TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
00186 };

Enumerator:
RxModeMask 
AcceptAllPhys 
AcceptBroadcast 
AcceptMulticast 
AcceptRunt 
ALP 
AcceptErr 
AcceptMyPhys 
RxEnable 
RxFlowCtrl 
TxEnable 
TxModeFDX 
TxThreshold 
PS1000 
PS10 
FD 
AcceptErr 
AcceptRunt 
AcceptBroadcast 
AcceptMulticast 
AcceptAllMulticast 
AcceptAllPhys 
AcceptMyPhys 
RxFilterEnable 
AcceptAllIPMulti 
AcceptMultiHash 
AcceptAll 
AcceptBroadcast 
AcceptMulticast 
AcceptMyPhys 
AcceptErr 
AcceptRunt 
AcceptBroadcast 
AcceptMulticast 
AcceptAllPhys 
AcceptMyPhys 

Definition at line 189 of file w89c840.c.

00189                   {
00190     AcceptErr=0x80, AcceptRunt=0x40,
00191     AcceptBroadcast=0x20, AcceptMulticast=0x10,
00192     AcceptAllPhys=0x08, AcceptMyPhys=0x02,
00193 };

Enumerator:
MDIO_ShiftClk 
MDIO_Data 
MDIO_EnbOutput 
MDIO_ShiftClk 
MDIO_DataIn 
MDIO_DataOut 
MDIO_EnbOutput 
MDIO_EnbIn 

Definition at line 195 of file w89c840.c.

00195                   {
00196     MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
00197     MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
00198 };

Enumerator:
DescOwn 
DescMore 
DescIntr 
DescNoCRC 
DescPktOK 
RxTooLong 
DescOwn 
DescEndPacket 
DescEndRing 
LastFrag 
DescIntrOnTx 
DescIntrOnDMADone 
DisableAlign 
DescOwnded 
RxDescFatalErr 
RxWholePkt 
DescOwn 
DescEndRing 
DescUseLink 
DescWholePkt 
DescStartPkt 
DescEndPkt 
DescIntr 

Definition at line 215 of file w89c840.c.

00215                       {
00216     DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
00217     DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
00218     DescIntr=0x80000000,
00219 };

Enumerator:
EE_ShiftClk 
EE_DataIn 
EE_ChipSelect 
EE_DataOut 
EE_ShiftClk 
EE_Write0 
EE_Write1 
EE_ChipSelect 
EE_DataIn 

Definition at line 733 of file w89c840.c.

00733                       {
00734     EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
00735     EE_ChipSelect=0x801, EE_DataIn=0x08,
00736 };

Enumerator:
EE_WriteCmd 
EE_ReadCmd 
EE_EraseCmd 
EE_WriteCmd 
EE_ReadCmd 
EE_EraseCmd 

Definition at line 739 of file w89c840.c.

00739                  {
00740     EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
00741 };


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static int eeprom_read ( long  ioaddr,
int  location 
) [static]

Definition at line 743 of file w89c840.c.

References EE_ChipSelect, EE_DataIn, EE_ReadCmd, EE_ShiftClk, EE_Write0, EE_Write1, EECtrl, eeprom_delay, readl, and writel.

00744 {
00745     int i;
00746     int retval = 0;
00747     int ee_addr = addr + EECtrl;
00748     int read_cmd = location | EE_ReadCmd;
00749     writel(EE_ChipSelect, ee_addr);
00750 
00751     /* Shift the read command bits out. */
00752     for (i = 10; i >= 0; i--) {
00753         short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
00754         writel(dataval, ee_addr);
00755         eeprom_delay(ee_addr);
00756         writel(dataval | EE_ShiftClk, ee_addr);
00757         eeprom_delay(ee_addr);
00758     }
00759     writel(EE_ChipSelect, ee_addr);
00760 
00761     for (i = 16; i > 0; i--) {
00762         writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
00763         eeprom_delay(ee_addr);
00764         retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
00765         writel(EE_ChipSelect, ee_addr);
00766         eeprom_delay(ee_addr);
00767     }
00768 
00769     /* Terminate the EEPROM access. */
00770     writel(0, ee_addr);
00771     return retval;
00772 }

static int mdio_read ( int  base_address,
int  phy_id,
int  location 
) [static]

Definition at line 806 of file w89c840.c.

References MDIO_DataIn, mdio_delay, MDIO_EnbIn, MDIO_ShiftClk, mdio_sync(), MDIO_WRITE0, MDIO_WRITE1, MIICtrl, readl, and writel.

00807 {
00808     long mdio_addr = base_address + MIICtrl;
00809     int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
00810     int i, retval = 0;
00811 
00812     if (mii_preamble_required)
00813         mdio_sync(mdio_addr);
00814 
00815     /* Shift the read command bits out. */
00816     for (i = 15; i >= 0; i--) {
00817         int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00818 
00819         writel(dataval, mdio_addr);
00820         mdio_delay(mdio_addr);
00821         writel(dataval | MDIO_ShiftClk, mdio_addr);
00822         mdio_delay(mdio_addr);
00823     }
00824     /* Read the two transition, 16 data, and wire-idle bits. */
00825     for (i = 20; i > 0; i--) {
00826         writel(MDIO_EnbIn, mdio_addr);
00827         mdio_delay(mdio_addr);
00828         retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
00829         writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00830         mdio_delay(mdio_addr);
00831     }
00832     return (retval>>1) & 0xffff;
00833 }

static void check_duplex ( void   )  [static]

Definition at line 868 of file w89c840.c.

References winbond_private::advertising, winbond_private::csr6, winbond_private::duplex_lock, winbond_private::full_duplex, mdio_read(), winbond_private::phys, printf(), and w840private.

00869 {
00870     int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
00871     int negotiated =  mii_reg5 & w840private.advertising;
00872     int duplex;
00873 
00874     if (w840private.duplex_lock  ||  mii_reg5 == 0xffff)
00875         return;
00876 
00877     duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
00878     if (w840private.full_duplex != duplex) {
00879         w840private.full_duplex = duplex;       
00880 
00881 #if defined(W89C840_DEBUG)
00882         printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
00883                duplex ? "full" : "half", w840private.phys[0], negotiated);
00884 #endif
00885 
00886         w840private.csr6 &= ~0x200;
00887         w840private.csr6 |= duplex ? 0x200 : 0;
00888     }
00889 }

static void set_rx_mode ( void   )  [static]

Definition at line 891 of file w89c840.c.

References AcceptBroadcast, AcceptMulticast, AcceptMyPhys, winbond_private::csr6, memset(), MulticastFilter0, MulticastFilter1, NetworkConfig, printf(), u32, w840private, and writel.

00892 {
00893     u32 mc_filter[2];            /* Multicast hash filter */
00894     u32 rx_mode;
00895 
00896     /* Accept all multicasts from now on. */
00897     memset(mc_filter, 0xff, sizeof(mc_filter));
00898 
00899 /*
00900  * works OK with multicast enabled. 
00901  */
00902 
00903     rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
00904 
00905     writel(mc_filter[0], ioaddr + MulticastFilter0);
00906     writel(mc_filter[1], ioaddr + MulticastFilter1);
00907     w840private.csr6 &= ~0x00F8;
00908     w840private.csr6 |= rx_mode;
00909     writel(w840private.csr6, ioaddr + NetworkConfig);
00910 
00911 #if defined(W89C840_DEBUG)
00912     printf("winbond-840 : Done setting RX mode.\n");
00913 #endif
00914 }

static void init_ring ( void   )  [static]

Definition at line 917 of file w89c840.c.

References w840_rx_desc::buffer1, winbond_private::cur_rx, winbond_private::cur_tx, DescEndRing, DescIntr, DescOwn, winbond_private::dirty_rx, winbond_private::dirty_tx, w840_rx_desc::length, w840_rx_desc::next_desc, PKT_BUF_SZ, winbond_private::rx_buf_sz, winbond_private::rx_head_desc, winbond_private::rx_ring, RX_RING_SIZE, w840_tx_desc::status, w840_rx_desc::status, winbond_private::tx_full, winbond_private::tx_q_bytes, winbond_private::tx_ring, TX_RING_SIZE, virt_to_le32desc, and w840private.

00918 {
00919     int i;
00920     char * p;
00921 
00922     w840private.tx_full = 0;
00923     w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
00924     w840private.dirty_rx = w840private.dirty_tx = 0;
00925 
00926     w840private.rx_buf_sz = PKT_BUF_SZ;
00927     w840private.rx_head_desc = &w840private.rx_ring[0];
00928 
00929     /* Initial all Rx descriptors. Fill in the Rx buffers. */
00930 
00931     p = &w89c840_buf.rx_packet[0];
00932 
00933     for (i = 0; i < RX_RING_SIZE; i++) {
00934         w840private.rx_ring[i].length = w840private.rx_buf_sz;
00935         w840private.rx_ring[i].status = 0;
00936         w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);
00937 
00938         w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
00939         w840private.rx_ring[i].status = DescOwn | DescIntr;
00940     }
00941 
00942     /* Mark the last entry as wrapping the ring. */
00943     w840private.rx_ring[i-1].length |= DescEndRing;
00944     w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);
00945 
00946     w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);
00947 
00948     for (i = 0; i < TX_RING_SIZE; i++) {
00949         w840private.tx_ring[i].status = 0;
00950     }
00951     return;
00952 }

static void w89c840_reset ( struct nic nic  )  [static]

Definition at line 300 of file w89c840.c.

References check_duplex(), winbond_private::csr6, ETH_ALEN, init_ring(), nic::node_addr, PCIBusCfg, printf(), winbond_private::rx_ring, RxRingPtr, RxStartDemand, set_rx_mode(), StationAddr, winbond_private::tx_ring, TxRingPtr, virt_to_bus(), w840private, writeb, and writel.

Referenced by w89c840_disable(), w89c840_poll(), and w89c840_probe().

00301 {
00302     int i;
00303 
00304     /* Reset the chip to erase previous misconfiguration.
00305        No hold time required! */
00306     writel(0x00000001, ioaddr + PCIBusCfg);
00307 
00308     init_ring();
00309 
00310     writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
00311     writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);
00312 
00313     for (i = 0; i < ETH_ALEN; i++)
00314         writeb(nic->node_addr[i], ioaddr + StationAddr + i);
00315 
00316     /* Initialize other registers. */
00317     /* Configure the PCI bus bursts and FIFO thresholds.
00318        486: Set 8 longword cache alignment, 8 longword burst.
00319        586: Set 16 longword cache alignment, no burst limit.
00320        Cache alignment bits 15:14         Burst length 13:8
00321         0000    <not allowed>         0000 align to cache    0800 8 longwords
00322         4000    8  longwords        0100 1 longword        1000 16 longwords
00323         8000    16 longwords        0200 2 longwords    2000 32 longwords
00324         C000    32  longwords        0400 4 longwords
00325        Wait the specified 50 PCI cycles after a reset by initializing
00326        Tx and Rx queues and the address filter list. */
00327 
00328     writel(0xE010, ioaddr + PCIBusCfg);
00329 
00330     writel(0, ioaddr + RxStartDemand);
00331     w840private.csr6 = 0x20022002;
00332     check_duplex();
00333     set_rx_mode();
00334 
00335     /* Do not enable the interrupts Etherboot doesn't need them */
00336 /*
00337     writel(0x1A0F5, ioaddr + IntrStatus);
00338     writel(0x1A0F5, ioaddr + IntrEnable);
00339 */
00340 #if defined(W89C840_DEBUG)
00341     printf("winbond-840 : Done reset.\n");
00342 #endif
00343 }

static int w89c840_poll ( struct nic nic,
int  retrieve 
) [static]

Definition at line 376 of file w89c840.c.

References w840_rx_desc::buffer1, winbond_private::cur_rx, DescOwn, entry, IntrStatus, le32desc_to_virt, memcpy, nic::packet, nic::packetlen, printf(), readl, winbond_private::rx_head_desc, winbond_private::rx_ring, RX_RING_SIZE, w840_rx_desc::status, u32, w840private, and w89c840_reset().

00377 {
00378     /* return true if there's an ethernet packet ready to read */
00379     /* nic->packet should contain data on return */
00380     /* nic->packetlen should contain length of data */
00381     int packet_received = 0;
00382 
00383 #if defined(W89C840_DEBUG)
00384     u32 intr_status = readl(ioaddr + IntrStatus);
00385 #endif
00386 
00387     do {
00388         /* Code from netdev_rx(dev) */
00389 
00390         int entry = w840private.cur_rx % RX_RING_SIZE;
00391 
00392         struct w840_rx_desc *desc = w840private.rx_head_desc;
00393         s32 status = desc->status;
00394 
00395         if (status & DescOwn) {
00396             /* DescOwn bit is still set, we should wait for RX to complete */
00397             packet_received = 0;
00398             break;
00399         }
00400 
00401         if ( !retrieve ) {
00402             packet_received = 1;
00403             break;
00404         }
00405 
00406         if ((status & 0x38008300) != 0x0300) {
00407             if ((status & 0x38000300) != 0x0300) {
00408                 /* Ingore earlier buffers. */
00409                 if ((status & 0xffff) != 0x7fff) {
00410                     printf("winbond-840 : Oversized Ethernet frame spanned "
00411                            "multiple buffers, entry %d status %X !\n",
00412                            w840private.cur_rx, (unsigned int) status);
00413                 }
00414             } else if (status & 0x8000) {
00415                 /* There was a fatal error. */
00416 #if defined(W89C840_DEBUG)
00417                 printf("winbond-840 : Receive error, Rx status %X :", status);
00418                 if (status & 0x0890) {
00419                     printf(" RXLEN_ERROR");
00420                 }
00421                 if (status & 0x004C) {
00422                     printf(", FRAME_ERROR");
00423                 }
00424                 if (status & 0x0002) {
00425                     printf(", CRC_ERROR");
00426                 }
00427                 printf("\n");
00428 #endif
00429 
00430                 /* Simpy do a reset now... */
00431                 w89c840_reset(nic);
00432 
00433                 packet_received = 0;
00434                 break;
00435             }
00436         } else {
00437             /* Omit the four octet CRC from the length. */
00438             int pkt_len = ((status >> 16) & 0x7ff) - 4;
00439 
00440 #if defined(W89C840_DEBUG)
00441             printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
00442 #endif
00443 
00444             nic->packetlen = pkt_len;
00445 
00446             /* Check if the packet is long enough to accept without copying
00447                to a minimally-sized skbuff. */
00448 
00449             memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
00450             packet_received = 1;
00451 
00452             /* Release buffer to NIC */
00453             w840private.rx_ring[entry].status = DescOwn;
00454 
00455 #if defined(W89C840_DEBUG)
00456             /* You will want this info for the initial debug. */
00457             printf("  Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
00458                    "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
00459                    "%hhX.%hhX.%hhX.%hhX.\n",
00460                    nic->packet[0],  nic->packet[1],  nic->packet[2], nic->packet[3],
00461                    nic->packet[4],  nic->packet[5],  nic->packet[6], nic->packet[7],
00462                    nic->packet[8],  nic->packet[9],  nic->packet[10],
00463                    nic->packet[11], nic->packet[12], nic->packet[13],
00464                    nic->packet[14], nic->packet[15], nic->packet[16],
00465                    nic->packet[17]);
00466 #endif
00467 
00468         }
00469 
00470         entry = (++w840private.cur_rx) % RX_RING_SIZE;
00471         w840private.rx_head_desc = &w840private.rx_ring[entry];
00472     } while (0);
00473     
00474     return packet_received;
00475 }

static void w89c840_transmit ( struct nic nic,
const char *  d,
unsigned int  t,
unsigned int  s,
const char *  p 
) [static]

Definition at line 481 of file w89c840.c.

References w840_tx_desc::buffer1, winbond_private::cur_tx, currticks(), DescEndRing, DescIntr, DescOwn, DescWholePkt, winbond_private::drv_flags, entry, ETH_ALEN, ETH_HLEN, ETH_ZLEN, HasBrokenTx, w840_tx_desc::length, memcpy, nic::node_addr, printf(), w840_tx_desc::status, TX_BUG_FIFO_LIMIT, winbond_private::tx_full, winbond_private::tx_q_bytes, winbond_private::tx_ring, TX_RING_SIZE, TX_TIMEOUT, TxStartDemand, u16, u32, virt_to_le32desc, w840private, and writel.

00487 {
00488     /* send the packet to destination */
00489     unsigned entry;
00490     int transmit_status;
00491     unsigned long ct;
00492 
00493     /* Caution: the write order is important here, set the field
00494        with the "ownership" bits last. */
00495 
00496     /* Fill in our transmit buffer */
00497     entry = w840private.cur_tx % TX_RING_SIZE;
00498 
00499     memcpy (w89c840_buf.tx_packet, d, ETH_ALEN);    /* dst */
00500     memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/*src*/
00501 
00502     *((char *) w89c840_buf.tx_packet + 12) = t >> 8;    /* type */
00503     *((char *) w89c840_buf.tx_packet + 13) = t;
00504 
00505     memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s);
00506     s += ETH_HLEN;
00507 
00508     while (s < ETH_ZLEN)
00509     *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0;
00510 
00511     w840private.tx_ring[entry].buffer1
00512             = virt_to_le32desc(w89c840_buf.tx_packet);
00513 
00514     w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
00515     if (entry >= TX_RING_SIZE-1)         /* Wrap ring */
00516         w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
00517     w840private.tx_ring[entry].status = (DescOwn);
00518     w840private.cur_tx++;
00519 
00520     w840private.tx_q_bytes = (u16) s;
00521     writel(0, ioaddr + TxStartDemand);
00522 
00523     /* Work around horrible bug in the chip by marking the queue as full
00524        when we do not have FIFO room for a maximum sized packet. */
00525 
00526     if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
00527         /* Actually this is left to help finding error tails later in debugging...
00528          * See Linux kernel driver in winbond-840.c for details.
00529          */
00530         w840private.tx_full = 1;
00531     }
00532 
00533 #if defined(W89C840_DEBUG)
00534     printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
00535 #endif
00536 
00537     /* Now wait for TX to complete. */
00538     transmit_status = w840private.tx_ring[entry].status;
00539 
00540     ct = currticks();
00541     {
00542 #if defined W89C840_DEBUG
00543         u32 intr_stat = 0;
00544 #endif
00545         while (1) {
00546 
00547 #if defined(W89C840_DEBUG)
00548               decode_interrupt(intr_stat);
00549 #endif
00550 
00551                 while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) {
00552 
00553                     transmit_status = w840private.tx_ring[entry].status;
00554                 }
00555 
00556                 break;
00557         }
00558     }
00559 
00560     if ((transmit_status & DescOwn) == 0) {
00561 
00562 #if defined(W89C840_DEBUG)
00563         printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
00564                 w840private.tx_ring[entry].status);
00565 #endif
00566 
00567         return;
00568     }
00569 
00570     /* Transmit timed out... */
00571 
00572     printf("winbond-840 : transmission TIMEOUT : status %X\n", 
00573            (unsigned int) w840private.tx_ring[entry].status);
00574 
00575     return;
00576 }

static void w89c840_disable ( struct nic nic  )  [static]

Definition at line 581 of file w89c840.c.

References winbond_private::csr6, NetworkConfig, w840private, w89c840_reset(), and writel.

00581                                                 {
00582 
00583     w89c840_reset(nic);
00584 
00585     /* Don't know what to do to disable the board. Is this needed at all? */
00586     /* Yes, a live NIC can corrupt the loaded memory later [Ken] */
00587     /* Stop the chip's Tx and Rx processes. */
00588     writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
00589 }

static void w89c840_irq ( struct nic *nic  __unused,
irq_action_t action  __unused 
) [static]

Definition at line 594 of file w89c840.c.

References DISABLE, ENABLE, and FORCE.

00595 {
00596   switch ( action ) {
00597   case DISABLE :
00598     break;
00599   case ENABLE :
00600     break;
00601   case FORCE :
00602     break;
00603   }
00604 }

PCI_DRIVER ( w89c840_driver  ,
w89c840_nics  ,
PCI_NO_CLASS   
)

static int w89c840_probe ( struct nic nic,
struct pci_device p 
) [static]

Definition at line 624 of file w89c840.c.

References adjust_pci_device(), winbond_private::advertising, pci_device::bus, CanHaveMII, DBG, pci_device::devfn, pci_device::device, driver_flags, eeprom_read(), ETH_ALEN, eth_ntoa(), nic::ioaddr, pci_device::ioaddr, nic::irqno, mdio_read(), winbond_private::mii_cnt, nic::nic_op, nic::node_addr, PCI_DEVICE_ID_COMPEX_RL100ATX, PCI_DEVICE_ID_WINBOND2_89C840, PCI_VENDOR_ID_COMPEX, PCI_VENDOR_ID_WINBOND2, PCIBusCfg, winbond_private::phys, printf(), u16, pci_device::vendor, w840private, w89c840_reset(), w89c840_version, and writel.

00624                                                                    {
00625 
00626 
00627     u16 sum = 0;
00628     int i, j;
00629     unsigned short value;
00630 
00631     if (p->ioaddr == 0)
00632         return 0;
00633 
00634     nic->ioaddr = p->ioaddr;
00635     nic->irqno  = 0;
00636 
00637 #if defined(W89C840_DEBUG)
00638     printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
00639 #endif
00640 
00641     ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
00642 
00643 #define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
00644 #define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011
00645 
00646     /* From Matt Hortman <mbhortman@acpthinclient.com> */
00647     if (p->vendor == PCI_VENDOR_ID_WINBOND2
00648         && p->device == PCI_DEVICE_ID_WINBOND2_89C840) {
00649 
00650         /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */
00651 
00652     } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
00653                 && p->device == PCI_DEVICE_ID_COMPEX_RL100ATX) {
00654 
00655         /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */
00656 
00657     } else {
00658         /* Gee, guess what? They missed again. */
00659         printf("device ID : %X - is not a Compex RL100ATX NIC.\n",
00660                p->device);
00661         return 0;
00662     }
00663 
00664     printf(" %s\n", w89c840_version);
00665 
00666     adjust_pci_device(p);
00667 
00668     /* Ok. Got one. Read the eeprom. */
00669     for (j = 0, i = 0; i < 0x40; i++) {
00670         value = eeprom_read(ioaddr, i);
00671         eeprom[i] = value;
00672         sum += value;
00673     }
00674 
00675     for (i=0;i<ETH_ALEN;i++) {
00676         nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;
00677     }
00678 
00679     DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
00680 
00681 #if defined(W89C840_DEBUG)
00682     printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
00683 #endif
00684 
00685     /* Reset the chip to erase previous misconfiguration.
00686        No hold time required! */
00687     writel(0x00000001, ioaddr + PCIBusCfg);
00688 
00689     if (driver_flags & CanHaveMII) {
00690         int phy, phy_idx = 0;
00691         for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
00692             int mii_status = mdio_read(ioaddr, phy, 1);
00693             if (mii_status != 0xffff  &&  mii_status != 0x0000) {
00694                 w840private.phys[phy_idx++] = phy;
00695                 w840private.advertising = mdio_read(ioaddr, phy, 4);
00696 
00697 #if defined(W89C840_DEBUG)
00698                 printf("winbond-840 : MII PHY found at address %d, status "
00699                        "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
00700 #endif
00701 
00702             }
00703         }
00704 
00705         w840private.mii_cnt = phy_idx;
00706 
00707         if (phy_idx == 0) {
00708                 printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
00709         }
00710     }
00711 
00712     /* point to NIC specific routines */
00713     nic->nic_op = &w89c840_operations;
00714 
00715     w89c840_reset(nic);
00716 
00717     return 1;
00718 }

static void mdio_sync ( long  mdio_addr  )  [static]

Definition at line 793 of file w89c840.c.

References mdio_delay, MDIO_ShiftClk, MDIO_WRITE1, and writel.

00794 {
00795     int bits = 32;
00796 
00797     /* Establish sync by sending at least 32 logic ones. */
00798     while (--bits >= 0) {
00799         writel(MDIO_WRITE1, mdio_addr);
00800         mdio_delay(mdio_addr);
00801         writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
00802         mdio_delay(mdio_addr);
00803     }
00804 }

DRIVER ( "W89C840F"  ,
nic_driver  ,
pci_driver  ,
w89c840_driver  ,
w89c840_probe  ,
w89c840_disable   
)


Variable Documentation

const char* w89c840_version = "driver Version 0.94 - December 12, 2003" [static]

Definition at line 87 of file w89c840.c.

Referenced by w89c840_probe().

u32 driver_flags = CanHaveMII | HasBrokenTx [static]

Definition at line 141 of file w89c840.c.

Referenced by w89c840_probe().

struct winbond_private w840private [static]

int ioaddr [static]

Definition at line 254 of file w89c840.c.

unsigned short eeprom[0x40] [static]

Definition at line 255 of file w89c840.c.

char rx_packet[PKT_BUF_SZ *RX_RING_SIZE]

Definition at line 257 of file w89c840.c.

char tx_packet[PKT_BUF_SZ *TX_RING_SIZE]

Definition at line 258 of file w89c840.c.

struct { ... } __shared

Initial value:

 {
        .connect        = dummy_connect,
        .poll           = w89c840_poll,
        .transmit       = w89c840_transmit,
        .irq            = w89c840_irq,

}

Definition at line 606 of file w89c840.c.

struct pci_device_id w89c840_nics[] [static]

Initial value:

 {
PCI_ROM(0x1050, 0x0840, "winbond840",     "Winbond W89C840F", 0),
PCI_ROM(0x11f6, 0x2011, "compexrl100atx", "Compex RL100ATX", 0),
}

Definition at line 614 of file w89c840.c.

char mii_preamble_required = 1 [static]

Definition at line 786 of file w89c840.c.


Generated on Tue Apr 6 20:01:46 2010 for gPXE by  doxygen 1.5.7.1