iPXE
Enumerations | Functions | Variables
3c5x9.c File Reference
#include <ipxe/ethernet.h>
#include "etherboot.h"
#include "nic.h"
#include <ipxe/isa.h>
#include "3c509.h"

Go to the source code of this file.

Enumerations

enum  { none, bnc, utp }

Functions

 FILE_LICENCE (BSD2)
void t5x9_disable (struct nic *nic)
static void t509_enable (struct nic *nic)
static void t509_reset (struct nic *nic)
static void t509_transmit (struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
static int t509_poll (struct nic *nic, int retrieve)
static void t509_irq (struct nic *nic __unused, irq_action_t action __unused)
static int eeprom_rdy (uint16_t ioaddr)
static int get_e (uint16_t ioaddr, int offset)
int t5x9_probe (struct nic *nic, uint16_t prod_id_check, uint16_t prod_id_mask)

Variables

static enum { ... }  connector
static char padmap []
static struct nic_operations t509_operations

Enumeration Type Documentation

anonymous enum
Enumerator:
none 
bnc 
utp 

Definition at line 35 of file 3c5x9.c.

{ none, bnc, utp } connector = none;    /* for 3C509 */

Function Documentation

FILE_LICENCE ( BSD2  )
void t5x9_disable ( struct nic nic)

Definition at line 40 of file 3c5x9.c.

References C_INTR_LATCH, EP_COMMAND, EP_STATUS, EP_W0_CONFIG_CTRL, EP_W0_RESOURCE_CFG, GO_WINDOW, inw(), outw(), RX_DISABLE, RX_DISCARD_TOP_PACK, RX_RESET, S_COMMAND_IN_PROGRESS, SET_INTR_MASK, SET_IRQ, SET_RD_0_MASK, SET_RX_FILTER, STOP_TRANSCEIVER, TX_DISABLE, TX_RESET, and udelay().

Referenced by el3_eisa_disable(), legacy_t509_disable(), t509_reset(), and t529_disable().

                                      {
        /* stop card */
        outw(RX_DISABLE, nic->ioaddr + EP_COMMAND);
        outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
        while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
                ;
        outw(TX_DISABLE, nic->ioaddr + EP_COMMAND);
        outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
        udelay(1000);
        outw(RX_RESET, nic->ioaddr + EP_COMMAND);
        outw(TX_RESET, nic->ioaddr + EP_COMMAND);
        outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
        outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND);
        outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
        outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND);

        /*
         * wait for reset to complete
         */
        while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
                ;

        GO_WINDOW(nic->ioaddr,0);

        /* Disable the card */
        outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL);

        /* Configure IRQ to none */
        outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG);
}
static void t509_enable ( struct nic nic) [static]

Definition at line 71 of file 3c5x9.c.

References ACK_INTR, bnc, connector, ENABLE_DRQ_IRQ, ENABLE_UTP, EP_COMMAND, EP_W0_CONFIG_CTRL, EP_W1_TX_STATUS, EP_W2_ADDR_0, EP_W4_MEDIA_TYPE, ETH_ALEN, ETH_ZLEN, FIL_BRDCST, FIL_GROUP, FIL_INDIVIDUAL, GO_WINDOW, inb(), mdelay(), outb(), outw(), RX_ENABLE, RX_RESET, S_5_INTS, SET_INTR_MASK, SET_RD_0_MASK, SET_RX_EARLY_THRESH, SET_RX_FILTER, SET_TX_START_THRESH, START_TRANSCEIVER, TX_ENABLE, TX_RESET, udelay(), and utp.

Referenced by t509_reset().

                                            {
        int i;

        /* Enable the card */
        GO_WINDOW(nic->ioaddr,0);
        outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL);

        GO_WINDOW(nic->ioaddr,2);

        /* Reload the ether_addr. */
        for (i = 0; i < ETH_ALEN; i++)
                outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i);

        outw(RX_RESET, nic->ioaddr + EP_COMMAND);
        outw(TX_RESET, nic->ioaddr + EP_COMMAND);

        /* Window 1 is operating window */
        GO_WINDOW(nic->ioaddr,1);
        for (i = 0; i < 31; i++)
                inb(nic->ioaddr + EP_W1_TX_STATUS);

        /* get rid of stray intr's */
        outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);

        outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND);

        outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);

        outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST,
             nic->ioaddr + EP_COMMAND);

        /* configure BNC */
        if (connector == bnc) {
                outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
                udelay(1000);
        }
        /* configure UTP */
        else if (connector == utp) {
                GO_WINDOW(nic->ioaddr,4);
                outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE);
                mdelay(2000);   /* Give time for media to negotiate */
                GO_WINDOW(nic->ioaddr,1);
        }

        /* start transceiver and receiver */
        outw(RX_ENABLE, nic->ioaddr + EP_COMMAND);
        outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);

        /* set early threshold for minimal packet length */
        outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND);
        outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND);
}
static void t509_reset ( struct nic nic) [static]

Definition at line 124 of file 3c5x9.c.

References t509_enable(), and t5x9_disable().

Referenced by t5x9_probe().

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

Definition at line 135 of file 3c5x9.c.

References EP_COMMAND, EP_STATUS, EP_W1_FREE_TX, EP_W1_TX_PIO_WR_1, EP_W1_TX_STATUS, ETH_ALEN, ETH_FRAME_LEN, ETH_HLEN, htons, inb(), inw(), len, outb(), outsw(), outw(), pad, padmap, printf(), S_COMMAND_IN_PROGRESS, status, TX_ENABLE, TX_RESET, TXS_COMPLETE, TXS_MAX_COLLISION, TXS_STATUS_OVERFLOW, and TXS_UNDERRUN.

{
        register unsigned int len;
        int pad;
        int status;

#ifdef  EDEBUG
        printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
#endif

        /* swap bytes of type */
        t= htons(t);

        len=s+ETH_HLEN; /* actual length of packet */
        pad = padmap[len & 3];

        /*
        * The 3c509 automatically pads short packets to minimum ethernet length,
        * but we drop packets that are too large. Perhaps we should truncate
        * them instead?
        */
        if (len + pad > ETH_FRAME_LEN) {
                return;
        }

        /* drop acknowledgements */
        while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
                if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
                        outw(TX_RESET, nic->ioaddr + EP_COMMAND);
                        outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
                }
                outb(0x0, nic->ioaddr + EP_W1_TX_STATUS);
        }

        while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
                ; /* no room in FIFO */

        outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1);
        outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1);     /* Second dword meaningless */

        /* write packet */
        outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
        outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
        outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1);
        outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2);
        if (s & 1)
                outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1);

        while (pad--)
                outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1);       /* Padding */

        /* wait for Tx complete */
        while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
                ;
}
static int t509_poll ( struct nic nic,
int  retrieve 
) [static]

Definition at line 199 of file 3c5x9.c.

References ACK_INTR, C_INTR_LATCH, EP_COMMAND, EP_STATUS, EP_W1_RX_PIO_RD_1, EP_W1_RX_STATUS, ERR_RX, ETH_ALEN, inb(), insw(), inw(), outw(), printf(), RX_BYTES_MASK, RX_DISCARD_TOP_PACK, RX_INCOMPLETE, S_5_INTS, S_COMMAND_IN_PROGRESS, S_RX_COMPLETE, status, type, and udelay().

{
        /* common variables */
        /* variables for 3C509 */
        short status, cst;
        register short rx_fifo;

        cst=inw(nic->ioaddr + EP_STATUS);

#ifdef  EDEBUG
        if(cst & 0x1FFF)
                printf("-%hX-",cst);
#endif

        if( (cst & S_RX_COMPLETE)==0 ) {
                /* acknowledge  everything */
                outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND);
                outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);

                return 0;
        }

        status = inw(nic->ioaddr + EP_W1_RX_STATUS);
#ifdef  EDEBUG
        printf("*%hX*",status);
#endif

        if (status & ERR_RX) {
                outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
                return 0;
        }

        rx_fifo = status & RX_BYTES_MASK;
        if (rx_fifo==0)
                return 0;

        if ( ! retrieve ) return 1;

                /* read packet */
#ifdef  EDEBUG
        printf("[l=%d",rx_fifo);
#endif
        insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
        if(rx_fifo & 1)
                nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
        nic->packetlen=rx_fifo;

        while(1) {
                status = inw(nic->ioaddr + EP_W1_RX_STATUS);
#ifdef  EDEBUG
                printf("*%hX*",status);
#endif
                rx_fifo = status & RX_BYTES_MASK;
                if(rx_fifo>0) {
                        insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
                        if(rx_fifo & 1)
                                nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
                        nic->packetlen+=rx_fifo;
#ifdef  EDEBUG
                        printf("+%d",rx_fifo);
#endif
                }
                if(( status & RX_INCOMPLETE )==0) {
#ifdef  EDEBUG
                        printf("=%d",nic->packetlen);
#endif
                        break;
                }
                udelay(1000);   /* if incomplete wait 1 ms */
        }
        /* acknowledge reception of packet */
        outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
        while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
                ;
#ifdef  EDEBUG
{
        unsigned short type = 0;        /* used by EDEBUG */
        type = (nic->packet[12]<<8) | nic->packet[13];
        if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
            nic->packet[5] == 0xFF*ETH_ALEN)
                printf(",t=%hX,b]",type);
        else
                printf(",t=%hX]",type);
}
#endif
        return (1);
}
static void t509_irq ( struct nic *nic  __unused,
irq_action_t action  __unused 
) [static]

Definition at line 290 of file 3c5x9.c.

{
  switch ( action ) {
  case DISABLE :
    break;
  case ENABLE :
    break;
  case FORCE :
    break;
  }
}
static int eeprom_rdy ( uint16_t  ioaddr) [static]

Definition at line 306 of file 3c5x9.c.

References is_eeprom_busy, and MAX_EEPROMBUSY.

Referenced by get_e().

                                          {
        int i;

        for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++);
        if (i >= MAX_EEPROMBUSY) {
                /* printf("3c509: eeprom failed to come ready.\n"); */
                /* memory in EPROM is tight */
                /* printf("3c509: eeprom busy.\n"); */
                return (0);
        }
        return (1);
}
static int get_e ( uint16_t  ioaddr,
int  offset 
) [static]

Definition at line 322 of file 3c5x9.c.

References EEPROM_CMD_RD, eeprom_rdy(), EP_W0_EEPROM_COMMAND, EP_W0_EEPROM_DATA, GO_WINDOW, inw(), and outw().

Referenced by t5x9_probe().

                                                 {
        GO_WINDOW(ioaddr,0);
        if (!eeprom_rdy(ioaddr))
                return (0xffff);
        outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND);
        if (!eeprom_rdy(ioaddr))
                return (0xffff);
        return (inw(ioaddr + EP_W0_EEPROM_DATA));
}
int t5x9_probe ( struct nic nic,
uint16_t  prod_id_check,
uint16_t  prod_id_mask 
)

Definition at line 342 of file 3c5x9.c.

References bnc, connector, DBG, EEPROM_PROD_ID, EP_W0_ADDRESS_CFG, EP_W0_CONFIG_CTRL, EP_W2_ADDR_0, ETH_ALEN, eth_ntoa(), get_e(), GO_WINDOW, htons, inw(), IS_AUI, IS_BNC, IS_UTP, ntohs, outw(), printf(), t509_operations, t509_reset(), and utp.

Referenced by el3_eisa_probe(), legacy_t509_probe(), and t529_probe().

                                                                 {
        uint16_t prod_id;
        int i,j;
        unsigned short *p;
        
        /* Check product ID */
        prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID );
        if ( ( prod_id & prod_id_mask ) != prod_id_check ) {
                printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n",
                         prod_id, prod_id_mask, prod_id_check );
                return 0;
        }

        /* test for presence of connectors */
        GO_WINDOW(nic->ioaddr,0);
        i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL);
        j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3;

        switch(j) {
        case 0:
                if (i & IS_UTP) {
                        printf("10baseT\n");
                        connector = utp;
                } else {
                        printf("10baseT not present\n");
                        return 0;
                }
                break;
        case 1:
                if (i & IS_AUI) {
                        printf("10base5\n");
                } else {
                        printf("10base5 not present\n");
                        return 0;
                }
                break;
        case 3:
                if (i & IS_BNC) {
                        printf("10base2\n");
                        connector = bnc;
                } else {
                        printf("10base2 not present\n");
                        return 0;
                }
                break;
        default:
                printf("unknown connector\n");
                return 0;
        }

        /*
        * Read the station address from the eeprom
        */
        p = (unsigned short *) nic->node_addr;
        for (i = 0; i < ETH_ALEN / 2; i++) {
                p[i] = htons(get_e(nic->ioaddr,i));
                GO_WINDOW(nic->ioaddr,2);
                outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2));
        }

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

        t509_reset(nic);

        nic->nic_op = &t509_operations;
        return 1;

}

Variable Documentation

enum { ... } connector [static]

Referenced by t509_enable(), and t5x9_probe().

char padmap[] [static]
Initial value:
 {
        0, 3, 2, 1}

Definition at line 132 of file 3c5x9.c.

Referenced by t509_transmit().

struct nic_operations t509_operations [static]
Initial value:
 {
        .connect        = dummy_connect,
        .poll           = t509_poll,
        .transmit       = t509_transmit,
        .irq            = t509_irq,
}

Definition at line 332 of file 3c5x9.c.

Referenced by t5x9_probe().