• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  ***************************************************************************/
t595_reset(struct nic * nic)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  
t595_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)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  ***************************************************************************/
t595_poll(struct nic * nic,int retrieve)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
eeprom_rdy()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
get_e(offset)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
vxgetlink(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
vxsetlink(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  
t595_disable(struct nic * nic)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  
t595_irq(struct nic * nic __unused,irq_action_t action __unused)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  ***************************************************************************/
t595_probe(struct nic * nic,struct pci_device * pci)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