3c5x9.c File Reference

#include <gpxe/ethernet.h>
#include "etherboot.h"
#include "nic.h"
#include <gpxe/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.

00035 { 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, nic::ioaddr, 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().

00040                                       {
00041         /* stop card */
00042         outw(RX_DISABLE, nic->ioaddr + EP_COMMAND);
00043         outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
00044         while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
00045                 ;
00046         outw(TX_DISABLE, nic->ioaddr + EP_COMMAND);
00047         outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
00048         udelay(1000);
00049         outw(RX_RESET, nic->ioaddr + EP_COMMAND);
00050         outw(TX_RESET, nic->ioaddr + EP_COMMAND);
00051         outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
00052         outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND);
00053         outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
00054         outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND);
00055 
00056         /*
00057          * wait for reset to complete
00058          */
00059         while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
00060                 ;
00061 
00062         GO_WINDOW(nic->ioaddr,0);
00063 
00064         /* Disable the card */
00065         outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL);
00066 
00067         /* Configure IRQ to none */
00068         outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG);
00069 }

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, nic::ioaddr, nic::node_addr, 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, sleep(), START_TRANSCEIVER, TX_ENABLE, TX_RESET, udelay(), and utp.

Referenced by t509_reset().

00071                                             {
00072         int i;
00073 
00074         /* Enable the card */
00075         GO_WINDOW(nic->ioaddr,0);
00076         outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL);
00077 
00078         GO_WINDOW(nic->ioaddr,2);
00079 
00080         /* Reload the ether_addr. */
00081         for (i = 0; i < ETH_ALEN; i++)
00082                 outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i);
00083 
00084         outw(RX_RESET, nic->ioaddr + EP_COMMAND);
00085         outw(TX_RESET, nic->ioaddr + EP_COMMAND);
00086 
00087         /* Window 1 is operating window */
00088         GO_WINDOW(nic->ioaddr,1);
00089         for (i = 0; i < 31; i++)
00090                 inb(nic->ioaddr + EP_W1_TX_STATUS);
00091 
00092         /* get rid of stray intr's */
00093         outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);
00094 
00095         outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND);
00096 
00097         outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
00098 
00099         outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST,
00100              nic->ioaddr + EP_COMMAND);
00101 
00102         /* configure BNC */
00103         if (connector == bnc) {
00104                 outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
00105                 udelay(1000);
00106         }
00107         /* configure UTP */
00108         else if (connector == utp) {
00109                 GO_WINDOW(nic->ioaddr,4);
00110                 outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE);
00111                 sleep(2);       /* Give time for media to negotiate */
00112                 GO_WINDOW(nic->ioaddr,1);
00113         }
00114 
00115         /* start transceiver and receiver */
00116         outw(RX_ENABLE, nic->ioaddr + EP_COMMAND);
00117         outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
00118 
00119         /* set early threshold for minimal packet length */
00120         outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND);
00121         outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND);
00122 }

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().

00124                                            {
00125         t5x9_disable ( nic );
00126         t509_enable ( nic );
00127 }    

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, nic::ioaddr, nic::node_addr, outb, outsw, outw, padmap, printf(), S_COMMAND_IN_PROGRESS, TX_ENABLE, TX_RESET, TXS_COMPLETE, TXS_MAX_COLLISION, TXS_STATUS_OVERFLOW, and TXS_UNDERRUN.

00141 {
00142         register unsigned int len;
00143         int pad;
00144         int status;
00145 
00146 #ifdef  EDEBUG
00147         printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
00148 #endif
00149 
00150         /* swap bytes of type */
00151         t= htons(t);
00152 
00153         len=s+ETH_HLEN; /* actual length of packet */
00154         pad = padmap[len & 3];
00155 
00156         /*
00157         * The 3c509 automatically pads short packets to minimum ethernet length,
00158         * but we drop packets that are too large. Perhaps we should truncate
00159         * them instead?
00160         */
00161         if (len + pad > ETH_FRAME_LEN) {
00162                 return;
00163         }
00164 
00165         /* drop acknowledgements */
00166         while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
00167                 if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
00168                         outw(TX_RESET, nic->ioaddr + EP_COMMAND);
00169                         outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
00170                 }
00171                 outb(0x0, nic->ioaddr + EP_W1_TX_STATUS);
00172         }
00173 
00174         while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
00175                 ; /* no room in FIFO */
00176 
00177         outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1);
00178         outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1);     /* Second dword meaningless */
00179 
00180         /* write packet */
00181         outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
00182         outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
00183         outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1);
00184         outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2);
00185         if (s & 1)
00186                 outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1);
00187 
00188         while (pad--)
00189                 outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1);       /* Padding */
00190 
00191         /* wait for Tx complete */
00192         while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
00193                 ;
00194 }

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, nic::ioaddr, outw, nic::packet, nic::packetlen, printf(), RX_BYTES_MASK, RX_DISCARD_TOP_PACK, RX_INCOMPLETE, S_5_INTS, S_COMMAND_IN_PROGRESS, S_RX_COMPLETE, and udelay().

00200 {
00201         /* common variables */
00202         /* variables for 3C509 */
00203         short status, cst;
00204         register short rx_fifo;
00205 
00206         cst=inw(nic->ioaddr + EP_STATUS);
00207 
00208 #ifdef  EDEBUG
00209         if(cst & 0x1FFF)
00210                 printf("-%hX-",cst);
00211 #endif
00212 
00213         if( (cst & S_RX_COMPLETE)==0 ) {
00214                 /* acknowledge  everything */
00215                 outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND);
00216                 outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
00217 
00218                 return 0;
00219         }
00220 
00221         status = inw(nic->ioaddr + EP_W1_RX_STATUS);
00222 #ifdef  EDEBUG
00223         printf("*%hX*",status);
00224 #endif
00225 
00226         if (status & ERR_RX) {
00227                 outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
00228                 return 0;
00229         }
00230 
00231         rx_fifo = status & RX_BYTES_MASK;
00232         if (rx_fifo==0)
00233                 return 0;
00234 
00235         if ( ! retrieve ) return 1;
00236 
00237                 /* read packet */
00238 #ifdef  EDEBUG
00239         printf("[l=%d",rx_fifo);
00240 #endif
00241         insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
00242         if(rx_fifo & 1)
00243                 nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
00244         nic->packetlen=rx_fifo;
00245 
00246         while(1) {
00247                 status = inw(nic->ioaddr + EP_W1_RX_STATUS);
00248 #ifdef  EDEBUG
00249                 printf("*%hX*",status);
00250 #endif
00251                 rx_fifo = status & RX_BYTES_MASK;
00252                 if(rx_fifo>0) {
00253                         insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
00254                         if(rx_fifo & 1)
00255                                 nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
00256                         nic->packetlen+=rx_fifo;
00257 #ifdef  EDEBUG
00258                         printf("+%d",rx_fifo);
00259 #endif
00260                 }
00261                 if(( status & RX_INCOMPLETE )==0) {
00262 #ifdef  EDEBUG
00263                         printf("=%d",nic->packetlen);
00264 #endif
00265                         break;
00266                 }
00267                 udelay(1000);   /* if incomplete wait 1 ms */
00268         }
00269         /* acknowledge reception of packet */
00270         outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
00271         while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
00272                 ;
00273 #ifdef  EDEBUG
00274 {
00275         unsigned short type = 0;        /* used by EDEBUG */
00276         type = (nic->packet[12]<<8) | nic->packet[13];
00277         if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
00278             nic->packet[5] == 0xFF*ETH_ALEN)
00279                 printf(",t=%hX,b]",type);
00280         else
00281                 printf(",t=%hX]",type);
00282 }
00283 #endif
00284         return (1);
00285 }

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

Definition at line 290 of file 3c5x9.c.

References DISABLE, ENABLE, and FORCE.

00291 {
00292   switch ( action ) {
00293   case DISABLE :
00294     break;
00295   case ENABLE :
00296     break;
00297   case FORCE :
00298     break;
00299   }
00300 }

static int eeprom_rdy ( uint16_t  ioaddr  )  [static]

Definition at line 306 of file 3c5x9.c.

References is_eeprom_busy, and MAX_EEPROMBUSY.

00306                                           {
00307         int i;
00308 
00309         for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++);
00310         if (i >= MAX_EEPROMBUSY) {
00311                 /* printf("3c509: eeprom failed to come ready.\n"); */
00312                 /* memory in EPROM is tight */
00313                 /* printf("3c509: eeprom busy.\n"); */
00314                 return (0);
00315         }
00316         return (1);
00317 }

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.

00322                                                  {
00323         GO_WINDOW(ioaddr,0);
00324         if (!eeprom_rdy(ioaddr))
00325                 return (0xffff);
00326         outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND);
00327         if (!eeprom_rdy(ioaddr))
00328                 return (0xffff);
00329         return (inw(ioaddr + EP_W0_EEPROM_DATA));
00330 }

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, nic::ioaddr, IS_AUI, IS_BNC, IS_UTP, nic::nic_op, nic::node_addr, ntohs, outw, printf(), t509_reset(), and utp.

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

00343                                                                  {
00344         uint16_t prod_id;
00345         int i,j;
00346         unsigned short *p;
00347         
00348         /* Check product ID */
00349         prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID );
00350         if ( ( prod_id & prod_id_mask ) != prod_id_check ) {
00351                 printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n",
00352                          prod_id, prod_id_mask, prod_id_check );
00353                 return 0;
00354         }
00355 
00356         /* test for presence of connectors */
00357         GO_WINDOW(nic->ioaddr,0);
00358         i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL);
00359         j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
00360 
00361         switch(j) {
00362         case 0:
00363                 if (i & IS_UTP) {
00364                         printf("10baseT\n");
00365                         connector = utp;
00366                 } else {
00367                         printf("10baseT not present\n");
00368                         return 0;
00369                 }
00370                 break;
00371         case 1:
00372                 if (i & IS_AUI) {
00373                         printf("10base5\n");
00374                 } else {
00375                         printf("10base5 not present\n");
00376                         return 0;
00377                 }
00378                 break;
00379         case 3:
00380                 if (i & IS_BNC) {
00381                         printf("10base2\n");
00382                         connector = bnc;
00383                 } else {
00384                         printf("10base2 not present\n");
00385                         return 0;
00386                 }
00387                 break;
00388         default:
00389                 printf("unknown connector\n");
00390                 return 0;
00391         }
00392 
00393         /*
00394         * Read the station address from the eeprom
00395         */
00396         p = (unsigned short *) nic->node_addr;
00397         for (i = 0; i < ETH_ALEN / 2; i++) {
00398                 p[i] = htons(get_e(nic->ioaddr,i));
00399                 GO_WINDOW(nic->ioaddr,2);
00400                 outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2));
00401         }
00402 
00403         DBG ( "Ethernet Address: %s\n", eth_ntoa ( nic->node_addr ) );
00404 
00405         t509_reset(nic);
00406 
00407         nic->nic_op = &t509_operations;
00408         return 1;
00409 
00410 }


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.

Initial value:

 {
        .connect        = dummy_connect,
        .poll           = t509_poll,
        .transmit       = t509_transmit,
        .irq            = t509_irq,
}

Definition at line 332 of file 3c5x9.c.


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