"Fossies" - the Fresh Open Source Software Archive

Member "syslinux-6.03/gpxe/src/drivers/net/3c5x9.c" (6 Oct 2014, 10823 Bytes) of package /linux/misc/syslinux-6.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**************************************************************************
    2 ETHERBOOT -  BOOTP/TFTP Bootstrap Program
    3 
    4 Author: Martin Renters.
    5   Date: Mar 22 1995
    6 
    7  This code is based heavily on David Greenman's if_ed.c driver and
    8   Andres Vega Garcia's if_ep.c driver.
    9 
   10  Copyright (C) 1993-1994, David Greenman, Martin Renters.
   11  Copyright (C) 1993-1995, Andres Vega Garcia.
   12  Copyright (C) 1995, Serge Babkin.
   13   This software may be used, modified, copied, distributed, and sold, in
   14   both source and binary form provided that the above copyright and these
   15   terms are retained. Under no circumstances are the authors responsible for
   16   the proper functioning of this software, nor do the authors assume any
   17   responsibility for damages incurred with its use.
   18 
   19 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
   20 
   21 $Id$
   22 
   23 ***************************************************************************/
   24 
   25 FILE_LICENCE ( BSD2 );
   26 
   27 /* #define EDEBUG */
   28 
   29 #include <gpxe/ethernet.h>
   30 #include "etherboot.h"
   31 #include "nic.h"
   32 #include <gpxe/isa.h>
   33 #include "3c509.h"
   34 
   35 static enum { none, bnc, utp } connector = none;    /* for 3C509 */
   36 
   37 /**************************************************************************
   38 ETH_RESET - Reset adapter
   39 ***************************************************************************/
   40 void t5x9_disable ( struct nic *nic ) {
   41     /* stop card */
   42     outw(RX_DISABLE, nic->ioaddr + EP_COMMAND);
   43     outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
   44     while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
   45         ;
   46     outw(TX_DISABLE, nic->ioaddr + EP_COMMAND);
   47     outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
   48     udelay(1000);
   49     outw(RX_RESET, nic->ioaddr + EP_COMMAND);
   50     outw(TX_RESET, nic->ioaddr + EP_COMMAND);
   51     outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
   52     outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND);
   53     outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
   54     outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND);
   55 
   56     /*
   57      * wait for reset to complete
   58      */
   59     while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
   60         ;
   61 
   62     GO_WINDOW(nic->ioaddr,0);
   63 
   64     /* Disable the card */
   65     outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL);
   66 
   67     /* Configure IRQ to none */
   68     outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG);
   69 }
   70 
   71 static void t509_enable ( struct nic *nic ) {
   72     int i;
   73 
   74     /* Enable the card */
   75     GO_WINDOW(nic->ioaddr,0);
   76     outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL);
   77 
   78     GO_WINDOW(nic->ioaddr,2);
   79 
   80     /* Reload the ether_addr. */
   81     for (i = 0; i < ETH_ALEN; i++)
   82         outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i);
   83 
   84     outw(RX_RESET, nic->ioaddr + EP_COMMAND);
   85     outw(TX_RESET, nic->ioaddr + EP_COMMAND);
   86 
   87     /* Window 1 is operating window */
   88     GO_WINDOW(nic->ioaddr,1);
   89     for (i = 0; i < 31; i++)
   90         inb(nic->ioaddr + EP_W1_TX_STATUS);
   91 
   92     /* get rid of stray intr's */
   93     outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);
   94 
   95     outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND);
   96 
   97     outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
   98 
   99     outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST,
  100          nic->ioaddr + EP_COMMAND);
  101 
  102     /* configure BNC */
  103     if (connector == bnc) {
  104         outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
  105         udelay(1000);
  106     }
  107     /* configure UTP */
  108     else if (connector == utp) {
  109         GO_WINDOW(nic->ioaddr,4);
  110         outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE);
  111         sleep(2);   /* Give time for media to negotiate */
  112         GO_WINDOW(nic->ioaddr,1);
  113     }
  114 
  115     /* start transceiver and receiver */
  116     outw(RX_ENABLE, nic->ioaddr + EP_COMMAND);
  117     outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
  118 
  119     /* set early threshold for minimal packet length */
  120     outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND);
  121     outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND);
  122 }
  123 
  124 static void t509_reset ( struct nic *nic ) {
  125     t5x9_disable ( nic );
  126     t509_enable ( nic );
  127 }    
  128 
  129 /**************************************************************************
  130 ETH_TRANSMIT - Transmit a frame
  131 ***************************************************************************/
  132 static char padmap[] = {
  133     0, 3, 2, 1};
  134 
  135 static void t509_transmit(
  136 struct nic *nic,
  137 const char *d,          /* Destination */
  138 unsigned int t,         /* Type */
  139 unsigned int s,         /* size */
  140 const char *p)          /* Packet */
  141 {
  142     register unsigned int len;
  143     int pad;
  144     int status;
  145 
  146 #ifdef  EDEBUG
  147     printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
  148 #endif
  149 
  150     /* swap bytes of type */
  151     t= htons(t);
  152 
  153     len=s+ETH_HLEN; /* actual length of packet */
  154     pad = padmap[len & 3];
  155 
  156     /*
  157     * The 3c509 automatically pads short packets to minimum ethernet length,
  158     * but we drop packets that are too large. Perhaps we should truncate
  159     * them instead?
  160     */
  161     if (len + pad > ETH_FRAME_LEN) {
  162         return;
  163     }
  164 
  165     /* drop acknowledgements */
  166     while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
  167         if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
  168             outw(TX_RESET, nic->ioaddr + EP_COMMAND);
  169             outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
  170         }
  171         outb(0x0, nic->ioaddr + EP_W1_TX_STATUS);
  172     }
  173 
  174     while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
  175         ; /* no room in FIFO */
  176 
  177     outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1);
  178     outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */
  179 
  180     /* write packet */
  181     outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
  182     outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
  183     outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1);
  184     outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2);
  185     if (s & 1)
  186         outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1);
  187 
  188     while (pad--)
  189         outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1);   /* Padding */
  190 
  191     /* wait for Tx complete */
  192     while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
  193         ;
  194 }
  195 
  196 /**************************************************************************
  197 ETH_POLL - Wait for a frame
  198 ***************************************************************************/
  199 static int t509_poll(struct nic *nic, int retrieve)
  200 {
  201     /* common variables */
  202     /* variables for 3C509 */
  203     short status, cst;
  204     register short rx_fifo;
  205 
  206     cst=inw(nic->ioaddr + EP_STATUS);
  207 
  208 #ifdef  EDEBUG
  209     if(cst & 0x1FFF)
  210         printf("-%hX-",cst);
  211 #endif
  212 
  213     if( (cst & S_RX_COMPLETE)==0 ) {
  214         /* acknowledge  everything */
  215         outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND);
  216         outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
  217 
  218         return 0;
  219     }
  220 
  221     status = inw(nic->ioaddr + EP_W1_RX_STATUS);
  222 #ifdef  EDEBUG
  223     printf("*%hX*",status);
  224 #endif
  225 
  226     if (status & ERR_RX) {
  227         outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
  228         return 0;
  229     }
  230 
  231     rx_fifo = status & RX_BYTES_MASK;
  232     if (rx_fifo==0)
  233         return 0;
  234 
  235     if ( ! retrieve ) return 1;
  236 
  237         /* read packet */
  238 #ifdef  EDEBUG
  239     printf("[l=%d",rx_fifo);
  240 #endif
  241     insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
  242     if(rx_fifo & 1)
  243         nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
  244     nic->packetlen=rx_fifo;
  245 
  246     while(1) {
  247         status = inw(nic->ioaddr + EP_W1_RX_STATUS);
  248 #ifdef  EDEBUG
  249         printf("*%hX*",status);
  250 #endif
  251         rx_fifo = status & RX_BYTES_MASK;
  252         if(rx_fifo>0) {
  253             insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
  254             if(rx_fifo & 1)
  255                 nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
  256             nic->packetlen+=rx_fifo;
  257 #ifdef  EDEBUG
  258             printf("+%d",rx_fifo);
  259 #endif
  260         }
  261         if(( status & RX_INCOMPLETE )==0) {
  262 #ifdef  EDEBUG
  263             printf("=%d",nic->packetlen);
  264 #endif
  265             break;
  266         }
  267         udelay(1000);   /* if incomplete wait 1 ms */
  268     }
  269     /* acknowledge reception of packet */
  270     outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
  271     while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
  272         ;
  273 #ifdef  EDEBUG
  274 {
  275     unsigned short type = 0;    /* used by EDEBUG */
  276     type = (nic->packet[12]<<8) | nic->packet[13];
  277     if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
  278         nic->packet[5] == 0xFF*ETH_ALEN)
  279         printf(",t=%hX,b]",type);
  280     else
  281         printf(",t=%hX]",type);
  282 }
  283 #endif
  284     return (1);
  285 }
  286 
  287 /**************************************************************************
  288 ETH_IRQ - interrupt handling
  289 ***************************************************************************/
  290 static void t509_irq(struct nic *nic __unused, irq_action_t action __unused)
  291 {
  292   switch ( action ) {
  293   case DISABLE :
  294     break;
  295   case ENABLE :
  296     break;
  297   case FORCE :
  298     break;
  299   }
  300 }
  301 
  302 /*************************************************************************
  303     3Com 509 - specific routines
  304 **************************************************************************/
  305 
  306 static int eeprom_rdy ( uint16_t ioaddr ) {
  307     int i;
  308 
  309     for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++);
  310     if (i >= MAX_EEPROMBUSY) {
  311         /* printf("3c509: eeprom failed to come ready.\n"); */
  312         /* memory in EPROM is tight */
  313         /* printf("3c509: eeprom busy.\n"); */
  314         return (0);
  315     }
  316     return (1);
  317 }
  318 
  319 /*
  320  * get_e: gets a 16 bits word from the EEPROM.
  321  */
  322 static int get_e ( uint16_t ioaddr, int offset ) {
  323     GO_WINDOW(ioaddr,0);
  324     if (!eeprom_rdy(ioaddr))
  325         return (0xffff);
  326     outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND);
  327     if (!eeprom_rdy(ioaddr))
  328         return (0xffff);
  329     return (inw(ioaddr + EP_W0_EEPROM_DATA));
  330 }
  331 
  332 static struct nic_operations t509_operations = {
  333     .connect    = dummy_connect,
  334     .poll       = t509_poll,
  335     .transmit   = t509_transmit,
  336     .irq        = t509_irq,
  337 };
  338 
  339 /**************************************************************************
  340 ETH_PROBE - Look for an adapter
  341 ***************************************************************************/
  342 int t5x9_probe ( struct nic *nic,
  343          uint16_t prod_id_check, uint16_t prod_id_mask ) {
  344     uint16_t prod_id;
  345     int i,j;
  346     unsigned short *p;
  347     
  348     /* Check product ID */
  349     prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID );
  350     if ( ( prod_id & prod_id_mask ) != prod_id_check ) {
  351         printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n",
  352              prod_id, prod_id_mask, prod_id_check );
  353         return 0;
  354     }
  355 
  356     /* test for presence of connectors */
  357     GO_WINDOW(nic->ioaddr,0);
  358     i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL);
  359     j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
  360 
  361     switch(j) {
  362     case 0:
  363         if (i & IS_UTP) {
  364             printf("10baseT\n");
  365             connector = utp;
  366         } else {
  367             printf("10baseT not present\n");
  368             return 0;
  369         }
  370         break;
  371     case 1:
  372         if (i & IS_AUI) {
  373             printf("10base5\n");
  374         } else {
  375             printf("10base5 not present\n");
  376             return 0;
  377         }
  378         break;
  379     case 3:
  380         if (i & IS_BNC) {
  381             printf("10base2\n");
  382             connector = bnc;
  383         } else {
  384             printf("10base2 not present\n");
  385             return 0;
  386         }
  387         break;
  388     default:
  389         printf("unknown connector\n");
  390         return 0;
  391     }
  392 
  393     /*
  394     * Read the station address from the eeprom
  395     */
  396     p = (unsigned short *) nic->node_addr;
  397     for (i = 0; i < ETH_ALEN / 2; i++) {
  398         p[i] = htons(get_e(nic->ioaddr,i));
  399         GO_WINDOW(nic->ioaddr,2);
  400         outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2));
  401     }
  402 
  403     DBG ( "Ethernet Address: %s\n", eth_ntoa ( nic->node_addr ) );
  404 
  405     t509_reset(nic);
  406 
  407     nic->nic_op = &t509_operations;
  408     return 1;
  409 
  410 }
  411 
  412 /*
  413  * Local variables:
  414  *  c-basic-offset: 8
  415  * End:
  416  */