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