iPXE
Data Structures | Defines | Enumerations | Functions | Variables
w89c840.c File Reference
#include "etherboot.h"
#include "nic.h"
#include <ipxe/pci.h>
#include <ipxe/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 /* Size of each temporary Rx buffer.*/
#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 /* Required alignment mask */
#define PRIV_ALIGN_BYTES   32
#define PCI_VENDOR_ID_WINBOND2   0x1050
#define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
#define PCI_VENDOR_ID_COMPEX   0x11f6
#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 { 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 {
  IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008, IntrTxDone = 0x0004,
  IntrRxDone = 0x0010, IntrRxStart = 0x0020, IntrDrvRqst = 0x0040, StatsMax = 0x0080,
  LinkChange = 0x0100, IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400, 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 {
  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 = 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 = 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) }

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 81 of file w89c840.c.

#define virt_to_le32desc (   addr)    virt_to_bus(addr)

Definition at line 91 of file w89c840.c.

Referenced by init_ring(), and w89c840_transmit().

#define le32desc_to_virt (   addr)    bus_to_virt(addr)

Definition at line 92 of file w89c840.c.

Referenced by w89c840_poll().

#define TX_RING_SIZE   2

Definition at line 106 of file w89c840.c.

Referenced by init_ring(), and w89c840_transmit().

#define RX_RING_SIZE   2

Definition at line 107 of file w89c840.c.

Referenced by init_ring(), and w89c840_poll().

#define TX_FIFO_SIZE   (2048)

Definition at line 113 of file w89c840.c.

#define TX_BUG_FIFO_LIMIT   (TX_FIFO_SIZE-1514-16)

Definition at line 114 of file w89c840.c.

Referenced by w89c840_transmit().

#define TX_TIMEOUT   (10*1000)

Definition at line 118 of file w89c840.c.

Referenced by w89c840_transmit().

#define PKT_BUF_SZ   1536 /* Size of each temporary Rx buffer.*/

Definition at line 120 of file w89c840.c.

Referenced by init_ring().

Definition at line 137 of file w89c840.c.

#define readb   inb

Definition at line 155 of file w89c840.c.

#define readw   inw

Definition at line 156 of file w89c840.c.

#define readl   inl

Definition at line 157 of file w89c840.c.

Referenced by eeprom_read(), mdio_read(), and w89c840_poll().

#define writeb   outb

Definition at line 158 of file w89c840.c.

Referenced by w89c840_reset().

#define writew   outw

Definition at line 159 of file w89c840.c.

#define writel   outl
#define PRIV_ALIGN   15 /* Required alignment mask */

Definition at line 221 of file w89c840.c.

#define PRIV_ALIGN_BYTES   32

Definition at line 222 of file w89c840.c.

#define PCI_VENDOR_ID_WINBOND2   0x1050

Referenced by w89c840_probe().

#define PCI_DEVICE_ID_WINBOND2_89C840   0x0840

Referenced by w89c840_probe().

#define PCI_VENDOR_ID_COMPEX   0x11f6

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 734 of file w89c840.c.

Referenced by eeprom_read().

#define mdio_delay (   mdio_addr)    readl(mdio_addr)

Definition at line 784 of file w89c840.c.

Referenced by mdio_read(), and mdio_sync().

#define MDIO_WRITE0   (MDIO_EnbOutput)

Definition at line 791 of file w89c840.c.

Referenced by mdio_read().

Definition at line 792 of file w89c840.c.

Referenced by mdio_read(), and mdio_sync().


Enumeration Type Documentation

Enumerator:
CanHaveMII 
KendinPktDropBug 
CanHaveMII 
HasBrokenTx 

Definition at line 134 of file w89c840.c.

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

Definition at line 169 of file w89c840.c.

                  {
    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,            /* Debug use */
    MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
    CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
};
Enumerator:
IntrSummary 
IntrPCIErr 
IntrMACCtrl 
IntrTxDone 
IntrRxDone 
IntrRxStart 
IntrDrvRqst 
StatsMax 
LinkChange 
IntrTxDMADone 
IntrRxDMADone 
NormalIntr 
AbnormalIntr 
IntrPCIErr 
TimerInt 
IntrRxDied 
RxNoBuf 
IntrRxDone 
TxFIFOUnderflow 
RxErrIntr 
TxIdle 
IntrTxStopped 
IntrTxDone 

Definition at line 181 of file w89c840.c.

                      {
    NormalIntr=0x10000, AbnormalIntr=0x8000,
    IntrPCIErr=0x2000, TimerInt=0x800,
    IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
    TxFIFOUnderflow=0x20, RxErrIntr=0x10,
    TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
};
Enumerator:
AcceptAllIPMulti 
AcceptMultiHash 
AcceptAll 
AcceptBroadcast 
AcceptMulticast 
AcceptMyPhys 
AcceptErr 
AcceptRunt 
AcceptBroadcast 
AcceptMulticast 
AcceptAllPhys 
AcceptMyPhys 

Definition at line 190 of file w89c840.c.

Enumerator:
MDIO_ShiftClk 
MDIO_Data 
MDIO_EnbOutput 
MDIO_ShiftClk 
MDIO_DataIn 
MDIO_DataOut 
MDIO_EnbOutput 
MDIO_EnbIn 

Definition at line 196 of file w89c840.c.

                  {
    MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
    MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
};
Enumerator:
DescOwn 
DescEndPacket 
DescEndRing 
LastFrag 
DescIntrOnTx 
DescIntrOnDMADone 
DisableAlign 
DescOwnded 
RxDescFatalErr 
RxWholePkt 
DescOwn 
DescEndRing 
DescUseLink 
DescWholePkt 
DescStartPkt 
DescEndPkt 
DescIntr 

Definition at line 216 of file w89c840.c.

                      {
    DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
    DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
    DescIntr=0x80000000,
};
Enumerator:
EE_ShiftClk 
EE_Write0 
EE_Write1 
EE_ChipSelect 
EE_DataIn 

Definition at line 736 of file w89c840.c.

                      {
    EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
    EE_ChipSelect=0x801, EE_DataIn=0x08,
};
Enumerator:
EE_WriteCmd 
EE_ReadCmd 
EE_EraseCmd 

Definition at line 742 of file w89c840.c.

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

Function Documentation

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

Definition at line 746 of file w89c840.c.

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

Referenced by w89c840_probe().

{
    int i;
    int retval = 0;
    int ee_addr = addr + EECtrl;
    int read_cmd = location | EE_ReadCmd;
    writel(EE_ChipSelect, ee_addr);

    /* Shift the read command bits out. */
    for (i = 10; i >= 0; i--) {
        short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
        writel(dataval, ee_addr);
        eeprom_delay(ee_addr);
        writel(dataval | EE_ShiftClk, ee_addr);
        eeprom_delay(ee_addr);
    }
    writel(EE_ChipSelect, ee_addr);

    for (i = 16; i > 0; i--) {
        writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
        eeprom_delay(ee_addr);
        retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
        writel(EE_ChipSelect, ee_addr);
        eeprom_delay(ee_addr);
    }

    /* Terminate the EEPROM access. */
    writel(0, ee_addr);
    return retval;
}
static int mdio_read ( int  base_address,
int  phy_id,
int  location 
) [static]

Definition at line 809 of file w89c840.c.

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

{
    long mdio_addr = base_address + MIICtrl;
    int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
    int i, retval = 0;

    if (mii_preamble_required)
        mdio_sync(mdio_addr);

    /* Shift the read command bits out. */
    for (i = 15; i >= 0; i--) {
        int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;

        writel(dataval, mdio_addr);
        mdio_delay(mdio_addr);
        writel(dataval | MDIO_ShiftClk, mdio_addr);
        mdio_delay(mdio_addr);
    }
    /* Read the two transition, 16 data, and wire-idle bits. */
    for (i = 20; i > 0; i--) {
        writel(MDIO_EnbIn, mdio_addr);
        mdio_delay(mdio_addr);
        retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
        writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
        mdio_delay(mdio_addr);
    }
    return (retval>>1) & 0xffff;
}
static void check_duplex ( void  ) [static]

Definition at line 871 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.

Referenced by w89c840_reset().

{
    int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
    int negotiated =  mii_reg5 & w840private.advertising;
    int duplex;

    if (w840private.duplex_lock  ||  mii_reg5 == 0xffff)
        return;

    duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
    if (w840private.full_duplex != duplex) {
        w840private.full_duplex = duplex;       

#if defined(W89C840_DEBUG)
        printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
               duplex ? "full" : "half", w840private.phys[0], negotiated);
#endif

        w840private.csr6 &= ~0x200;
        w840private.csr6 |= duplex ? 0x200 : 0;
    }
}
static void set_rx_mode ( void  ) [static]

Definition at line 894 of file w89c840.c.

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

Referenced by w89c840_reset().

{
    u32 mc_filter[2];            /* Multicast hash filter */
    u32 rx_mode;

    /* Accept all multicasts from now on. */
    memset(mc_filter, 0xff, sizeof(mc_filter));

/*
 * works OK with multicast enabled. 
 */

    rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;

    writel(mc_filter[0], ioaddr + MulticastFilter0);
    writel(mc_filter[1], ioaddr + MulticastFilter1);
    w840private.csr6 &= ~0x00F8;
    w840private.csr6 |= rx_mode;
    writel(w840private.csr6, ioaddr + NetworkConfig);

#if defined(W89C840_DEBUG)
    printf("winbond-840 : Done setting RX mode.\n");
#endif
}
static void init_ring ( void  ) [static]

Definition at line 920 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_rx_desc::status, w840_tx_desc::status, winbond_private::tx_full, winbond_private::tx_q_bytes, winbond_private::tx_ring, TX_RING_SIZE, virt_to_le32desc, and w840private.

Referenced by w89c840_reset().

{
    int i;
    char * p;

    w840private.tx_full = 0;
    w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
    w840private.dirty_rx = w840private.dirty_tx = 0;

    w840private.rx_buf_sz = PKT_BUF_SZ;
    w840private.rx_head_desc = &w840private.rx_ring[0];

    /* Initial all Rx descriptors. Fill in the Rx buffers. */

    p = &w89c840_buf.rx_packet[0];

    for (i = 0; i < RX_RING_SIZE; i++) {
        w840private.rx_ring[i].length = w840private.rx_buf_sz;
        w840private.rx_ring[i].status = 0;
        w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);

        w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
        w840private.rx_ring[i].status = DescOwn | DescIntr;
    }

    /* Mark the last entry as wrapping the ring. */
    w840private.rx_ring[i-1].length |= DescEndRing;
    w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);

    w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);

    for (i = 0; i < TX_RING_SIZE; i++) {
        w840private.tx_ring[i].status = 0;
    }
    return;
}
static void w89c840_reset ( struct nic nic) [static]

Definition at line 301 of file w89c840.c.

References check_duplex(), winbond_private::csr6, ETH_ALEN, init_ring(), 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().

{
    int i;

    /* Reset the chip to erase previous misconfiguration.
       No hold time required! */
    writel(0x00000001, ioaddr + PCIBusCfg);

    init_ring();

    writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
    writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);

    for (i = 0; i < ETH_ALEN; i++)
        writeb(nic->node_addr[i], ioaddr + StationAddr + i);

    /* Initialize other registers. */
    /* Configure the PCI bus bursts and FIFO thresholds.
       486: Set 8 longword cache alignment, 8 longword burst.
       586: Set 16 longword cache alignment, no burst limit.
       Cache alignment bits 15:14         Burst length 13:8
        0000    <not allowed>         0000 align to cache    0800 8 longwords
        4000    8  longwords        0100 1 longword        1000 16 longwords
        8000    16 longwords        0200 2 longwords    2000 32 longwords
        C000    32  longwords        0400 4 longwords
       Wait the specified 50 PCI cycles after a reset by initializing
       Tx and Rx queues and the address filter list. */

    writel(0xE010, ioaddr + PCIBusCfg);

    writel(0, ioaddr + RxStartDemand);
    w840private.csr6 = 0x20022002;
    check_duplex();
    set_rx_mode();

    /* Do not enable the interrupts Etherboot doesn't need them */
/*
    writel(0x1A0F5, ioaddr + IntrStatus);
    writel(0x1A0F5, ioaddr + IntrEnable);
*/
#if defined(W89C840_DEBUG)
    printf("winbond-840 : Done reset.\n");
#endif
}
static int w89c840_poll ( struct nic nic,
int  retrieve 
) [static]

Definition at line 377 of file w89c840.c.

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

{
    /* return true if there's an ethernet packet ready to read */
    /* nic->packet should contain data on return */
    /* nic->packetlen should contain length of data */
    int packet_received = 0;

#if defined(W89C840_DEBUG)
    u32 intr_status = readl(ioaddr + IntrStatus);
#endif

    do {
        /* Code from netdev_rx(dev) */

        int entry = w840private.cur_rx % RX_RING_SIZE;

        struct w840_rx_desc *desc = w840private.rx_head_desc;
        s32 status = desc->status;

        if (status & DescOwn) {
            /* DescOwn bit is still set, we should wait for RX to complete */
            packet_received = 0;
            break;
        }

        if ( !retrieve ) {
            packet_received = 1;
            break;
        }

        if ((status & 0x38008300) != 0x0300) {
            if ((status & 0x38000300) != 0x0300) {
                /* Ingore earlier buffers. */
                if ((status & 0xffff) != 0x7fff) {
                    printf("winbond-840 : Oversized Ethernet frame spanned "
                           "multiple buffers, entry %d status %X !\n",
                           w840private.cur_rx, (unsigned int) status);
                }
            } else if (status & 0x8000) {
                /* There was a fatal error. */
#if defined(W89C840_DEBUG)
                printf("winbond-840 : Receive error, Rx status %X :", status);
                if (status & 0x0890) {
                    printf(" RXLEN_ERROR");
                }
                if (status & 0x004C) {
                    printf(", FRAME_ERROR");
                }
                if (status & 0x0002) {
                    printf(", CRC_ERROR");
                }
                printf("\n");
#endif

                /* Simpy do a reset now... */
                w89c840_reset(nic);

                packet_received = 0;
                break;
            }
        } else {
            /* Omit the four octet CRC from the length. */
            int pkt_len = ((status >> 16) & 0x7ff) - 4;

#if defined(W89C840_DEBUG)
            printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
#endif

            nic->packetlen = pkt_len;

            /* Check if the packet is long enough to accept without copying
               to a minimally-sized skbuff. */

            memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
            packet_received = 1;

            /* Release buffer to NIC */
            w840private.rx_ring[entry].status = DescOwn;

#if defined(W89C840_DEBUG)
            /* You will want this info for the initial debug. */
            printf("  Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
                   "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
                   "%hhX.%hhX.%hhX.%hhX.\n",
                   nic->packet[0],  nic->packet[1],  nic->packet[2], nic->packet[3],
                   nic->packet[4],  nic->packet[5],  nic->packet[6], nic->packet[7],
                   nic->packet[8],  nic->packet[9],  nic->packet[10],
                   nic->packet[11], nic->packet[12], nic->packet[13],
                   nic->packet[14], nic->packet[15], nic->packet[16],
                   nic->packet[17]);
#endif

        }

        entry = (++w840private.cur_rx) % RX_RING_SIZE;
        w840private.rx_head_desc = &w840private.rx_ring[entry];
    } while (0);
    
    return packet_received;
}
static void w89c840_transmit ( struct nic nic,
const char *  d,
unsigned int  t,
unsigned int  s,
const char *  p 
) [static]

Definition at line 482 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(), 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, virt_to_le32desc, w840private, and writel.

{
    /* send the packet to destination */
    unsigned entry;
    int transmit_status;
    unsigned long ct;

    /* Caution: the write order is important here, set the field
       with the "ownership" bits last. */

    /* Fill in our transmit buffer */
    entry = w840private.cur_tx % TX_RING_SIZE;

    memcpy (w89c840_buf.tx_packet, d, ETH_ALEN);    /* dst */
    memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/*src*/

    *((char *) w89c840_buf.tx_packet + 12) = t >> 8;    /* type */
    *((char *) w89c840_buf.tx_packet + 13) = t;

    memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s);
    s += ETH_HLEN;

    while (s < ETH_ZLEN)
    *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0;

    w840private.tx_ring[entry].buffer1
            = virt_to_le32desc(w89c840_buf.tx_packet);

    w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
    if (entry >= TX_RING_SIZE-1)         /* Wrap ring */
        w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
    w840private.tx_ring[entry].status = (DescOwn);
    w840private.cur_tx++;

    w840private.tx_q_bytes = (u16) s;
    writel(0, ioaddr + TxStartDemand);

    /* Work around horrible bug in the chip by marking the queue as full
       when we do not have FIFO room for a maximum sized packet. */

    if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
        /* Actually this is left to help finding error tails later in debugging...
         * See Linux kernel driver in winbond-840.c for details.
         */
        w840private.tx_full = 1;
    }

#if defined(W89C840_DEBUG)
    printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
#endif

    /* Now wait for TX to complete. */
    transmit_status = w840private.tx_ring[entry].status;

    ct = currticks();
    {
#if defined W89C840_DEBUG
        u32 intr_stat = 0;
#endif
        while (1) {

#if defined(W89C840_DEBUG)
              decode_interrupt(intr_stat);
#endif

                while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) {

                    transmit_status = w840private.tx_ring[entry].status;
                }

                break;
        }
    }

    if ((transmit_status & DescOwn) == 0) {

#if defined(W89C840_DEBUG)
        printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
                w840private.tx_ring[entry].status);
#endif

        return;
    }

    /* Transmit timed out... */

    printf("winbond-840 : transmission TIMEOUT : status %X\n", 
           (unsigned int) w840private.tx_ring[entry].status);

    return;
}
static void w89c840_disable ( struct nic nic) [static]

Definition at line 582 of file w89c840.c.

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

                                                {

    w89c840_reset(nic);

    /* Don't know what to do to disable the board. Is this needed at all? */
    /* Yes, a live NIC can corrupt the loaded memory later [Ken] */
    /* Stop the chip's Tx and Rx processes. */
    writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
}
static void w89c840_irq ( struct nic *nic  __unused,
irq_action_t action  __unused 
) [static]

Definition at line 595 of file w89c840.c.

{
  switch ( action ) {
  case DISABLE :
    break;
  case ENABLE :
    break;
  case FORCE :
    break;
  }
}
PCI_DRIVER ( w89c840_driver  ,
w89c840_nics  ,
PCI_NO_CLASS   
)
static int w89c840_probe ( struct nic nic,
struct pci_device p 
) [static]

Definition at line 625 of file w89c840.c.

References adjust_pci_device(), winbond_private::advertising, CanHaveMII, DBG, pci_device::device, driver_flags, eeprom_read(), ETH_ALEN, eth_ntoa(), pci_device::ioaddr, mdio_read(), winbond_private::mii_cnt, PCI_DEVICE_ID_COMPEX_RL100ATX, PCI_DEVICE_ID_WINBOND2_89C840, PCI_VENDOR_ID_COMPEX, PCI_VENDOR_ID_WINBOND2, PCIBusCfg, phy, winbond_private::phys, printf(), value, pci_device::vendor, w840private, w89c840_operations, w89c840_reset(), w89c840_version, and writel.

                                                                   {


    u16 sum = 0;
    int i;
    unsigned short value;

    if (p->ioaddr == 0)
        return 0;

    nic->ioaddr = p->ioaddr;
    nic->irqno  = 0;

#if defined(W89C840_DEBUG)
    printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
#endif

    ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */

#define PCI_VENDOR_ID_WINBOND2          0x1050
#define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
#define PCI_VENDOR_ID_COMPEX            0x11f6
#define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011

    /* From Matt Hortman <mbhortman@acpthinclient.com> */
    if (p->vendor == PCI_VENDOR_ID_WINBOND2
        && p->device == PCI_DEVICE_ID_WINBOND2_89C840) {

        /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */

    } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
                && p->device == PCI_DEVICE_ID_COMPEX_RL100ATX) {

        /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */

    } else {
        /* Gee, guess what? They missed again. */
        printf("device ID : %X - is not a Compex RL100ATX NIC.\n",
               p->device);
        return 0;
    }

    printf(" %s\n", w89c840_version);

    adjust_pci_device(p);

    /* Ok. Got one. Read the eeprom. */
    for (i = 0; i < 0x40; i++) {
        value = eeprom_read(ioaddr, i);
        eeprom[i] = value;
        sum += value;
    }

    for (i=0;i<ETH_ALEN;i++) {
        nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;
    }

    DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );

#if defined(W89C840_DEBUG)
    printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
#endif

    /* Reset the chip to erase previous misconfiguration.
       No hold time required! */
    writel(0x00000001, ioaddr + PCIBusCfg);

    if (driver_flags & CanHaveMII) {
        int phy, phy_idx = 0;
        for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
            int mii_status = mdio_read(ioaddr, phy, 1);
            if (mii_status != 0xffff  &&  mii_status != 0x0000) {
                w840private.phys[phy_idx++] = phy;
                w840private.advertising = mdio_read(ioaddr, phy, 4);

#if defined(W89C840_DEBUG)
                printf("winbond-840 : MII PHY found at address %d, status "
                       "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
#endif

            }
        }

        w840private.mii_cnt = phy_idx;

        if (phy_idx == 0) {
                printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
        }
    }

    /* point to NIC specific routines */
    nic->nic_op = &w89c840_operations;

    w89c840_reset(nic);

    return 1;
}
static void mdio_sync ( long  mdio_addr) [static]

Definition at line 796 of file w89c840.c.

References mdio_delay, MDIO_ShiftClk, MDIO_WRITE1, and writel.

Referenced by mdio_read().

{
    int bits = 32;

    /* Establish sync by sending at least 32 logic ones. */
    while (--bits >= 0) {
        writel(MDIO_WRITE1, mdio_addr);
        mdio_delay(mdio_addr);
        writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
        mdio_delay(mdio_addr);
    }
}
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 88 of file w89c840.c.

Referenced by w89c840_probe().

Definition at line 142 of file w89c840.c.

Referenced by w89c840_probe().

struct winbond_private w840private [static]
int ioaddr [static]

Definition at line 255 of file w89c840.c.

unsigned short eeprom[0x40] [static]

Definition at line 258 of file w89c840.c.

Definition at line 259 of file w89c840.c.

struct { ... } __shared
struct nic_operations w89c840_operations [static]
Initial value:
 {
        .connect        = dummy_connect,
        .poll           = w89c840_poll,
        .transmit       = w89c840_transmit,
        .irq            = w89c840_irq,

}

Definition at line 607 of file w89c840.c.

Referenced by w89c840_probe().

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 615 of file w89c840.c.

char mii_preamble_required = 1 [static]

Definition at line 789 of file w89c840.c.