Home | History | Annotate | Download | only in netboot
      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 */
     24 
     25 /* #define EDEBUG */
     26 
     27 #include "etherboot.h"
     28 #include "nic.h"
     29 #include "pci.h"
     30 #include "3c595.h"
     31 #include "timer.h"
     32 
     33 static unsigned short	eth_nic_base, eth_asic_base;
     34 static unsigned short	vx_connector, vx_connectors;
     35 
     36 static struct connector_entry {
     37   int bit;
     38   char *name;
     39 } conn_tab[VX_CONNECTORS] = {
     40 #define CONNECTOR_UTP   0
     41   { 0x08, "utp"},
     42 #define CONNECTOR_AUI   1
     43   { 0x20, "aui"},
     44 /* dummy */
     45   { 0, "???"},
     46 #define CONNECTOR_BNC   3
     47   { 0x10, "bnc"},
     48 #define CONNECTOR_TX    4
     49   { 0x02, "tx"},
     50 #define CONNECTOR_FX    5
     51   { 0x04, "fx"},
     52 #define CONNECTOR_MII   6
     53   { 0x40, "mii"},
     54   { 0, "???"}
     55 };
     56 
     57 static void vxgetlink(void);
     58 static void vxsetlink(void);
     59 
     60 #define	udelay(n)	waiton_timer2(((n)*TICKS_PER_MS)/1000)
     61 
     62 /**************************************************************************
     63 ETH_RESET - Reset adapter
     64 ***************************************************************************/
     65 static void t595_reset(struct nic *nic)
     66 {
     67 	int i, j;
     68 
     69 	/***********************************************************
     70 			Reset 3Com 595 card
     71 	*************************************************************/
     72 
     73 	/* stop card */
     74 	outw(RX_DISABLE, BASE + VX_COMMAND);
     75 	outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
     76 	VX_BUSY_WAIT;
     77 	outw(TX_DISABLE, BASE + VX_COMMAND);
     78 	outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
     79 	udelay(8000);
     80 	outw(RX_RESET, BASE + VX_COMMAND);
     81 	VX_BUSY_WAIT;
     82 	outw(TX_RESET, BASE + VX_COMMAND);
     83 	VX_BUSY_WAIT;
     84 	outw(C_INTR_LATCH, BASE + VX_COMMAND);
     85 	outw(SET_RD_0_MASK, BASE + VX_COMMAND);
     86 	outw(SET_INTR_MASK, BASE + VX_COMMAND);
     87 	outw(SET_RX_FILTER, BASE + VX_COMMAND);
     88 
     89 	/*
     90 	* initialize card
     91 	*/
     92 	VX_BUSY_WAIT;
     93 
     94 	GO_WINDOW(0);
     95 
     96 	/* Disable the card */
     97 /*	outw(0, BASE + VX_W0_CONFIG_CTRL); */
     98 
     99 	/* Configure IRQ to none */
    100 /*	outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
    101 
    102 	/* Enable the card */
    103 /*	outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
    104 
    105 	GO_WINDOW(2);
    106 
    107 	/* Reload the ether_addr. */
    108 	for (i = 0; i < ETH_ALEN; i++)
    109 		outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
    110 
    111 	outw(RX_RESET, BASE + VX_COMMAND);
    112 	VX_BUSY_WAIT;
    113 	outw(TX_RESET, BASE + VX_COMMAND);
    114 	VX_BUSY_WAIT;
    115 
    116 	/* Window 1 is operating window */
    117 	GO_WINDOW(1);
    118 	for (i = 0; i < 31; i++)
    119 		inb(BASE + VX_W1_TX_STATUS);
    120 
    121 	outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
    122 		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
    123 	outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
    124 		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
    125 
    126 /*
    127  * Attempt to get rid of any stray interrupts that occured during
    128  * configuration.  On the i386 this isn't possible because one may
    129  * already be queued.  However, a single stray interrupt is
    130  * unimportant.
    131  */
    132 
    133 	outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
    134 
    135 	outw(SET_RX_FILTER | FIL_INDIVIDUAL |
    136 	    FIL_BRDCST, BASE + VX_COMMAND);
    137 
    138 	vxsetlink();
    139 /*{
    140 	int i,j;
    141 	i = CONNECTOR_TX;
    142 	GO_WINDOW(3);
    143 	j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
    144 	outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
    145         GO_WINDOW(4);
    146         outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
    147         GO_WINDOW(1);
    148 }*/
    149 
    150 	/* start tranciever and receiver */
    151 	outw(RX_ENABLE, BASE + VX_COMMAND);
    152 	outw(TX_ENABLE, BASE + VX_COMMAND);
    153 
    154 }
    155 
    156 /**************************************************************************
    157 ETH_TRANSMIT - Transmit a frame
    158 ***************************************************************************/
    159 static char padmap[] = {
    160 	0, 3, 2, 1};
    161 
    162 static void t595_transmit(
    163 struct nic *nic,
    164 const char *d,			/* Destination */
    165 unsigned int t,			/* Type */
    166 unsigned int s,			/* size */
    167 const char *p)			/* Packet */
    168 {
    169 	register int len;
    170 	int pad;
    171 	int status;
    172 
    173 #ifdef EDEBUG
    174 	printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
    175 #endif
    176 
    177 	/* swap bytes of type */
    178 	t= htons(t);
    179 
    180 	len=s+ETH_HLEN; /* actual length of packet */
    181 	pad = padmap[len & 3];
    182 
    183 	/*
    184 	* The 3c595 automatically pads short packets to minimum ethernet length,
    185 	* but we drop packets that are too large. Perhaps we should truncate
    186 	* them instead?
    187 	*/
    188 	if (len + pad > ETH_FRAME_LEN) {
    189 		return;
    190 	}
    191 
    192 	/* drop acknowledgements */
    193 	while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
    194 		if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
    195 			outw(TX_RESET, BASE + VX_COMMAND);
    196 			outw(TX_ENABLE, BASE + VX_COMMAND);
    197 		}
    198 
    199 		outb(0x0, BASE + VX_W1_TX_STATUS);
    200 	}
    201 
    202 	while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
    203 		/* no room in FIFO */
    204 	}
    205 
    206 	outw(len, BASE + VX_W1_TX_PIO_WR_1);
    207 	outw(0x0, BASE + VX_W1_TX_PIO_WR_1);	/* Second dword meaningless */
    208 
    209 	/* write packet */
    210 	outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
    211 	outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
    212 	outw(t, BASE + VX_W1_TX_PIO_WR_1);
    213 	outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
    214 	if (s & 1)
    215 		outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
    216 
    217 	while (pad--)
    218 		outb(0, BASE + VX_W1_TX_PIO_WR_1);	/* Padding */
    219 
    220         /* wait for Tx complete */
    221         while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
    222                 ;
    223 }
    224 
    225 /**************************************************************************
    226 ETH_POLL - Wait for a frame
    227 ***************************************************************************/
    228 static int t595_poll(struct nic *nic)
    229 {
    230 	/* common variables */
    231 	unsigned short type = 0;	/* used by EDEBUG */
    232 	/* variables for 3C595 */
    233 	short status, cst;
    234 	register short rx_fifo;
    235 
    236 	cst=inw(BASE + VX_STATUS);
    237 
    238 #ifdef EDEBUG
    239 	if(cst & 0x1FFF)
    240 		printf("-%hX-",cst);
    241 #endif
    242 
    243 	if( (cst & S_RX_COMPLETE)==0 ) {
    244 		/* acknowledge  everything */
    245 		outw(ACK_INTR | cst, BASE + VX_COMMAND);
    246 		outw(C_INTR_LATCH, BASE + VX_COMMAND);
    247 
    248 		return 0;
    249 	}
    250 
    251 	status = inw(BASE + VX_W1_RX_STATUS);
    252 #ifdef EDEBUG
    253 	printf("*%hX*",status);
    254 #endif
    255 
    256 	if (status & ERR_RX) {
    257 		outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
    258 		return 0;
    259 	}
    260 
    261 	rx_fifo = status & RX_BYTES_MASK;
    262 	if (rx_fifo==0)
    263 		return 0;
    264 
    265 		/* read packet */
    266 #ifdef EDEBUG
    267 	printf("[l=%d",rx_fifo);
    268 #endif
    269 	insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
    270 	if(rx_fifo & 1)
    271 		nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
    272 	nic->packetlen=rx_fifo;
    273 
    274 	while(1) {
    275 		status = inw(BASE + VX_W1_RX_STATUS);
    276 #ifdef EDEBUG
    277 		printf("*%hX*",status);
    278 #endif
    279 		rx_fifo = status & RX_BYTES_MASK;
    280 
    281 		if(rx_fifo>0) {
    282 			insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
    283 			if(rx_fifo & 1)
    284 				nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
    285 			nic->packetlen+=rx_fifo;
    286 #ifdef EDEBUG
    287 			printf("+%d",rx_fifo);
    288 #endif
    289 		}
    290 		if(( status & RX_INCOMPLETE )==0) {
    291 #ifdef EDEBUG
    292 			printf("=%d",nic->packetlen);
    293 #endif
    294 			break;
    295 		}
    296 		udelay(1000);
    297 	}
    298 
    299 	/* acknowledge reception of packet */
    300 	outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
    301 	while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
    302 #ifdef EDEBUG
    303 	type = (nic->packet[12]<<8) | nic->packet[13];
    304 	if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
    305 	    nic->packet[5] == 0xFF*ETH_ALEN)
    306 		printf(",t=%hX,b]",type);
    307 	else
    308 		printf(",t=%hX]",type);
    309 #endif
    310 	return 1;
    311 }
    312 
    313 
    314 /*************************************************************************
    315 	3Com 595 - specific routines
    316 **************************************************************************/
    317 
    318 static int
    319 eeprom_rdy()
    320 {
    321 	int i;
    322 
    323 	for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
    324 		udelay(1000);
    325 	if (i >= MAX_EEPROMBUSY) {
    326 	        /* printf("3c595: eeprom failed to come ready.\n"); */
    327 		printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
    328 		return (0);
    329 	}
    330 	return (1);
    331 }
    332 
    333 /*
    334  * get_e: gets a 16 bits word from the EEPROM. we must have set the window
    335  * before
    336  */
    337 static int
    338 get_e(offset)
    339 int offset;
    340 {
    341 	if (!eeprom_rdy())
    342 		return (0xffff);
    343 	outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
    344 	if (!eeprom_rdy())
    345 		return (0xffff);
    346 	return (inw(BASE + VX_W0_EEPROM_DATA));
    347 }
    348 
    349 static void
    350 vxgetlink(void)
    351 {
    352     int n, k;
    353 
    354     GO_WINDOW(3);
    355     vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
    356     for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
    357       if (vx_connectors & conn_tab[k].bit) {
    358         if (n > 0) {
    359           printf("/");
    360 	}
    361         printf(conn_tab[k].name);
    362         n++;
    363       }
    364     }
    365     if (vx_connectors == 0) {
    366         printf("no connectors!");
    367         return;
    368     }
    369     GO_WINDOW(3);
    370     vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
    371                         & INTERNAL_CONNECTOR_MASK)
    372                         >> INTERNAL_CONNECTOR_BITS;
    373     if (vx_connector & 0x10) {
    374         vx_connector &= 0x0f;
    375         printf("[*%s*]", conn_tab[vx_connector].name);
    376         printf(": disable 'auto select' with DOS util!");
    377     } else {
    378         printf("[*%s*]", conn_tab[vx_connector].name);
    379     }
    380 }
    381 
    382 static void
    383 vxsetlink(void)
    384 {
    385     int i, j, k;
    386     char *reason, *warning;
    387     static short prev_flags;
    388     static char prev_conn = -1;
    389 
    390     if (prev_conn == -1) {
    391         prev_conn = vx_connector;
    392     }
    393 
    394     i = vx_connector;       /* default in EEPROM */
    395     reason = "default";
    396     warning = 0;
    397 
    398     if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
    399         warning = "strange connector type in EEPROM.";
    400         reason = "forced";
    401         i = CONNECTOR_UTP;
    402     }
    403 
    404         if (warning != 0) {
    405             printf("warning: %s\n", warning);
    406         }
    407         printf("selected %s. (%s)\n", conn_tab[i].name, reason);
    408 
    409     /* Set the selected connector. */
    410     GO_WINDOW(3);
    411     j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
    412     outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
    413 
    414     /* First, disable all. */
    415     outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
    416     udelay(8000);
    417     GO_WINDOW(4);
    418     outw(0, BASE + VX_W4_MEDIA_TYPE);
    419 
    420     /* Second, enable the selected one. */
    421     switch(i) {
    422       case CONNECTOR_UTP:
    423         GO_WINDOW(4);
    424         outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
    425         break;
    426       case CONNECTOR_BNC:
    427         outw(START_TRANSCEIVER,BASE + VX_COMMAND);
    428         udelay(8000);
    429         break;
    430       case CONNECTOR_TX:
    431       case CONNECTOR_FX:
    432         GO_WINDOW(4);
    433         outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
    434         break;
    435       default:  /* AUI and MII fall here */
    436         break;
    437     }
    438     GO_WINDOW(1);
    439 }
    440 
    441 static void t595_disable(struct nic *nic)
    442 {
    443     outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
    444     udelay(8000);
    445     GO_WINDOW(4);
    446     outw(0, BASE + VX_W4_MEDIA_TYPE);
    447     GO_WINDOW(1);
    448 }
    449 
    450 /**************************************************************************
    451 ETH_PROBE - Look for an adapter
    452 ***************************************************************************/
    453 struct nic *t595_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci)
    454 {
    455 	int i;
    456 	unsigned short *p;
    457 
    458 	if (probeaddrs == 0 || probeaddrs[0] == 0)
    459 		return 0;
    460 /*	eth_nic_base = probeaddrs[0] & ~3; */
    461 	eth_nic_base = pci->ioaddr;
    462 
    463 	GO_WINDOW(0);
    464 	outw(GLOBAL_RESET, BASE + VX_COMMAND);
    465 	VX_BUSY_WAIT;
    466 
    467 	vxgetlink();
    468 
    469 /*
    470 	printf("\nEEPROM:");
    471 	for (i = 0; i < (EEPROMSIZE/2); i++) {
    472 	  printf("%hX:", get_e(i));
    473 	}
    474 	printf("\n");
    475 */
    476 	/*
    477 	* Read the station address from the eeprom
    478 	*/
    479 	p = (unsigned short *) nic->node_addr;
    480 	for (i = 0; i < 3; i++) {
    481 		GO_WINDOW(0);
    482 		p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
    483 		GO_WINDOW(2);
    484 		outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
    485 	}
    486 
    487 	printf("Ethernet address: %!\n", nic->node_addr);
    488 
    489 	t595_reset(nic);
    490 	nic->reset = t595_reset;
    491 	nic->poll = t595_poll;
    492 	nic->transmit = t595_transmit;
    493 	nic->disable = t595_disable;
    494 	return nic;
    495 
    496 }
    497 
    498 /*
    499  * Local variables:
    500  *  c-basic-offset: 8
    501  * End:
    502  */
    503 
    504