"Fossies" - the Fresh Open Source Software Archive

Member "syslinux-6.03/gpxe/src/drivers/net/3c595.c" (6 Oct 2014, 14025 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 * 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
    3 *
    4 * Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
    5 * All rights reserved.
    6 * Mar. 14, 2000
    7 *
    8 *  This software may be used, modified, copied, distributed, and sold, in
    9 *  both source and binary form provided that the above copyright and these
   10 *  terms are retained. Under no circumstances are the authors responsible for
   11 *  the proper functioning of this software, nor do the authors assume any
   12 *  responsibility for damages incurred with its use.
   13 *
   14 * This code is based on Martin Renters' etherboot-4.4.3 3c509.c and 
   15 * Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
   16 *
   17 *  Copyright (C) 1993-1994, David Greenman, Martin Renters.
   18 *  Copyright (C) 1993-1995, Andres Vega Garcia.
   19 *  Copyright (C) 1995, Serge Babkin.
   20 *
   21 *  Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
   22 *
   23 * timlegge  08-24-2003  Add Multicast Support
   24 */
   25 
   26 FILE_LICENCE ( BSD2 );
   27 
   28 /* #define EDEBUG */
   29 
   30 #include "etherboot.h"
   31 #include "nic.h"
   32 #include <gpxe/pci.h>
   33 #include <gpxe/ethernet.h>
   34 #include "3c595.h"
   35 
   36 static struct nic_operations t595_operations;
   37 
   38 static unsigned short   eth_nic_base;
   39 static unsigned short   vx_connector, vx_connectors;
   40 
   41 static struct connector_entry {
   42   int bit;
   43   char *name;
   44 } conn_tab[VX_CONNECTORS] = {
   45 #define CONNECTOR_UTP   0
   46   { 0x08, "utp"},
   47 #define CONNECTOR_AUI   1
   48   { 0x20, "aui"},
   49 /* dummy */
   50   { 0, "???"},
   51 #define CONNECTOR_BNC   3
   52   { 0x10, "bnc"},
   53 #define CONNECTOR_TX    4
   54   { 0x02, "tx"},
   55 #define CONNECTOR_FX    5
   56   { 0x04, "fx"},
   57 #define CONNECTOR_MII   6
   58   { 0x40, "mii"},
   59   { 0, "???"}
   60 };
   61 
   62 static void vxgetlink(void);
   63 static void vxsetlink(void);
   64 
   65 /**************************************************************************
   66 ETH_RESET - Reset adapter
   67 ***************************************************************************/
   68 static void t595_reset(struct nic *nic)
   69 {
   70     int i;
   71 
   72     /***********************************************************
   73             Reset 3Com 595 card
   74     *************************************************************/
   75 
   76     /* stop card */
   77     outw(RX_DISABLE, BASE + VX_COMMAND);
   78     outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
   79     VX_BUSY_WAIT;
   80     outw(TX_DISABLE, BASE + VX_COMMAND);
   81     outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
   82     udelay(8000);
   83     outw(RX_RESET, BASE + VX_COMMAND);
   84     VX_BUSY_WAIT;
   85     outw(TX_RESET, BASE + VX_COMMAND);
   86     VX_BUSY_WAIT;
   87     outw(C_INTR_LATCH, BASE + VX_COMMAND);
   88     outw(SET_RD_0_MASK, BASE + VX_COMMAND);
   89     outw(SET_INTR_MASK, BASE + VX_COMMAND);
   90     outw(SET_RX_FILTER, BASE + VX_COMMAND);
   91 
   92     /*
   93     * initialize card
   94     */
   95     VX_BUSY_WAIT;
   96 
   97     GO_WINDOW(0);
   98 
   99     /* Disable the card */
  100 /*  outw(0, BASE + VX_W0_CONFIG_CTRL); */
  101 
  102     /* Configure IRQ to none */
  103 /*  outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
  104 
  105     /* Enable the card */
  106 /*  outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
  107 
  108     GO_WINDOW(2);
  109 
  110     /* Reload the ether_addr. */
  111     for (i = 0; i < ETH_ALEN; i++)
  112         outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
  113 
  114     outw(RX_RESET, BASE + VX_COMMAND);
  115     VX_BUSY_WAIT;
  116     outw(TX_RESET, BASE + VX_COMMAND);
  117     VX_BUSY_WAIT;
  118 
  119     /* Window 1 is operating window */
  120     GO_WINDOW(1);
  121     for (i = 0; i < 31; i++)
  122         inb(BASE + VX_W1_TX_STATUS);
  123 
  124     outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
  125         S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
  126     outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
  127         S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
  128 
  129 /*
  130  * Attempt to get rid of any stray interrupts that occured during
  131  * configuration.  On the i386 this isn't possible because one may
  132  * already be queued.  However, a single stray interrupt is
  133  * unimportant.
  134  */
  135 
  136     outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
  137 
  138     outw(SET_RX_FILTER | FIL_INDIVIDUAL |
  139         FIL_BRDCST|FIL_MULTICAST, BASE + VX_COMMAND);
  140 
  141     vxsetlink();
  142 /*{
  143     int i,j;
  144     i = CONNECTOR_TX;
  145     GO_WINDOW(3);
  146     j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
  147     outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
  148         GO_WINDOW(4);
  149         outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
  150         GO_WINDOW(1);
  151 }*/
  152 
  153     /* start tranciever and receiver */
  154     outw(RX_ENABLE, BASE + VX_COMMAND);
  155     outw(TX_ENABLE, BASE + VX_COMMAND);
  156 
  157 }
  158 
  159 /**************************************************************************
  160 ETH_TRANSMIT - Transmit a frame
  161 ***************************************************************************/
  162 static char padmap[] = {
  163     0, 3, 2, 1};
  164 
  165 static void t595_transmit(
  166 struct nic *nic,
  167 const char *d,          /* Destination */
  168 unsigned int t,         /* Type */
  169 unsigned int s,         /* size */
  170 const char *p)          /* Packet */
  171 {
  172     register int len;
  173     int pad;
  174     int status;
  175 
  176 #ifdef EDEBUG
  177     printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
  178 #endif
  179 
  180     /* swap bytes of type */
  181     t= htons(t);
  182 
  183     len=s+ETH_HLEN; /* actual length of packet */
  184     pad = padmap[len & 3];
  185 
  186     /*
  187     * The 3c595 automatically pads short packets to minimum ethernet length,
  188     * but we drop packets that are too large. Perhaps we should truncate
  189     * them instead?
  190     */
  191     if (len + pad > ETH_FRAME_LEN) {
  192         return;
  193     }
  194 
  195     /* drop acknowledgements */
  196     while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
  197         if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
  198             outw(TX_RESET, BASE + VX_COMMAND);
  199             outw(TX_ENABLE, BASE + VX_COMMAND);
  200         }
  201 
  202         outb(0x0, BASE + VX_W1_TX_STATUS);
  203     }
  204 
  205     while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
  206         /* no room in FIFO */
  207     }
  208 
  209     outw(len, BASE + VX_W1_TX_PIO_WR_1);
  210     outw(0x0, BASE + VX_W1_TX_PIO_WR_1);    /* Second dword meaningless */
  211 
  212     /* write packet */
  213     outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
  214     outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
  215     outw(t, BASE + VX_W1_TX_PIO_WR_1);
  216     outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
  217     if (s & 1)
  218         outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
  219 
  220     while (pad--)
  221         outb(0, BASE + VX_W1_TX_PIO_WR_1);  /* Padding */
  222 
  223         /* wait for Tx complete */
  224         while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
  225                 ;
  226 }
  227 
  228 /**************************************************************************
  229 ETH_POLL - Wait for a frame
  230 ***************************************************************************/
  231 static int t595_poll(struct nic *nic, int retrieve)
  232 {
  233     /* common variables */
  234     /* variables for 3C595 */
  235     short status, cst;
  236     register short rx_fifo;
  237 
  238     cst=inw(BASE + VX_STATUS);
  239 
  240 #ifdef EDEBUG
  241     if(cst & 0x1FFF)
  242         printf("-%hX-",cst);
  243 #endif
  244 
  245     if( (cst & S_RX_COMPLETE)==0 ) {
  246         /* acknowledge  everything */
  247         outw(ACK_INTR | cst, BASE + VX_COMMAND);
  248         outw(C_INTR_LATCH, BASE + VX_COMMAND);
  249 
  250         return 0;
  251     }
  252 
  253     status = inw(BASE + VX_W1_RX_STATUS);
  254 #ifdef EDEBUG
  255     printf("*%hX*",status);
  256 #endif
  257 
  258     if (status & ERR_RX) {
  259         outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
  260         return 0;
  261     }
  262 
  263     rx_fifo = status & RX_BYTES_MASK;
  264     if (rx_fifo==0)
  265         return 0;
  266 
  267     if ( ! retrieve ) return 1;
  268 
  269         /* read packet */
  270 #ifdef EDEBUG
  271     printf("[l=%d",rx_fifo);
  272 #endif
  273     insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
  274     if(rx_fifo & 1)
  275         nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
  276     nic->packetlen=rx_fifo;
  277 
  278     while(1) {
  279         status = inw(BASE + VX_W1_RX_STATUS);
  280 #ifdef EDEBUG
  281         printf("*%hX*",status);
  282 #endif
  283         rx_fifo = status & RX_BYTES_MASK;
  284 
  285         if(rx_fifo>0) {
  286             insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
  287             if(rx_fifo & 1)
  288                 nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
  289             nic->packetlen+=rx_fifo;
  290 #ifdef EDEBUG
  291             printf("+%d",rx_fifo);
  292 #endif
  293         }
  294         if(( status & RX_INCOMPLETE )==0) {
  295 #ifdef EDEBUG
  296             printf("=%d",nic->packetlen);
  297 #endif
  298             break;
  299         }
  300         udelay(1000);
  301     }
  302 
  303     /* acknowledge reception of packet */
  304     outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
  305     while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
  306 #ifdef EDEBUG
  307 {
  308     unsigned short type = 0;    /* used by EDEBUG */
  309     type = (nic->packet[12]<<8) | nic->packet[13];
  310     if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
  311         nic->packet[5] == 0xFF*ETH_ALEN)
  312         printf(",t=%hX,b]",type);
  313     else
  314         printf(",t=%hX]",type);
  315 }
  316 #endif
  317     return 1;
  318 }
  319 
  320 
  321 /*************************************************************************
  322     3Com 595 - specific routines
  323 **************************************************************************/
  324 
  325 static int
  326 eeprom_rdy()
  327 {
  328     int i;
  329 
  330     for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
  331         udelay(1000);
  332     if (i >= MAX_EEPROMBUSY) {
  333             /* printf("3c595: eeprom failed to come ready.\n"); */
  334         printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
  335         return (0);
  336     }
  337     return (1);
  338 }
  339 
  340 /*
  341  * get_e: gets a 16 bits word from the EEPROM. we must have set the window
  342  * before
  343  */
  344 static int
  345 get_e(offset)
  346 int offset;
  347 {
  348     if (!eeprom_rdy())
  349         return (0xffff);
  350     outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
  351     if (!eeprom_rdy())
  352         return (0xffff);
  353     return (inw(BASE + VX_W0_EEPROM_DATA));
  354 }
  355 
  356 static void            
  357 vxgetlink(void)
  358 {
  359     int n, k;
  360 
  361     GO_WINDOW(3);
  362     vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
  363     for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
  364       if (vx_connectors & conn_tab[k].bit) {
  365         if (n > 0) {
  366           printf("/");
  367     }
  368         printf("%s", conn_tab[k].name );
  369         n++;
  370       }
  371     }
  372     if (vx_connectors == 0) {
  373         printf("no connectors!");
  374         return;
  375     }
  376     GO_WINDOW(3);
  377     vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 
  378                         & INTERNAL_CONNECTOR_MASK) 
  379                         >> INTERNAL_CONNECTOR_BITS;
  380     if (vx_connector & 0x10) {
  381         vx_connector &= 0x0f;
  382         printf("[*%s*]", conn_tab[vx_connector].name);
  383         printf(": disable 'auto select' with DOS util!");
  384     } else {
  385         printf("[*%s*]", conn_tab[vx_connector].name);
  386     }
  387 }
  388 
  389 static void            
  390 vxsetlink(void)
  391 {       
  392     int i, j;
  393     char *reason, *warning;
  394     static char prev_conn = -1;
  395 
  396     if (prev_conn == -1) {
  397         prev_conn = vx_connector;
  398     }
  399 
  400     i = vx_connector;       /* default in EEPROM */
  401     reason = "default";
  402     warning = 0;
  403 
  404     if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
  405         warning = "strange connector type in EEPROM.";
  406         reason = "forced";
  407         i = CONNECTOR_UTP;
  408     }
  409 
  410         if (warning != 0) {
  411             printf("warning: %s\n", warning);
  412         }
  413         printf("selected %s. (%s)\n", conn_tab[i].name, reason);
  414 
  415     /* Set the selected connector. */
  416     GO_WINDOW(3);
  417     j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
  418     outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
  419 
  420     /* First, disable all. */
  421     outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
  422     udelay(8000);
  423     GO_WINDOW(4);
  424     outw(0, BASE + VX_W4_MEDIA_TYPE);
  425 
  426     /* Second, enable the selected one. */
  427     switch(i) {
  428       case CONNECTOR_UTP:
  429         GO_WINDOW(4);
  430         outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
  431         break;
  432       case CONNECTOR_BNC:
  433         outw(START_TRANSCEIVER,BASE + VX_COMMAND);
  434         udelay(8000);
  435         break;
  436       case CONNECTOR_TX:
  437       case CONNECTOR_FX:
  438         GO_WINDOW(4);
  439         outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
  440         break;
  441       default:  /* AUI and MII fall here */
  442         break;
  443     }
  444     GO_WINDOW(1); 
  445 }
  446 
  447 static void t595_disable ( struct nic *nic ) {
  448 
  449     t595_reset(nic);
  450 
  451     outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
  452     udelay(8000);
  453     GO_WINDOW(4);
  454     outw(0, BASE + VX_W4_MEDIA_TYPE);
  455     GO_WINDOW(1);
  456 }
  457 
  458 static void t595_irq(struct nic *nic __unused, irq_action_t action __unused)
  459 {
  460   switch ( action ) {
  461   case DISABLE :
  462     break;
  463   case ENABLE :
  464     break;
  465   case FORCE :
  466     break;
  467   }
  468 }
  469 
  470 /**************************************************************************
  471 ETH_PROBE - Look for an adapter
  472 ***************************************************************************/
  473 static int t595_probe ( struct nic *nic, struct pci_device *pci ) {
  474 
  475     int i;
  476     unsigned short *p;
  477 
  478     if (pci->ioaddr == 0)
  479         return 0;
  480     eth_nic_base = pci->ioaddr;
  481 
  482     nic->irqno  = 0;
  483     nic->ioaddr = pci->ioaddr;
  484 
  485     GO_WINDOW(0);
  486     outw(GLOBAL_RESET, BASE + VX_COMMAND);
  487     VX_BUSY_WAIT;
  488 
  489     vxgetlink();
  490 
  491 /*
  492     printf("\nEEPROM:");
  493     for (i = 0; i < (EEPROMSIZE/2); i++) {
  494       printf("%hX:", get_e(i));
  495     }
  496     printf("\n");
  497 */
  498     /*
  499     * Read the station address from the eeprom
  500     */
  501     p = (unsigned short *) nic->node_addr;
  502     for (i = 0; i < 3; i++) {
  503         GO_WINDOW(0);
  504         p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
  505         GO_WINDOW(2);
  506         outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
  507     }
  508 
  509     DBG ( "Ethernet address: %s\n", eth_ntoa (nic->node_addr) );
  510 
  511     t595_reset(nic);
  512     nic->nic_op = &t595_operations;
  513     return 1;
  514 
  515 }
  516 
  517 static struct nic_operations t595_operations = {
  518     .connect    = dummy_connect,
  519     .poll       = t595_poll,
  520     .transmit   = t595_transmit,
  521     .irq        = t595_irq,
  522 
  523 };
  524 
  525 static struct pci_device_id t595_nics[] = {
  526 PCI_ROM(0x10b7, 0x5900, "3c590",           "3Com590", 0),       /* Vortex 10Mbps */
  527 PCI_ROM(0x10b7, 0x5950, "3c595",           "3Com595", 0),       /* Vortex 100baseTx */
  528 PCI_ROM(0x10b7, 0x5951, "3c595-1",         "3Com595", 0),       /* Vortex 100baseT4 */
  529 PCI_ROM(0x10b7, 0x5952, "3c595-2",         "3Com595", 0),       /* Vortex 100base-MII */
  530 PCI_ROM(0x10b7, 0x9000, "3c900-tpo",       "3Com900-TPO", 0),   /* 10 Base TPO */
  531 PCI_ROM(0x10b7, 0x9001, "3c900-t4",        "3Com900-Combo", 0), /* 10/100 T4 */
  532 PCI_ROM(0x10b7, 0x9004, "3c900b-tpo",      "3Com900B-TPO", 0),  /* 10 Base TPO */
  533 PCI_ROM(0x10b7, 0x9005, "3c900b-combo",    "3Com900B-Combo", 0),    /* 10 Base Combo */
  534 PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2",     "3Com900B-2/T", 0),  /* 10 Base TP and Base2 */
  535 PCI_ROM(0x10b7, 0x900a, "3c900b-fl",       "3Com900B-FL", 0),   /* 10 Base F */
  536 PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone", 0),   /* Cyclone */
  537 PCI_ROM(0x10b7, 0x9805, "3c9805-1",        "3Com9805", 0),      /* Dual Port Server Cyclone */
  538 PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1",  "3CSOHO100-TX", 0),  /* Hurricane */
  539 PCI_ROM(0x10b7, 0x4500, "3c450-1",         "3Com450 HomePNA Tornado", 0),
  540 };
  541 
  542 PCI_DRIVER ( t595_driver, t595_nics, PCI_NO_CLASS );
  543 
  544 DRIVER ( "3C595", nic_driver, pci_driver, t595_driver,
  545      t595_probe, t595_disable );
  546 
  547 /*
  548  * Local variables:
  549  *  c-basic-offset: 8
  550  *  c-indent-level: 8
  551  *  tab-width: 8
  552  * End:
  553  */