Home | History | Annotate | Download | only in net
      1 /*
      2 * 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
      3 *
      4 * Copyright (C) 2000 Shusuke Nisiyama <shu (at) 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 (at) 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  */
    554