Automatically updated using
[people/sha0/gpxe.git] / src / drivers / net / smc9000.c
1 #ifdef ALLMULTI
2 #error multicast support is not yet implemented
3 #endif
4  /*------------------------------------------------------------------------
5  * smc9000.c
6  * This is a Etherboot driver for SMC's 9000 series of Ethernet cards.
7  *
8  * Copyright (C) 1998 Daniel Engström <daniel.engstrom@riksnett.no>
9  * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman
10  * Copyright (C) 1996 by Erik Stahlman <eric@vt.edu>
11  *
12  * This software may be used and distributed according to the terms
13  * of the GNU Public License, incorporated herein by reference.
14  *
15  * "Features" of the SMC chip:
16  *   4608 byte packet memory. ( for the 91C92/4.  Others have more )
17  *   EEPROM for configuration
18  *   AUI/TP selection
19  *
20  * Authors
21  *      Erik Stahlman                           <erik@vt.edu>
22  *      Daniel Engström                         <daniel.engstrom@riksnett.no>
23  *
24  * History
25  * 98-09-25              Daniel Engström Etherboot driver crated from Eric's
26  *                                       Linux driver.
27  *
28  *---------------------------------------------------------------------------*/
29 #define LINUX_OUT_MACROS 1
30 #define SMC9000_VERBOSE  1
31 #define SMC9000_DEBUG    0
32
33 #include "etherboot.h"
34 #include "nic.h"
35 #include "isa.h"
36 #include "smc9000.h"
37
38 # define _outb outb
39 # define _outw outw
40
41 static const char       smc9000_version[] = "Version 0.99 98-09-30";
42 static unsigned int     smc9000_base=0;
43 static const char       *interfaces[ 2 ] = { "TP", "AUI" };
44 static const char       *chip_ids[ 15 ] =  {
45    NULL, NULL, NULL,
46    /* 3 */ "SMC91C90/91C92",
47    /* 4 */ "SMC91C94",
48    /* 5 */ "SMC91C95",
49    NULL,
50    /* 7 */ "SMC91C100",
51    /* 8 */ "SMC91C100FD",
52    NULL, NULL, NULL,
53    NULL, NULL, NULL
54 };
55 static const char      smc91c96_id[] = "SMC91C96";
56
57 /*
58  * Function: smc_reset( int ioaddr )
59  * Purpose:
60  *      This sets the SMC91xx chip to its normal state, hopefully from whatever
61  *      mess that any other DOS driver has put it in.
62  *
63  * Maybe I should reset more registers to defaults in here?  SOFTRESET  should
64  * do that for me.
65  *
66  * Method:
67  *      1.  send a SOFT RESET
68  *      2.  wait for it to finish
69  *      3.  reset the memory management unit
70  *      4.  clear all interrupts
71  *
72 */
73 static void smc_reset(int ioaddr)
74 {
75    /* This resets the registers mostly to defaults, but doesn't
76     * affect EEPROM.  That seems unnecessary */
77    SMC_SELECT_BANK(ioaddr, 0);
78    _outw( RCR_SOFTRESET, ioaddr + RCR );
79
80    /* this should pause enough for the chip to be happy */
81    SMC_DELAY(ioaddr);
82
83    /* Set the transmit and receive configuration registers to
84     * default values */
85    _outw(RCR_CLEAR, ioaddr + RCR);
86    _outw(TCR_CLEAR, ioaddr + TCR);
87
88    /* Reset the MMU */
89    SMC_SELECT_BANK(ioaddr, 2);
90    _outw( MC_RESET, ioaddr + MMU_CMD );
91
92    /* Note:  It doesn't seem that waiting for the MMU busy is needed here,
93     * but this is a place where future chipsets _COULD_ break.  Be wary
94     * of issuing another MMU command right after this */
95    _outb(0, ioaddr + INT_MASK);
96 }
97
98
99 /*----------------------------------------------------------------------
100  * Function: smc_probe( int ioaddr )
101  *
102  * Purpose:
103  *      Tests to see if a given ioaddr points to an SMC9xxx chip.
104  *      Returns a 0 on success
105  *
106  * Algorithm:
107  *      (1) see if the high byte of BANK_SELECT is 0x33
108  *      (2) compare the ioaddr with the base register's address
109  *      (3) see if I recognize the chip ID in the appropriate register
110  *
111  * ---------------------------------------------------------------------
112  */
113 static int smc_probe( int ioaddr )
114 {
115    word bank;
116    word revision_register;
117    word base_address_register;
118
119    /* First, see if the high byte is 0x33 */
120    bank = inw(ioaddr + BANK_SELECT);
121    if ((bank & 0xFF00) != 0x3300) {
122       return -1;
123    }
124    /* The above MIGHT indicate a device, but I need to write to further
125     *   test this.  */
126    _outw(0x0, ioaddr + BANK_SELECT);
127    bank = inw(ioaddr + BANK_SELECT);
128    if ((bank & 0xFF00) != 0x3300) {
129       return -1;
130    }
131
132    /* well, we've already written once, so hopefully another time won't
133     *  hurt.  This time, I need to switch the bank register to bank 1,
134     *  so I can access the base address register */
135    SMC_SELECT_BANK(ioaddr, 1);
136    base_address_register = inw(ioaddr + BASE);
137
138    if (ioaddr != (base_address_register >> 3 & 0x3E0))  {
139 #ifdef  SMC9000_VERBOSE
140       printf("SMC9000: IOADDR %hX doesn't match configuration (%hX)."
141              "Probably not a SMC chip\n",
142              ioaddr, base_address_register >> 3 & 0x3E0);
143 #endif
144       /* well, the base address register didn't match.  Must not have
145        * been a SMC chip after all. */
146       return -1;
147    }
148
149
150    /* check if the revision register is something that I recognize.
151     * These might need to be added to later, as future revisions
152     * could be added.  */
153    SMC_SELECT_BANK(ioaddr, 3);
154    revision_register  = inw(ioaddr + REVISION);
155    if (!chip_ids[(revision_register >> 4) & 0xF]) {
156       /* I don't recognize this chip, so... */
157 #ifdef  SMC9000_VERBOSE
158       printf("SMC9000: IO %hX: Unrecognized revision register:"
159              " %hX, Contact author.\n", ioaddr, revision_register);
160 #endif
161       return -1;
162    }
163
164    /* at this point I'll assume that the chip is an SMC9xxx.
165     * It might be prudent to check a listing of MAC addresses
166     * against the hardware address, or do some other tests. */
167    return 0;
168 }
169
170
171 /**************************************************************************
172  * ETH_TRANSMIT - Transmit a frame
173  ***************************************************************************/
174 static void smc9000_transmit(
175         struct nic *nic,
176         const char *d,                  /* Destination */
177         unsigned int t,                 /* Type */
178         unsigned int s,                 /* size */
179         const char *p)                  /* Packet */
180 {
181    word length; /* real, length incl. header */
182    word numPages;
183    unsigned long time_out;
184    byte packet_no;
185    word status;
186    int i;
187
188    /* We dont pad here since we can have the hardware doing it for us */
189    length = (s + ETH_HLEN + 1)&~1;
190
191    /* convert to MMU pages */
192    numPages = length / 256;
193
194    if (numPages > 7 ) {
195 #ifdef  SMC9000_VERBOSE
196       printf("SMC9000: Far too big packet error. \n");
197 #endif
198       return;
199    }
200
201    /* dont try more than, say 30 times */
202    for (i=0;i<30;i++) {
203       /* now, try to allocate the memory */
204       SMC_SELECT_BANK(smc9000_base, 2);
205       _outw(MC_ALLOC | numPages, smc9000_base + MMU_CMD);
206
207       status = 0;
208       /* wait for the memory allocation to finnish */
209       for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) {
210          status = inb(smc9000_base + INTERRUPT);
211          if ( status & IM_ALLOC_INT ) {
212             /* acknowledge the interrupt */
213             _outb(IM_ALLOC_INT, smc9000_base + INTERRUPT);
214             break;
215          }
216       }
217
218       if ((status & IM_ALLOC_INT) != 0 ) {
219          /* We've got the memory */
220          break;
221       } else {
222          printf("SMC9000: Memory allocation timed out, resetting MMU.\n");
223          _outw(MC_RESET, smc9000_base + MMU_CMD);
224       }
225    }
226
227    /* If I get here, I _know_ there is a packet slot waiting for me */
228    packet_no = inb(smc9000_base + PNR_ARR + 1);
229    if (packet_no & 0x80) {
230       /* or isn't there?  BAD CHIP! */
231       printf("SMC9000: Memory allocation failed. \n");
232       return;
233    }
234
235    /* we have a packet address, so tell the card to use it */
236    _outb(packet_no, smc9000_base + PNR_ARR);
237
238    /* point to the beginning of the packet */
239    _outw(PTR_AUTOINC, smc9000_base + POINTER);
240
241 #if     SMC9000_DEBUG > 2
242    printf("Trying to xmit packet of length %hX\n", length );
243 #endif
244
245    /* send the packet length ( +6 for status, length and ctl byte )
246     * and the status word ( set to zeros ) */
247    _outw(0, smc9000_base + DATA_1 );
248
249    /* send the packet length ( +6 for status words, length, and ctl) */
250    _outb((length+6) & 0xFF,  smc9000_base + DATA_1);
251    _outb((length+6) >> 8 ,   smc9000_base + DATA_1);
252
253    /* Write the contents of the packet */
254
255    /* The ethernet header first... */
256    outsw(smc9000_base + DATA_1, d, ETH_ALEN >> 1);
257    outsw(smc9000_base + DATA_1, nic->node_addr, ETH_ALEN >> 1);
258    _outw(htons(t), smc9000_base + DATA_1);
259
260    /* ... the data ... */
261    outsw(smc9000_base + DATA_1 , p, s >> 1);
262
263    /* ... and the last byte, if there is one.   */
264    if ((s & 1) == 0) {
265       _outw(0, smc9000_base + DATA_1);
266    } else {
267       _outb(p[s-1], smc9000_base + DATA_1);
268       _outb(0x20, smc9000_base + DATA_1);
269    }
270
271    /* and let the chipset deal with it */
272    _outw(MC_ENQUEUE , smc9000_base + MMU_CMD);
273
274    status = 0; time_out = currticks() + 5*TICKS_PER_SEC;
275    do {
276       status = inb(smc9000_base + INTERRUPT);
277
278       if ((status & IM_TX_INT ) != 0) {
279          word tx_status;
280
281          /* ack interrupt */
282          _outb(IM_TX_INT, smc9000_base + INTERRUPT);
283
284          packet_no = inw(smc9000_base + FIFO_PORTS);
285          packet_no &= 0x7F;
286
287          /* select this as the packet to read from */
288          _outb( packet_no, smc9000_base + PNR_ARR );
289
290          /* read the first word from this packet */
291          _outw( PTR_AUTOINC | PTR_READ, smc9000_base + POINTER );
292
293          tx_status = inw( smc9000_base + DATA_1 );
294
295          if (0 == (tx_status & TS_SUCCESS)) {
296 #ifdef  SMC9000_VERBOSE
297             printf("SMC9000: TX FAIL STATUS: %hX \n", tx_status);
298 #endif
299             /* re-enable transmit */
300             SMC_SELECT_BANK(smc9000_base, 0);
301             _outw(inw(smc9000_base + TCR ) | TCR_ENABLE, smc9000_base + TCR );
302          }
303
304          /* kill the packet */
305          SMC_SELECT_BANK(smc9000_base, 2);
306          _outw(MC_FREEPKT, smc9000_base + MMU_CMD);
307
308          return;
309       }
310    }while(currticks() < time_out);
311
312    printf("SMC9000: Waring TX timed out, resetting board\n");
313    smc_reset(smc9000_base);
314    return;
315 }
316
317 /**************************************************************************
318  * ETH_POLL - Wait for a frame
319  ***************************************************************************/
320 static int smc9000_poll(struct nic *nic, int retrieve)
321 {
322    if(!smc9000_base)
323      return 0;
324
325    SMC_SELECT_BANK(smc9000_base, 2);
326    if (inw(smc9000_base + FIFO_PORTS) & FP_RXEMPTY)
327      return 0;
328    
329    if ( ! retrieve ) return 1;
330
331    /*  start reading from the start of the packet */
332    _outw(PTR_READ | PTR_RCV | PTR_AUTOINC, smc9000_base + POINTER);
333
334    /* First read the status and check that we're ok */
335    if (!(inw(smc9000_base + DATA_1) & RS_ERRORS)) {
336       /* Next: read the packet length and mask off the top bits */
337       nic->packetlen = (inw(smc9000_base + DATA_1) & 0x07ff);
338
339       /* the packet length includes the 3 extra words */
340       nic->packetlen -= 6;
341 #if     SMC9000_DEBUG > 2
342       printf(" Reading %d words (and %d byte(s))\n",
343                (nic->packetlen >> 1), nic->packetlen & 1);
344 #endif
345       /* read the packet (and the last "extra" word) */
346       insw(smc9000_base + DATA_1, nic->packet, (nic->packetlen+2) >> 1);
347       /* is there an odd last byte ? */
348       if (nic->packet[nic->packetlen+1] & 0x20)
349          nic->packetlen++;
350
351       /*  error or good, tell the card to get rid of this packet */
352       _outw(MC_RELEASE, smc9000_base + MMU_CMD);
353       return 1;
354    }
355
356    printf("SMC9000: RX error\n");
357    /*  error or good, tell the card to get rid of this packet */
358    _outw(MC_RELEASE, smc9000_base + MMU_CMD);
359    return 0;
360 }
361
362 static void smc9000_disable ( struct nic *nic __unused ) {
363    if(!smc9000_base)
364      return;
365
366    smc_reset(smc9000_base);
367
368    /* no more interrupts for me */
369    SMC_SELECT_BANK(smc9000_base, 2);
370    _outb( 0, smc9000_base + INT_MASK);
371
372    /* and tell the card to stay away from that nasty outside world */
373    SMC_SELECT_BANK(smc9000_base, 0);
374    _outb( RCR_CLEAR, smc9000_base + RCR );
375    _outb( TCR_CLEAR, smc9000_base + TCR );
376 }
377
378 static void smc9000_irq(struct nic *nic __unused, irq_action_t action __unused)
379 {
380   switch ( action ) {
381   case DISABLE :
382     break;
383   case ENABLE :
384     break;
385   case FORCE :
386     break;
387   }
388 }
389
390 /**************************************************************************
391  * ETH_PROBE - Look for an adapter
392  ***************************************************************************/
393
394 static int smc9000_probe(struct dev *dev, unsigned short *probe_addrs)
395 {
396    struct nic *nic = (struct nic *)dev;
397    unsigned short   revision;
398    int              memory;
399    int              media;
400    const char *     version_string;
401    const char *     if_string;
402    int              i;
403
404    /*
405     * the SMC9000 can be at any of the following port addresses.  To change,
406     * for a slightly different card, you can add it to the array.  Keep in
407     * mind that the array must end in zero.
408     */
409    static unsigned short portlist[] = {
410 #ifdef  SMC9000_SCAN
411       SMC9000_SCAN,
412 #else
413       0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
414       0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0,
415 #endif
416       0 };
417
418    /* if no addresses supplied, fall back on defaults */
419    if (probe_addrs == 0 || probe_addrs[0] == 0)
420      probe_addrs = portlist;
421
422    /* check every ethernet address */
423    for (i = 0; probe_addrs[i]; i++) {
424       /* check this specific address */
425       if (smc_probe(probe_addrs[i]) == 0)
426         smc9000_base = probe_addrs[i];
427    }
428
429    /* couldn't find anything */
430    if(0 == smc9000_base)
431      goto out;
432
433    nic->irqno  = 0;
434    nic->ioaddr = smc9000_base;
435
436    /*
437     * Get the MAC address ( bank 1, regs 4 - 9 )
438     */
439    SMC_SELECT_BANK(smc9000_base, 1);
440    for ( i = 0; i < 6; i += 2 ) {
441       word address;
442
443       address = inw(smc9000_base + ADDR0 + i);
444       nic->node_addr[i+1] = address >> 8;
445       nic->node_addr[i] = address & 0xFF;
446    }
447
448
449    /* get the memory information */
450    SMC_SELECT_BANK(smc9000_base, 0);
451    memory = ( inw(smc9000_base + MCR) >> 9 )  & 0x7;  /* multiplier */
452    memory *= 256 * (inw(smc9000_base + MIR) & 0xFF);
453
454    /*
455     * Now, I want to find out more about the chip.  This is sort of
456     * redundant, but it's cleaner to have it in both, rather than having
457     * one VERY long probe procedure.
458     */
459    SMC_SELECT_BANK(smc9000_base, 3);
460    revision  = inw(smc9000_base + REVISION);
461    version_string = chip_ids[(revision >> 4) & 0xF];
462
463    if (((revision & 0xF0) >> 4 == CHIP_9196) &&
464        ((revision & 0x0F) >= REV_9196)) {
465       /* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but
466        * a revision starting at 6 */
467       version_string = smc91c96_id;
468    }
469
470    if ( !version_string ) {
471       /* I shouldn't get here because this call was done before.... */
472       goto out;
473    }
474
475    /* is it using AUI or 10BaseT ? */
476    SMC_SELECT_BANK(smc9000_base, 1);
477    if (inw(smc9000_base + CONFIG) & CFG_AUI_SELECT)
478      media = 2;
479    else
480      media = 1;
481
482    if_string = interfaces[media - 1];
483
484    /* now, reset the chip, and put it into a known state */
485    smc_reset(smc9000_base);
486
487    printf("SMC9000 %s\n", smc9000_version);
488 #ifdef  SMC9000_VERBOSE
489    printf("Copyright (C) 1998 Daniel Engstr\x94m\n");
490    printf("Copyright (C) 1996 Eric Stahlman\n");
491 #endif
492
493    printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n",
494           version_string, revision & 0xF,
495           smc9000_base, if_string, memory );
496    /*
497     * Print the Ethernet address
498     */
499    printf("Ethernet MAC address: %!\n", nic->node_addr);
500
501    SMC_SELECT_BANK(smc9000_base, 0);
502
503    /* see the header file for options in TCR/RCR NORMAL*/
504    _outw(TCR_NORMAL, smc9000_base + TCR);
505    _outw(RCR_NORMAL, smc9000_base + RCR);
506
507    /* Select which interface to use */
508    SMC_SELECT_BANK(smc9000_base, 1);
509    if ( media == 1 ) {
510       _outw( inw( smc9000_base + CONFIG ) & ~CFG_AUI_SELECT,
511            smc9000_base + CONFIG );
512    }
513    else if ( media == 2 ) {
514       _outw( inw( smc9000_base + CONFIG ) | CFG_AUI_SELECT,
515            smc9000_base + CONFIG );
516    }
517
518    dev->disable  = smc9000_disable;
519    nic->poll     = smc9000_poll;
520    nic->transmit = smc9000_transmit;
521    nic->irq      = smc9000_irq;
522
523    /* Based on PnP ISA map */
524    dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
525    dev->devid.device_id = htons(0x8228);
526
527    return 1;
528
529 out:
530 #ifdef  SMC9000_VERBOSE
531    /* printf("No SMC9000 adapters found\n"); */
532 #endif
533    smc9000_base = 0;
534
535    return (0);
536 }
537
538 static struct isa_driver smc9000_driver __isa_driver = {
539         .type    = NIC_DRIVER,
540         .name    = "SMC9000",
541         .probe   = smc9000_probe,
542         .ioaddrs = 0,
543 };
544 ISA_ROM("smc9000","SMC9000");