source: gpxe_study/gpxe_src/sis900.c @ 195

Last change on this file since 195 was 2, checked in by jazz, 17 years ago
  • Inital version of gPXE Study
File size: 34.8 KB
RevLine 
[2]1/* -*- Mode:C; c-basic-offset:4; -*- */
2
3/*
4   sis900.c: An SiS 900/7016 PCI Fast Ethernet driver for Etherboot
5   Copyright (C) 2001 Entity Cyber, Inc.
6
7   Revision:  1.0 March 1, 2001
8   
9   Author: Marty Connor (mdc@etherboot.org)
10
11   Adapted from a Linux driver which was written by Donald Becker
12   and modified by Ollie Lho and Chin-Shan Li of SiS Corporation.
13   Rewritten for Etherboot by Marty Connor.
14   
15   This software may be used and distributed according to the terms
16   of the GNU Public License (GPL), incorporated herein by reference.
17   
18   References:
19   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
20   preliminary Rev. 1.0 Jan. 14, 1998
21   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
22   preliminary Rev. 1.0 Nov. 10, 1998
23   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
24   preliminary Rev. 1.0 Jan. 18, 1998
25   http://www.sis.com.tw/support/databook.htm */
26
27/* Revision History */
28
29/*
30  07 Dec 2003  timlegge - Enabled Multicast Support
31  06 Dec 2003  timlegge - Fixed relocation issue in 5.2
32  04 Jan 2002  Chien-Yu Chen, Doug Ambrisko, Marty Connor  Patch to Etherboot 5.0.5
33     Added support for the SiS 630ET plus various bug fixes from linux kernel
34     source 2.4.17.
35  01 March 2001  mdc     1.0
36     Initial Release.  Tested with PCI based sis900 card and ThinkNIC
37     computer.
38  20 March 2001 P.Koegel
39     added support for sis630e and PHY ICS1893 and RTL8201
40     Testet with SIS730S chipset + ICS1893
41*/
42
43
44/* Includes */
45
46#include "etherboot.h"
47#include <gpxe/pci.h>
48#include "nic.h"
49#include "timer.h"
50
51#include "sis900.h"
52
53/* Globals */
54
55static struct nic_operations sis900_operations;
56
57static int sis900_debug = 0;
58
59static unsigned short vendor, dev_id;
60static unsigned long ioaddr;
61static u8 pci_revision;
62
63static unsigned int cur_phy;
64
65static unsigned int cur_rx;
66
67struct {
68    BufferDesc txd;
69    BufferDesc rxd[NUM_RX_DESC];
70    unsigned char txb[TX_BUF_SIZE];
71    unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
72} sis900_bufs __shared;
73#define txd sis900_bufs.txd
74#define rxd sis900_bufs.rxd
75#define txb sis900_bufs.txb
76#define rxb sis900_bufs.rxb
77
78#if 0
79static struct mac_chip_info {
80    const char *name;
81    u16 vendor_id, device_id, flags;
82    int io_size;
83} mac_chip_table[] = {
84    { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
85      PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
86    { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
87      PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
88    {0,0,0,0,0} /* 0 terminated list. */
89};
90#endif
91
92static void sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
93static void amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
94static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
95static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
96static void vt6103_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
97
98static struct mii_chip_info {
99    const char * name;
100    u16 phy_id0;
101    u16 phy_id1;
102    void (*read_mode) (struct nic *nic, int phy_addr, int *speed, int *duplex);
103} mii_chip_table[] = {
104    {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
105    {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
106    {"SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, sis900_read_mode},
107    {"AMD 79C901 10BASE-T PHY",  0x0000, 0x6B70, amd79c901_read_mode},
108    {"AMD 79C901 HomePNA PHY",   0x0000, 0x6B90, amd79c901_read_mode},
109    {"ICS 1893 Integrated PHYceiver"   , 0x0015, 0xf440,ics1893_read_mode},
110//  {"NS 83851 PHY",0x2000, 0x5C20, MIX },
111    {"RTL 8201 10/100Mbps Phyceiver"   , 0x0000, 0x8200,rtl8201_read_mode},
112    {"VIA 6103 10/100Mbps Phyceiver", 0x0101, 0x8f20,vt6103_read_mode},
113    {0,0,0,0}
114};
115
116static struct mii_phy {
117    struct mii_phy * next;
118    struct mii_chip_info * chip_info;
119    int phy_addr;
120    u16 status;
121} mii;
122
123
124
125#if 0
126// PCI to ISA bridge for SIS640E access
127static struct pci_device_id pci_isa_bridge_list[] = {
128  { .vendor = 0x1039, .device = 0x0008,
129    .name = "SIS 85C503/5513 PCI to ISA bridge"},
130};
131
132PCI_DRIVER( sis_bridge_pci_driver, pci_isa_bridge_list, PCI_NO_CLASS );
133
134static struct device_driver sis_bridge_driver = {
135    .name = "SIS ISA bridge",
136    .bus_driver = &pci_driver,
137    .bus_driver_info = ( struct bus_driver_info * ) &sis_bridge_pci_driver,
138};
139#endif
140
141/* Function Prototypes */
142
143static int sis900_probe(struct nic *nic,struct pci_device *pci);
144
145static u16  sis900_read_eeprom(int location);
146static void sis900_mdio_reset(long mdio_addr);
147static void sis900_mdio_idle(long mdio_addr);
148static u16  sis900_mdio_read(int phy_id, int location);
149#if 0
150static void sis900_mdio_write(int phy_id, int location, int val);
151#endif
152static void sis900_init(struct nic *nic);
153
154static void sis900_reset(struct nic *nic);
155
156static void sis900_init_rxfilter(struct nic *nic);
157static void sis900_init_txd(struct nic *nic);
158static void sis900_init_rxd(struct nic *nic);
159static void sis900_set_rx_mode(struct nic *nic);
160static void sis900_check_mode(struct nic *nic);
161
162static void sis900_transmit(struct nic *nic, const char *d, 
163                            unsigned int t, unsigned int s, const char *p);
164static int  sis900_poll(struct nic *nic, int retrieve);
165
166static void sis900_disable(struct nic *nic);
167
168static void sis900_irq(struct nic *nic, irq_action_t action);
169
170/**
171 *  sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
172 *  @pci_dev: the sis900 pci device
173 *  @net_dev: the net device to get address for
174 *
175 *  Older SiS900 and friends, use EEPROM to store MAC address.
176 *  MAC address is read from read_eeprom() into @net_dev->dev_addr.
177 */
178
179static int sis900_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
180{
181  u16 signature;
182  int i;
183
184  /* check to see if we have sane EEPROM */
185  signature = (u16) sis900_read_eeprom( EEPROMSignature);
186  if (signature == 0xffff || signature == 0x0000) {
187    printf ("sis900_probe: Error EERPOM read %hX\n", signature);
188    return 0;
189  }
190
191  /* get MAC address from EEPROM */
192  for (i = 0; i < 3; i++)
193      ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
194  return 1;
195}
196
197/**
198 *  sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
199 *  @pci_dev: the sis900 pci device
200 *  @net_dev: the net device to get address for
201 *
202 *  SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
203 *  is shared by
204 *  LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
205 *  and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
206 *  by LAN, otherwise is not. After MAC address is read from EEPROM, send
207 *  EEDONE signal to refuse EEPROM access by LAN.
208 *  The EEPROM map of SiS962 or SiS963 is different to SiS900.
209 *  The signature field in SiS962 or SiS963 spec is meaningless.
210 *  MAC address is read into @net_dev->dev_addr.
211 */
212
213static int sis96x_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
214{
215/*  long ioaddr = net_dev->base_addr; */
216  long ee_addr = ioaddr + mear;
217  u32 waittime = 0;
218  int i;
219 
220  printf("Alternate function\n");
221
222  outl(EEREQ, ee_addr);
223  while(waittime < 2000) {
224    if(inl(ee_addr) & EEGNT) {
225
226      /* get MAC address from EEPROM */
227      for (i = 0; i < 3; i++)
228              ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
229
230      outl(EEDONE, ee_addr);
231      return 1;
232    } else {
233      udelay(1); 
234      waittime ++;
235    }
236  }
237  outl(EEDONE, ee_addr);
238  return 0;
239}
240
241/**
242 *  sis630e_get_mac_addr: - Get MAC address for SiS630E model
243 *  @pci_dev: the sis900 pci device
244 *  @net_dev: the net device to get address for
245 *
246 *  SiS630E model, use APC CMOS RAM to store MAC address.
247 *  APC CMOS RAM is accessed through ISA bridge.
248 *  MAC address is read into @net_dev->dev_addr.
249 */
250
251static int sis630e_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
252{
253#if 0
254  u8 reg;
255  int i;
256  struct bus_loc bus_loc;
257  union {
258      struct bus_dev bus_dev;
259      struct pci_device isa_bridge;
260  } u;
261
262  /* find PCI to ISA bridge */
263  memset(&bus_loc, 0, sizeof(bus_loc));
264  if ( ! find_by_driver ( &bus_loc, &u.bus_dev, &sis_bridge_driver, 0 ) )
265      return 0;
266
267  pci_read_config_byte(&u.isa_bridge, 0x48, &reg);
268  pci_write_config_byte(&u.isa_bridge, 0x48, reg | 0x40);
269
270  for (i = 0; i < ETH_ALEN; i++)
271  {
272    outb(0x09 + i, 0x70);
273    ((u8 *)(nic->node_addr))[i] = inb(0x71);
274  }
275  pci_write_config_byte(&u.isa_bridge, 0x48, reg & ~0x40);
276
277  return 1;
278#endif
279
280  /* Does not work with current bus/device model */
281  memset ( nic->node_addr, 0, sizeof ( nic->node_addr ) );
282  return 0;
283}
284
285/**
286 *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
287 *      @pci_dev: the sis900 pci device
288 *      @net_dev: the net device to get address for
289 *
290 *      SiS630E model, use APC CMOS RAM to store MAC address.
291 *      APC CMOS RAM is accessed through ISA bridge.
292 *      MAC address is read into @net_dev->dev_addr.
293 */
294
295static int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
296{
297        u32 rfcrSave;
298        u32 i;
299 
300 
301        rfcrSave = inl(rfcr + ioaddr);
302
303        outl(rfcrSave | RELOAD, ioaddr + cr);
304        outl(0, ioaddr + cr);
305
306        /* disable packet filtering before setting filter */
307        outl(rfcrSave & ~RFEN, rfcr + ioaddr);
308
309        /* load MAC addr to filter data register */
310        for (i = 0 ; i < 3 ; i++) {
311                outl((i << RFADDR_shift), ioaddr + rfcr);
312                *( ((u16 *)nic->node_addr) + i) = inw(ioaddr + rfdr);
313        }
314
315        /* enable packet filitering */
316        outl(rfcrSave | RFEN, rfcr + ioaddr);
317
318        return 1;
319}
320
321/*
322 * Function: sis900_probe
323 *
324 * Description: initializes initializes the NIC, retrieves the
325 *    MAC address of the card, and sets up some globals required by
326 *    other routines.
327 *
328 * Side effects:
329 *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
330 *            leaves the sis900 initialized, and ready to recieve packets.
331 *
332 * Returns:   struct nic *:          pointer to NIC data structure
333 */
334
335static int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
336
337    int i;
338    int found=0;
339    int phy_addr;
340    u8 revision;
341    int ret;
342
343    if (pci->ioaddr == 0)
344        return 0;
345
346    nic->irqno  = 0;
347    nic->ioaddr = pci->ioaddr;
348
349    ioaddr  = pci->ioaddr;
350    vendor  = pci->vendor;
351    dev_id  = pci->device;
352
353    /* wakeup chip */
354    pci_write_config_dword(pci, 0x40, 0x00000000);
355
356    adjust_pci_device(pci);
357
358    /* get MAC address */
359    ret = 0;
360    pci_read_config_byte(pci, PCI_REVISION, &revision);
361   
362    /* save for use later in sis900_reset() */
363    pci_revision = revision; 
364
365    if (revision == SIS630E_900_REV)
366        ret = sis630e_get_mac_addr(pci, nic);
367    else if ((revision > 0x81) && (revision <= 0x90))
368        ret = sis635_get_mac_addr(pci, nic);
369    else if (revision == SIS96x_900_REV)
370  ret = sis96x_get_mac_addr(pci, nic);
371    else
372        ret = sis900_get_mac_addr(pci, nic);
373
374    if (ret == 0)
375    {
376        printf ("sis900_probe: Error MAC address not found\n");
377        return 0;
378    }
379
380    /* 630ET : set the mii access mode as software-mode */
381    if (revision == SIS630ET_900_REV)
382  outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
383
384    DBG( "sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id );
385
386    /* probe for mii transceiver */
387    /* search for total of 32 possible mii phy addresses */
388
389    found = 0;
390    for (phy_addr = 0; phy_addr < 32; phy_addr++) {
391        u16 mii_status;
392        u16 phy_id0, phy_id1;
393
394        mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
395        if (mii_status == 0xffff || mii_status == 0x0000)
396            /* the mii is not accessable, try next one */
397            continue;
398               
399        phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
400        phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
401
402        /* search our mii table for the current mii */ 
403        for (i = 0; mii_chip_table[i].phy_id1; i++) {
404
405            if ((phy_id0 == mii_chip_table[i].phy_id0) &&
406                ((phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
407
408                printf("sis900_probe: %s transceiver found at address %d.\n",
409                       mii_chip_table[i].name, phy_addr);
410
411                mii.chip_info = &mii_chip_table[i];
412                mii.phy_addr  = phy_addr;
413                mii.status    = sis900_mdio_read(phy_addr, MII_STATUS);
414                mii.next      = NULL;
415
416                found=1;
417                break;
418            }
419        }
420    }
421       
422    if (found == 0) {
423        printf("sis900_probe: No MII transceivers found!\n");
424        return 0;
425    }
426
427    /* Arbitrarily select the last PHY found as current PHY */
428    cur_phy = mii.phy_addr;
429    printf("sis900_probe: Using %s as default\n",  mii.chip_info->name);
430
431    /* initialize device */
432    sis900_init(nic);
433    nic->nic_op = &sis900_operations;
434
435    return 1;
436}
437
438
439
440
441/*
442 * EEPROM Routines:  These functions read and write to EEPROM for
443 *    retrieving the MAC address and other configuration information about
444 *    the card.
445 */
446
447/* Delay between EEPROM clock transitions. */
448#define eeprom_delay()  inl(ee_addr)
449
450
451/* Function: sis900_read_eeprom
452 *
453 * Description: reads and returns a given location from EEPROM
454 *
455 * Arguments: int location:       requested EEPROM location
456 *
457 * Returns:   u16:                contents of requested EEPROM location
458 *
459 */
460
461/* Read Serial EEPROM through EEPROM Access Register, Note that location is
462   in word (16 bits) unit */
463static u16 sis900_read_eeprom(int location)
464{
465    int i;
466    u16 retval = 0;
467    long ee_addr = ioaddr + mear;
468    u32 read_cmd = location | EEread;
469
470    outl(0, ee_addr);
471    eeprom_delay();
472    outl(EECS, ee_addr);
473    eeprom_delay();
474
475    /* Shift the read command (9) bits out. */
476    for (i = 8; i >= 0; i--) {
477        u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
478        outl(dataval, ee_addr);
479        eeprom_delay();
480        outl(dataval | EECLK, ee_addr);
481        eeprom_delay();
482    }
483    outl(EECS, ee_addr);
484    eeprom_delay();
485
486    /* read the 16-bits data in */
487    for (i = 16; i > 0; i--) {
488        outl(EECS, ee_addr);
489        eeprom_delay();
490        outl(EECS | EECLK, ee_addr);
491        eeprom_delay();
492        retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
493        eeprom_delay();
494    }
495               
496    /* Terminate the EEPROM access. */
497    outl(0, ee_addr);
498    eeprom_delay();
499//  outl(EECLK, ee_addr);
500
501    return (retval);
502}
503
504#define sis900_mdio_delay()    inl(mdio_addr)
505
506
507/*
508   Read and write the MII management registers using software-generated
509   serial MDIO protocol. Note that the command bits and data bits are
510   send out seperately
511*/
512
513static void sis900_mdio_idle(long mdio_addr)
514{
515    outl(MDIO | MDDIR, mdio_addr);
516    sis900_mdio_delay();
517    outl(MDIO | MDDIR | MDC, mdio_addr);
518}
519
520/* Syncronize the MII management interface by shifting 32 one bits out. */
521static void sis900_mdio_reset(long mdio_addr)
522{
523    int i;
524
525    for (i = 31; i >= 0; i--) {
526        outl(MDDIR | MDIO, mdio_addr);
527        sis900_mdio_delay();
528        outl(MDDIR | MDIO | MDC, mdio_addr);
529        sis900_mdio_delay();
530    }
531    return;
532}
533
534static u16 sis900_mdio_read(int phy_id, int location)
535{
536    long mdio_addr = ioaddr + mear;
537    int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
538    u16 retval = 0;
539    int i;
540
541    sis900_mdio_reset(mdio_addr);
542    sis900_mdio_idle(mdio_addr);
543
544    for (i = 15; i >= 0; i--) {
545        int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
546        outl(dataval, mdio_addr);
547        sis900_mdio_delay();
548        outl(dataval | MDC, mdio_addr);
549        sis900_mdio_delay();
550    }
551
552    /* Read the 16 data bits. */
553    for (i = 16; i > 0; i--) {
554        outl(0, mdio_addr);
555        sis900_mdio_delay();
556        retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
557        outl(MDC, mdio_addr);
558        sis900_mdio_delay();
559    }
560    outl(0x00, mdio_addr);
561    return retval;
562}
563
564#if 0
565static void sis900_mdio_write(int phy_id, int location, int value)
566{
567    long mdio_addr = ioaddr + mear;
568    int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
569    int i;
570
571    sis900_mdio_reset(mdio_addr);
572    sis900_mdio_idle(mdio_addr);
573
574    /* Shift the command bits out. */
575    for (i = 15; i >= 0; i--) {
576        int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
577        outb(dataval, mdio_addr);
578        sis900_mdio_delay();
579        outb(dataval | MDC, mdio_addr);
580        sis900_mdio_delay();
581    }
582    sis900_mdio_delay();
583
584    /* Shift the value bits out. */
585    for (i = 15; i >= 0; i--) {
586        int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
587        outl(dataval, mdio_addr);
588        sis900_mdio_delay();
589        outl(dataval | MDC, mdio_addr);
590        sis900_mdio_delay();
591    }
592    sis900_mdio_delay();
593       
594    /* Clear out extra bits. */
595    for (i = 2; i > 0; i--) {
596        outb(0, mdio_addr);
597        sis900_mdio_delay();
598        outb(MDC, mdio_addr);
599        sis900_mdio_delay();
600    }
601    outl(0x00, mdio_addr);
602    return;
603}
604#endif
605
606
607/* Function: sis900_init
608 *
609 * Description: resets the ethernet controller chip and various
610 *    data structures required for sending and receiving packets.
611 *   
612 * Arguments: struct nic *nic:          NIC data structure
613 *
614 * returns:   void.
615 */
616
617static void
618sis900_init(struct nic *nic)
619{
620    /* Soft reset the chip. */
621    sis900_reset(nic);
622
623    sis900_init_rxfilter(nic);
624
625    sis900_init_txd(nic);
626    sis900_init_rxd(nic);
627
628    sis900_set_rx_mode(nic);
629
630    sis900_check_mode(nic);
631
632    outl(RxENA| inl(ioaddr + cr), ioaddr + cr);
633}
634
635
636/*
637 * Function: sis900_reset
638 *
639 * Description: disables interrupts and soft resets the controller chip
640 *
641 * Arguments: struct nic *nic:          NIC data structure
642 *
643 * Returns:   void.
644 */
645
646static void 
647sis900_reset(struct nic *nic __unused)
648{
649    int i = 0;
650    u32 status = TxRCMP | RxRCMP;
651
652    outl(0, ioaddr + ier);
653    outl(0, ioaddr + imr);
654    outl(0, ioaddr + rfcr);
655
656    outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
657
658    /* Check that the chip has finished the reset. */
659    while (status && (i++ < 1000)) {
660        status ^= (inl(isr + ioaddr) & status);
661    }
662
663    if( (pci_revision >= SIS635A_900_REV) || (pci_revision == SIS900B_900_REV) )
664            outl(PESEL | RND_CNT, ioaddr + cfg);
665    else
666            outl(PESEL, ioaddr + cfg);
667}
668
669
670/* Function: sis_init_rxfilter
671 *
672 * Description: sets receive filter address to our MAC address
673 *
674 * Arguments: struct nic *nic:          NIC data structure
675 *
676 * returns:   void.
677 */
678
679static void
680sis900_init_rxfilter(struct nic *nic)
681{
682    u32 rfcrSave;
683    int i;
684       
685    rfcrSave = inl(rfcr + ioaddr);
686
687    /* disable packet filtering before setting filter */
688    outl(rfcrSave & ~RFEN, rfcr + ioaddr);
689
690    /* load MAC addr to filter data register */
691    for (i = 0 ; i < 3 ; i++) {
692        u32 w;
693
694        w = (u32) *((u16 *)(nic->node_addr)+i);
695        outl((i << RFADDR_shift), ioaddr + rfcr);
696        outl(w, ioaddr + rfdr);
697
698        if (sis900_debug > 0)
699            printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%lX\n",
700                   i, inl(ioaddr + rfdr));
701    }
702
703    /* enable packet filitering */
704    outl(rfcrSave | RFEN, rfcr + ioaddr);
705}
706
707
708/*
709 * Function: sis_init_txd
710 *
711 * Description: initializes the Tx descriptor
712 *
713 * Arguments: struct nic *nic:          NIC data structure
714 *
715 * returns:   void.
716 */
717
718static void
719sis900_init_txd(struct nic *nic __unused)
720{
721    txd.link   = (u32) 0;
722    txd.cmdsts = (u32) 0;
723    txd.bufptr = virt_to_bus(&txb[0]);
724
725    /* load Transmit Descriptor Register */
726    outl(virt_to_bus(&txd), ioaddr + txdp); 
727    if (sis900_debug > 0)
728        printf("sis900_init_txd: TX descriptor register loaded with: %lX\n", 
729               inl(ioaddr + txdp));
730}
731
732
733/* Function: sis_init_rxd
734 *
735 * Description: initializes the Rx descriptor ring
736 *   
737 * Arguments: struct nic *nic:          NIC data structure
738 *
739 * Returns:   void.
740 */
741
742static void 
743sis900_init_rxd(struct nic *nic __unused) 
744{ 
745    int i;
746
747    cur_rx = 0; 
748
749    /* init RX descriptor */
750    for (i = 0; i < NUM_RX_DESC; i++) {
751        rxd[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]);
752        rxd[i].cmdsts = (u32) RX_BUF_SIZE;
753        rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]);
754        if (sis900_debug > 0)
755            printf("sis900_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n", 
756                   i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts,
757       (unsigned int) rxd[i].bufptr);
758    }
759
760    /* load Receive Descriptor Register */
761    outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
762
763    if (sis900_debug > 0)
764        printf("sis900_init_rxd: RX descriptor register loaded with: %lX\n", 
765               inl(ioaddr + rxdp));
766
767}
768
769
770/* Function: sis_init_rxd
771 *
772 * Description:
773 *    sets the receive mode to accept all broadcast packets and packets
774 *    with our MAC address, and reject all multicast packets.     
775 *   
776 * Arguments: struct nic *nic:          NIC data structure
777 *
778 * Returns:   void.
779 */
780
781static void sis900_set_rx_mode(struct nic *nic __unused)
782{
783    int i, table_entries;
784    u32 rx_mode; 
785    u16 mc_filter[16] = {0};  /* 256/128 bits multicast hash table */
786     
787    if((pci_revision == SIS635A_900_REV) || (pci_revision == SIS900B_900_REV))
788  table_entries = 16;
789    else
790  table_entries = 8;
791
792    /* accept all multicast packet */
793    rx_mode = RFAAB | RFAAM;
794    for (i = 0; i < table_entries; i++)
795    mc_filter[i] = 0xffff;
796         
797    /* update Multicast Hash Table in Receive Filter */
798    for (i = 0; i < table_entries; i++) {
799        /* why plus 0x04? That makes the correct value for hash table. */
800        outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
801        outl(mc_filter[i], ioaddr + rfdr);
802    }
803
804    /* Accept Broadcast and multicast packets, destination addresses that match
805       our MAC address */
806    outl(RFEN | rx_mode, ioaddr + rfcr);
807
808    return;
809}
810
811
812/* Function: sis900_check_mode
813 *
814 * Description: checks the state of transmit and receive
815 *    parameters on the NIC, and updates NIC registers to match
816 *   
817 * Arguments: struct nic *nic:          NIC data structure
818 *
819 * Returns:   void.
820 */
821
822static void
823sis900_check_mode(struct nic *nic)
824{
825    int speed, duplex;
826    u32 tx_flags = 0, rx_flags = 0;
827
828    mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex);
829
830    if( inl(ioaddr + cfg) & EDB_MASTER_EN ) {
831        tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
832  rx_flags = DMA_BURST_64 << RxMXDMA_shift;
833    }
834    else {
835            tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
836            rx_flags = DMA_BURST_512 << RxMXDMA_shift;
837    }
838
839    if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) {
840        rx_flags |= (RxDRNT_10 << RxDRNT_shift);
841        tx_flags |= (TxDRNT_10 << TxDRNT_shift);
842    }
843    else {
844        rx_flags |= (RxDRNT_100 << RxDRNT_shift);
845        tx_flags |= (TxDRNT_100 << TxDRNT_shift);
846    }
847
848    if (duplex == FDX_CAPABLE_FULL_SELECTED) {
849        tx_flags |= (TxCSI | TxHBI);
850        rx_flags |= RxATX;
851    }
852
853    outl (tx_flags, ioaddr + txcfg);
854    outl (rx_flags, ioaddr + rxcfg);
855}
856
857
858/* Function: sis900_read_mode
859 *
860 * Description: retrieves and displays speed and duplex
861 *    parameters from the NIC
862 *   
863 * Arguments: struct nic *nic:          NIC data structure
864 *
865 * Returns:   void.
866 */
867
868static void
869sis900_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
870{
871    int i = 0;
872    u32 status;
873    u16 phy_id0, phy_id1;
874       
875    /* STSOUT register is Latched on Transition, read operation updates it */
876    do {
877        status = sis900_mdio_read(phy_addr, MII_STSOUT);
878    } while (i++ < 2);
879
880    *speed = HW_SPEED_10_MBPS;
881    *duplex = FDX_CAPABLE_HALF_SELECTED;
882   
883    if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
884  *speed = HW_SPEED_100_MBPS;
885    if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
886  *duplex = FDX_CAPABLE_FULL_SELECTED;
887 
888    /* Workaround for Realtek RTL8201 PHY issue */
889    phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
890    phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
891    if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){
892  if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX)
893      *duplex = FDX_CAPABLE_FULL_SELECTED;
894  if(sis900_mdio_read(phy_addr, 0x0019) & 0x01)
895      *speed = HW_SPEED_100_MBPS;
896    }
897
898    if (status & MII_STSOUT_LINK_FAIL)
899        printf("sis900_read_mode: Media Link Off\n");
900    else
901        printf("sis900_read_mode: Media Link On %s %s-duplex \n", 
902               *speed == HW_SPEED_100_MBPS ? 
903               "100mbps" : "10mbps",
904               *duplex == FDX_CAPABLE_FULL_SELECTED ?
905               "full" : "half");
906}
907
908
909/* Function: amd79c901_read_mode
910 *
911 * Description: retrieves and displays speed and duplex
912 *    parameters from the NIC
913 *   
914 * Arguments: struct nic *nic:          NIC data structure
915 *
916 * Returns:   void.
917 */
918
919static void
920amd79c901_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
921{
922    int i;
923    u16 status;
924       
925    for (i = 0; i < 2; i++)
926        status = sis900_mdio_read(phy_addr, MII_STATUS);
927
928    if (status & MII_STAT_CAN_AUTO) {
929        /* 10BASE-T PHY */
930        for (i = 0; i < 2; i++)
931            status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY);
932        if (status & MII_STSSUM_SPD)
933            *speed = HW_SPEED_100_MBPS;
934        else
935            *speed = HW_SPEED_10_MBPS;
936        if (status & MII_STSSUM_DPLX)
937            *duplex = FDX_CAPABLE_FULL_SELECTED;
938        else
939            *duplex = FDX_CAPABLE_HALF_SELECTED;
940
941        if (status & MII_STSSUM_LINK)
942            printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", 
943                   *speed == HW_SPEED_100_MBPS ? 
944                   "100mbps" : "10mbps",
945                   *duplex == FDX_CAPABLE_FULL_SELECTED ?
946                   "full" : "half");
947        else
948            printf("amd79c901_read_mode: Media Link Off\n");
949    }
950    else {
951        /* HomePNA */
952        *speed = HW_SPEED_HOME;
953        *duplex = FDX_CAPABLE_HALF_SELECTED;
954        if (status & MII_STAT_LINK)
955            printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n");
956        else
957            printf("amd79c901_read_mode: Media Link Off\n");
958    }
959}
960
961
962/**
963 *  ics1893_read_mode: - read media mode for ICS1893 PHY
964 *  @net_dev: the net device to read mode for
965 *  @phy_addr: mii phy address
966 *  @speed: the transmit speed to be determined
967 *  @duplex: the duplex mode to be determined
968 *
969 *  ICS1893 PHY use Quick Poll Detailed Status register
970 *  to determine the speed and duplex mode for sis900
971 */
972
973static void ics1893_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
974{
975  int i = 0;
976  u32 status;
977
978  /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
979  for (i = 0; i < 2; i++)
980    status = sis900_mdio_read(phy_addr, MII_QPDSTS);
981
982  if (status & MII_STSICS_SPD)
983    *speed = HW_SPEED_100_MBPS;
984  else
985    *speed = HW_SPEED_10_MBPS;
986
987  if (status & MII_STSICS_DPLX)
988    *duplex = FDX_CAPABLE_FULL_SELECTED;
989  else
990    *duplex = FDX_CAPABLE_HALF_SELECTED;
991
992  if (status & MII_STSICS_LINKSTS)
993    printf("ics1893_read_mode: Media Link On %s %s-duplex \n",
994           *speed == HW_SPEED_100_MBPS ?
995           "100mbps" : "10mbps",
996           *duplex == FDX_CAPABLE_FULL_SELECTED ?
997           "full" : "half");
998  else
999    printf("ics1893_read_mode: Media Link Off\n");
1000}
1001
1002/**
1003 *  rtl8201_read_mode: - read media mode for rtl8201 phy
1004 *  @nic: the net device to read mode for
1005 *  @phy_addr: mii phy address
1006 *  @speed: the transmit speed to be determined
1007 *  @duplex: the duplex mode to be determined
1008 *
1009 *  read MII_STATUS register from rtl8201 phy
1010 *  to determine the speed and duplex mode for sis900
1011 */
1012
1013static void rtl8201_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
1014{
1015  u32 status;
1016
1017  status = sis900_mdio_read(phy_addr, MII_STATUS);
1018
1019  if (status & MII_STAT_CAN_TX_FDX) {
1020    *speed = HW_SPEED_100_MBPS;
1021    *duplex = FDX_CAPABLE_FULL_SELECTED;
1022  }
1023  else if (status & MII_STAT_CAN_TX) {
1024    *speed = HW_SPEED_100_MBPS;
1025    *duplex = FDX_CAPABLE_HALF_SELECTED;
1026  }
1027  else if (status & MII_STAT_CAN_T_FDX) {
1028    *speed = HW_SPEED_10_MBPS;
1029    *duplex = FDX_CAPABLE_FULL_SELECTED;
1030  }
1031  else if (status & MII_STAT_CAN_T) {
1032    *speed = HW_SPEED_10_MBPS;
1033    *duplex = FDX_CAPABLE_HALF_SELECTED;
1034  }
1035
1036  if (status & MII_STAT_LINK)
1037    printf("rtl8201_read_mode: Media Link On %s %s-duplex \n",
1038           *speed == HW_SPEED_100_MBPS ?
1039           "100mbps" : "10mbps",
1040           *duplex == FDX_CAPABLE_FULL_SELECTED ?
1041           "full" : "half");
1042  else
1043    printf("rtl8201_read_config_mode: Media Link Off\n");
1044}
1045
1046/**
1047 *  vt6103_read_mode: - read media mode for vt6103 phy
1048 *  @nic: the net device to read mode for
1049 *  @phy_addr: mii phy address
1050 *  @speed: the transmit speed to be determined
1051 *  @duplex: the duplex mode to be determined
1052 *
1053 *  read MII_STATUS register from rtl8201 phy
1054 *  to determine the speed and duplex mode for sis900
1055 */
1056
1057static void vt6103_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
1058{
1059  u32 status;
1060
1061  status = sis900_mdio_read(phy_addr, MII_STATUS);
1062
1063  if (status & MII_STAT_CAN_TX_FDX) {
1064    *speed = HW_SPEED_100_MBPS;
1065    *duplex = FDX_CAPABLE_FULL_SELECTED;
1066  }
1067  else if (status & MII_STAT_CAN_TX) {
1068    *speed = HW_SPEED_100_MBPS;
1069    *duplex = FDX_CAPABLE_HALF_SELECTED;
1070  }
1071  else if (status & MII_STAT_CAN_T_FDX) {
1072    *speed = HW_SPEED_10_MBPS;
1073    *duplex = FDX_CAPABLE_FULL_SELECTED;
1074  }
1075  else if (status & MII_STAT_CAN_T) {
1076    *speed = HW_SPEED_10_MBPS;
1077    *duplex = FDX_CAPABLE_HALF_SELECTED;
1078  }
1079
1080  if (status & MII_STAT_LINK)
1081    printf("vt6103_read_mode: Media Link On %s %s-duplex \n",
1082           *speed == HW_SPEED_100_MBPS ?
1083           "100mbps" : "10mbps",
1084           *duplex == FDX_CAPABLE_FULL_SELECTED ?
1085           "full" : "half");
1086  else
1087    printf("vt6103_read_config_mode: Media Link Off\n");
1088}
1089
1090/* Function: sis900_transmit
1091 *
1092 * Description: transmits a packet and waits for completion or timeout.
1093 *
1094 * Arguments: char d[6]:          destination ethernet address.
1095 *            unsigned short t:   ethernet protocol type.
1096 *            unsigned short s:   size of the data-part of the packet.
1097 *            char *p:            the data for the packet.
1098 *   
1099 * Returns:   void.
1100 */
1101
1102static void
1103sis900_transmit(struct nic  *nic,
1104                const char  *d,     /* Destination */
1105                unsigned int t,     /* Type */
1106                unsigned int s,     /* size */
1107                const char  *p)     /* Packet */
1108{
1109    u32 to, nstype;
1110    volatile u32 tx_status;
1111   
1112    /* Stop the transmitter */
1113    outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
1114
1115    /* load Transmit Descriptor Register */
1116    outl(virt_to_bus(&txd), ioaddr + txdp); 
1117    if (sis900_debug > 1)
1118        printf("sis900_transmit: TX descriptor register loaded with: %lX\n", 
1119               inl(ioaddr + txdp));
1120
1121    memcpy(txb, d, ETH_ALEN);
1122    memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
1123    nstype = htons(t);
1124    memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
1125    memcpy(txb + ETH_HLEN, p, s);
1126
1127    s += ETH_HLEN;
1128    s &= DSIZE;
1129
1130    if (sis900_debug > 1)
1131        printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
1132
1133    /* pad to minimum packet size */
1134    while (s < ETH_ZLEN) 
1135        txb[s++] = '\0';
1136
1137    /* set the transmit buffer descriptor and enable Transmit State Machine */
1138    txd.bufptr = virt_to_bus(&txb[0]);
1139    txd.cmdsts = (u32) OWN | s;
1140
1141    /* restart the transmitter */
1142    outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
1143
1144    if (sis900_debug > 1)
1145        printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s);
1146
1147    to = currticks() + TX_TIMEOUT;
1148
1149    while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
1150        /* wait */ ;
1151
1152    if (currticks() >= to) {
1153        printf("sis900_transmit: TX Timeout! Tx status %X.\n", 
1154         (unsigned int) tx_status);
1155    }
1156   
1157    if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
1158        /* packet unsuccessfully transmited */
1159        printf("sis900_transmit: Transmit error, Tx status %X.\n", 
1160         (unsigned int) tx_status);
1161    }
1162    /* Disable interrupts by clearing the interrupt mask. */
1163    outl(0, ioaddr + imr);
1164}
1165
1166
1167/* Function: sis900_poll
1168 *
1169 * Description: checks for a received packet and returns it if found.
1170 *
1171 * Arguments: struct nic *nic:          NIC data structure
1172 *
1173 * Returns:   1 if a packet was recieved.
1174 *            0 if no pacet was recieved.
1175 *
1176 * Side effects:
1177 *            Returns (copies) the packet to the array nic->packet.
1178 *            Returns the length of the packet in nic->packetlen.
1179 */
1180
1181static int
1182sis900_poll(struct nic *nic, int retrieve)
1183{
1184    u32 rx_status = rxd[cur_rx].cmdsts;
1185    int retstat = 0;
1186
1187    if (sis900_debug > 2)
1188        printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, 
1189         (unsigned int) rx_status);
1190
1191    if (!(rx_status & OWN))
1192        return retstat;
1193
1194    if (sis900_debug > 1)
1195        printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n",
1196               cur_rx, (unsigned int) rx_status);
1197
1198    if ( ! retrieve ) return 1;
1199   
1200    nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
1201
1202    if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
1203        /* corrupted packet received */
1204        printf("sis900_poll: Corrupted packet received, buffer status = %X\n",
1205               (unsigned int) rx_status);
1206        retstat = 0;
1207    } else {
1208        /* give packet to higher level routine */
1209        memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
1210        retstat = 1;
1211    }
1212
1213    /* return the descriptor and buffer to receive ring */
1214    rxd[cur_rx].cmdsts = RX_BUF_SIZE;
1215    rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]);
1216       
1217    if (++cur_rx == NUM_RX_DESC)
1218        cur_rx = 0;
1219
1220    /* re-enable the potentially idle receive state machine */
1221    outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
1222
1223    return retstat;
1224
1225}
1226
1227
1228/* Function: sis900_disable
1229 *
1230 * Description: Turns off interrupts and stops Tx and Rx engines
1231 *   
1232 * Arguments: struct nic *nic:          NIC data structure
1233 *
1234 * Returns:   void.
1235 */
1236
1237static void
1238sis900_disable ( struct nic *nic ) {
1239
1240    sis900_init(nic);
1241
1242    /* Disable interrupts by clearing the interrupt mask. */
1243    outl(0, ioaddr + imr);
1244    outl(0, ioaddr + ier);
1245   
1246    /* Stop the chip's Tx and Rx Status Machine */
1247    outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
1248}
1249
1250
1251/* Function: sis900_irq
1252 *
1253 * Description: Enable, Disable, or Force, interrupts
1254 *   
1255 * Arguments: struct nic *nic:          NIC data structure
1256 *            irq_action_t action:      Requested action       
1257 *
1258 * Returns:   void.
1259 */
1260
1261static void
1262sis900_irq(struct nic *nic __unused, irq_action_t action __unused)
1263{
1264  switch ( action ) {
1265  case DISABLE :
1266    break;
1267  case ENABLE :
1268    break;
1269  case FORCE :
1270    break;
1271  }
1272}
1273
1274static struct nic_operations sis900_operations = {
1275  .connect  = dummy_connect,
1276  .poll   = sis900_poll,
1277  .transmit = sis900_transmit,
1278  .irq    = sis900_irq,
1279};
1280
1281static struct pci_device_id sis900_nics[] = {
1282PCI_ROM(0x1039, 0x0900, "sis900",  "SIS900"),
1283PCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016"),
1284};
1285
1286PCI_DRIVER ( sis900_driver, sis900_nics, PCI_NO_CLASS );
1287
1288DRIVER ( "SIS900", nic_driver, pci_driver, sis900_driver,
1289   sis900_probe, sis900_disable );
1290
1291/*
1292 * Local variables:
1293 *  c-basic-offset: 8
1294 *  c-indent-level: 8
1295 *  tab-width: 8
1296 * End:
1297 */
Note: See TracBrowser for help on using the repository browser.