1/* -*- Mode:C; c-basic-offset:4; -*- */
2
3/*
4   natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
5
6   Copyright (C) 2001 Entity Cyber, Inc.
7
8   This development of this Etherboot driver was funded by
9
10      Sicom Systems: http://www.sicompos.com/
11
12   Author: Marty Connor (mdc@thinguin.org)
13   Adapted from a Linux driver which was written by Donald Becker
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   Original Copyright Notice:
19
20   Written/copyright 1999-2001 by Donald Becker.
21
22   This software may be used and distributed according to the terms of
23   the GNU General Public License (GPL), incorporated herein by reference.
24   Drivers based on or derived from this code fall under the GPL and must
25   retain the authorship, copyright and license notice.  This file is not
26   a complete program and may only be used when the entire operating
27   system is licensed under the GPL.  License for under other terms may be
28   available.  Contact the original author for details.
29
30   The original author may be reached as becker@scyld.com, or at
31   Scyld Computing Corporation
32   410 Severn Ave., Suite 210
33   Annapolis MD 21403
34
35   Support information and updates available at
36   http://www.scyld.com/network/netsemi.html
37
38   References:
39
40   http://www.scyld.com/expert/100mbps.html
41   http://www.scyld.com/expert/NWay.html
42   Datasheet is available from:
43   http://www.national.com/pf/DP/DP83815.html
44
45*/
46
47/* Revision History */
48
49/*
50  29 May 2001  mdc     1.0
51     Initial Release.  Tested with Netgear FA311 and FA312 boards
52*/
53/* Includes */
54
55#include "etherboot.h"
56#include "nic.h"
57#include "pci.h"
58#include "cards.h"
59
60/* defines */
61
62#define OWN       0x80000000
63#define DSIZE     0x00000FFF
64#define CRC_SIZE  4
65
66/* Time in ticks before concluding the transmitter is hung. */
67#define TX_TIMEOUT       (4*TICKS_PER_SEC)
68
69#define TX_BUF_SIZE    1536
70#define RX_BUF_SIZE    1536
71
72#define NUM_RX_DESC    4              /* Number of Rx descriptor registers. */
73
74typedef unsigned char  u8;
75typedef   signed char  s8;
76typedef unsigned short u16;
77typedef   signed short s16;
78typedef unsigned int   u32;
79typedef   signed int   s32;
80
81/* helpful macroes if on a big_endian machine for changing byte order.
82   not strictly needed on Intel */
83#define le16_to_cpu(val) (val)
84#define cpu_to_le32(val) (val)
85#define get_unaligned(ptr) (*(ptr))
86#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
87#define get_u16(ptr) (*(u16 *)(ptr))
88#define virt_to_bus(x) ((unsigned long)x)
89#define virt_to_le32desc(addr)  virt_to_bus(addr)
90
91enum pcistuff {
92    PCI_USES_IO     = 0x01,
93    PCI_USES_MEM    = 0x02,
94    PCI_USES_MASTER = 0x04,
95    PCI_ADDR0       = 0x08,
96    PCI_ADDR1       = 0x10,
97};
98
99/* MMIO operations required */
100#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
101
102/* Offsets to the device registers.
103   Unlike software-only systems, device drivers interact with complex hardware.
104   It's not useful to define symbolic names for every register bit in the
105   device.
106*/
107enum register_offsets {
108    ChipCmd      = 0x00,
109    ChipConfig   = 0x04,
110    EECtrl       = 0x08,
111    PCIBusCfg    = 0x0C,
112    IntrStatus   = 0x10,
113    IntrMask     = 0x14,
114    IntrEnable   = 0x18,
115    TxRingPtr    = 0x20,
116    TxConfig     = 0x24,
117    RxRingPtr    = 0x30,
118    RxConfig     = 0x34,
119    ClkRun       = 0x3C,
120    WOLCmd       = 0x40,
121    PauseCmd     = 0x44,
122    RxFilterAddr = 0x48,
123    RxFilterData = 0x4C,
124    BootRomAddr  = 0x50,
125    BootRomData  = 0x54,
126    SiliconRev   = 0x58,
127    StatsCtrl    = 0x5C,
128    StatsData    = 0x60,
129    RxPktErrs    = 0x60,
130    RxMissed     = 0x68,
131    RxCRCErrs    = 0x64,
132    PCIPM        = 0x44,
133    PhyStatus    = 0xC0,
134    MIntrCtrl    = 0xC4,
135    MIntrStatus  = 0xC8,
136
137    /* These are from the spec, around page 78... on a separate table. */
138    PGSEL        = 0xCC,
139    PMDCSR       = 0xE4,
140    TSTDAT       = 0xFC,
141    DSPCFG       = 0xF4,
142    SDCFG        = 0x8C
143};
144
145/* Bit in ChipCmd. */
146enum ChipCmdBits {
147    ChipReset = 0x100,
148    RxReset   = 0x20,
149    TxReset   = 0x10,
150    RxOff     = 0x08,
151    RxOn      = 0x04,
152    TxOff     = 0x02,
153    TxOn      = 0x01
154};
155
156/* Bits in the RxMode register. */
157enum rx_mode_bits {
158    AcceptErr          = 0x20,
159    AcceptRunt         = 0x10,
160    AcceptBroadcast    = 0xC0000000,
161    AcceptMulticast    = 0x00200000,
162    AcceptAllMulticast = 0x20000000,
163    AcceptAllPhys      = 0x10000000,
164    AcceptMyPhys       = 0x08000000
165};
166
167typedef struct _BufferDesc {
168    u32              link;
169    volatile u32     cmdsts;
170    u32              bufptr;
171    u32				 software_use;
172} BufferDesc;
173
174/* Bits in network_desc.status */
175enum desc_status_bits {
176    DescOwn   = 0x80000000,
177    DescMore  = 0x40000000,
178    DescIntr  = 0x20000000,
179    DescNoCRC = 0x10000000,
180    DescPktOK = 0x08000000,
181    RxTooLong = 0x00400000
182};
183
184/* Globals */
185
186static int natsemi_debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
187
188const char *nic_name;
189
190static u32 SavedClkRun;
191
192
193static unsigned short vendor, dev_id;
194static unsigned long ioaddr;
195
196static unsigned int cur_rx;
197
198static unsigned int advertising;
199
200static unsigned int rx_config;
201static unsigned int tx_config;
202
203/* Note: transmit and receive buffers and descriptors must be
204   longword aligned
205*/
206
207static BufferDesc txd              __attribute__ ((aligned(4)));
208static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
209
210#ifdef USE_LOWMEM_BUFFER
211#define txb ((char *)0x10000 - TX_BUF_SIZE)
212#define rxb ((char *)0x10000 - NUM_RX_DESC*RX_BUF_SIZE - TX_BUF_SIZE)
213#else
214static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
215static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE] __attribute__ ((aligned(4)));
216#endif
217
218/* Function Prototypes */
219
220struct nic *natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci);
221static int eeprom_read(long addr, int location);
222static int mdio_read(int phy_id, int location);
223static void natsemi_init(struct nic *nic);
224static void natsemi_reset(struct nic *nic);
225static void natsemi_init_rxfilter(struct nic *nic);
226static void natsemi_init_txd(struct nic *nic);
227static void natsemi_init_rxd(struct nic *nic);
228static void natsemi_set_rx_mode(struct nic *nic);
229static void natsemi_check_duplex(struct nic *nic);
230static void natsemi_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
231static int  natsemi_poll(struct nic *nic);
232static void natsemi_disable(struct nic *nic);
233
234/*
235 * Function: natsemi_probe
236 *
237 * Description: Retrieves the MAC address of the card, and sets up some
238 * globals required by other routines,  and initializes the NIC, making it
239 * ready to send and receive packets.
240 *
241 * Side effects:
242 *            leaves the ioaddress of the natsemi chip in the variable ioaddr.
243 *            leaves the natsemi initialized, and ready to recieve packets.
244 *
245 * Returns:   struct nic *:          pointer to NIC data structure
246 */
247
248struct nic *
249natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
250{
251    int i;
252    int prev_eedata;
253    u32 tmp;
254
255    if (io_addrs == 0 || *io_addrs == 0)
256        return NULL;
257
258    /* initialize some commonly used globals */
259
260    ioaddr     = *io_addrs & ~3;
261    vendor     = pci->vendor;
262    dev_id     = pci->dev_id;
263    nic_name   = pci->name;
264
265    adjust_pci_device(pci);
266
267    /* natsemi has a non-standard PM control register
268     * in PCI config space.  Some boards apparently need
269     * to be brought to D0 in this manner.
270     */
271    pcibios_read_config_dword(pci->bus, pci->devfn, PCIPM, &tmp);
272    if (tmp & (0x03|0x100)) {
273	/* D0 state, disable PME assertion */
274	u32 newtmp = tmp & ~(0x03|0x100);
275	pcibios_write_config_dword(pci->bus, pci->devfn, PCIPM, newtmp);
276    }
277
278    /* get MAC address */
279
280    prev_eedata = eeprom_read(ioaddr, 6);
281    for (i = 0; i < 3; i++) {
282	int eedata = eeprom_read(ioaddr, i + 7);
283	nic->node_addr[i*2] = (eedata << 1) + (prev_eedata >> 15);
284	nic->node_addr[i*2+1] = eedata >> 7;
285	prev_eedata = eedata;
286    }
287
288    printf("\nnatsemi_probe: MAC addr %! at ioaddr %#hX\n",
289           nic->node_addr, ioaddr);
290    printf("natsemi_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id);
291
292    /* Reset the chip to erase any previous misconfiguration. */
293    outl(ChipReset, ioaddr + ChipCmd);
294
295    advertising = mdio_read(1, 4);
296    {
297	u32 chip_config = inl(ioaddr + ChipConfig);
298	printf("%s: Transceiver default autoneg. %s "
299	       "10%s %s duplex.\n",
300	       nic_name,
301	       chip_config & 0x2000 ? "enabled, advertise" : "disabled, force",
302	       chip_config & 0x4000 ? "0" : "",
303	       chip_config & 0x8000 ? "full" : "half");
304    }
305    printf("%s: Transceiver status %hX advertising %hX\n",
306	   nic_name, (int)inl(ioaddr + 0x84), advertising);
307
308    /* Disable PME:
309     * The PME bit is initialized from the EEPROM contents.
310     * PCI cards probably have PME disabled, but motherboard
311     * implementations may have PME set to enable WakeOnLan.
312     * With PME set the chip will scan incoming packets but
313     * nothing will be written to memory. */
314    SavedClkRun = inl(ioaddr + ClkRun);
315    outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
316
317    /* initialize device */
318    natsemi_init(nic);
319
320    nic->reset    = natsemi_init;
321    nic->poll     = natsemi_poll;
322    nic->transmit = natsemi_transmit;
323    nic->disable  = natsemi_disable;
324
325    return nic;
326}
327
328/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
329   The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses.
330*/
331
332/* Delay between EEPROM clock transitions.
333   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
334   a delay. */
335#define eeprom_delay(ee_addr)	inl(ee_addr)
336
337enum EEPROM_Ctrl_Bits {
338    EE_ShiftClk   = 0x04,
339    EE_DataIn     = 0x01,
340    EE_ChipSelect = 0x08,
341    EE_DataOut    = 0x02
342};
343
344#define EE_Write0 (EE_ChipSelect)
345#define EE_Write1 (EE_ChipSelect | EE_DataIn)
346
347/* The EEPROM commands include the alway-set leading bit. */
348enum EEPROM_Cmds {
349    EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
350};
351
352static int eeprom_read(long addr, int location)
353{
354    int i;
355    int retval = 0;
356    int ee_addr = addr + EECtrl;
357    int read_cmd = location | EE_ReadCmd;
358    outl(EE_Write0, ee_addr);
359
360    /* Shift the read command bits out. */
361    for (i = 10; i >= 0; i--) {
362	short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
363	outl(dataval, ee_addr);
364	eeprom_delay(ee_addr);
365	outl(dataval | EE_ShiftClk, ee_addr);
366	eeprom_delay(ee_addr);
367    }
368    outl(EE_ChipSelect, ee_addr);
369    eeprom_delay(ee_addr);
370
371    for (i = 0; i < 16; i++) {
372	outl(EE_ChipSelect | EE_ShiftClk, ee_addr);
373	eeprom_delay(ee_addr);
374	retval |= (inl(ee_addr) & EE_DataOut) ? 1 << i : 0;
375	outl(EE_ChipSelect, ee_addr);
376	eeprom_delay(ee_addr);
377    }
378
379    /* Terminate the EEPROM access. */
380    outl(EE_Write0, ee_addr);
381    outl(0, ee_addr);
382
383    return retval;
384}
385
386/*  MII transceiver control section.
387	The 83815 series has an internal transceiver, and we present the
388	management registers as if they were MII connected. */
389
390static int mdio_read(int phy_id, int location)
391{
392    if (phy_id == 1 && location < 32)
393	return inl(ioaddr + 0x80 + (location<<2)) & 0xffff;
394    else
395	return 0xffff;
396}
397
398/* Function: natsemi_init
399 *
400 * Description: resets the ethernet controller chip and configures
401 *    registers and data structures required for sending and receiving packets.
402 *
403 * Arguments: struct nic *nic:          NIC data structure
404 *
405 * returns:   void.
406 */
407
408static void
409natsemi_init(struct nic *nic)
410{
411    natsemi_reset(nic);
412
413    /* Disable PME:
414     * The PME bit is initialized from the EEPROM contents.
415     * PCI cards probably have PME disabled, but motherboard
416     * implementations may have PME set to enable WakeOnLan.
417     * With PME set the chip will scan incoming packets but
418     * nothing will be written to memory. */
419    outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
420
421    natsemi_init_rxfilter(nic);
422
423    natsemi_init_txd(nic);
424    natsemi_init_rxd(nic);
425
426    /* Initialize other registers. */
427    /* Configure the PCI bus bursts and FIFO thresholds. */
428    /* Configure for standard, in-spec Ethernet. */
429    if (inl(ioaddr + ChipConfig) & 0x20000000) {	/* Full duplex */
430	tx_config = 0xD0801002;
431	rx_config = 0x10000020;
432    } else {
433	tx_config = 0x10801002;
434	rx_config = 0x0020;
435    }
436    outl(tx_config, ioaddr + TxConfig);
437    outl(rx_config, ioaddr + RxConfig);
438
439    natsemi_check_duplex(nic);
440    natsemi_set_rx_mode(nic);
441
442    outl(RxOn, ioaddr + ChipCmd);
443}
444
445/*
446 * Function: natsemi_reset
447 *
448 * Description: soft resets the controller chip
449 *
450 * Arguments: struct nic *nic:          NIC data structure
451 *
452 * Returns:   void.
453 */
454static void
455natsemi_reset(struct nic *nic)
456{
457    outl(ChipReset, ioaddr + ChipCmd);
458
459    /* On page 78 of the spec, they recommend some settings for "optimum
460       performance" to be done in sequence.  These settings optimize some
461       of the 100Mbit autodetection circuitry.  Also, we only want to do
462       this for rev C of the chip.
463    */
464    if (inl(ioaddr + SiliconRev) == 0x302) {
465	outw(0x0001, ioaddr + PGSEL);
466	outw(0x189C, ioaddr + PMDCSR);
467	outw(0x0000, ioaddr + TSTDAT);
468	outw(0x5040, ioaddr + DSPCFG);
469	outw(0x008C, ioaddr + SDCFG);
470    }
471    /* Disable interrupts using the mask. */
472    outl(0, ioaddr + IntrMask);
473    outl(0, ioaddr + IntrEnable);
474}
475
476/* Function: natsemi_init_rxfilter
477 *
478 * Description: sets receive filter address to our MAC address
479 *
480 * Arguments: struct nic *nic:          NIC data structure
481 *
482 * returns:   void.
483 */
484
485static void
486natsemi_init_rxfilter(struct nic *nic)
487{
488    int i;
489
490    for (i = 0; i < ETH_ALEN; i += 2) {
491	outl(i, ioaddr + RxFilterAddr);
492	outw(nic->node_addr[i] + (nic->node_addr[i+1] << 8), ioaddr + RxFilterData);
493    }
494}
495
496/*
497 * Function: natsemi_init_txd
498 *
499 * Description: initializes the Tx descriptor
500 *
501 * Arguments: struct nic *nic:          NIC data structure
502 *
503 * returns:   void.
504 */
505
506static void
507natsemi_init_txd(struct nic *nic)
508{
509    txd.link   = (u32) 0;
510    txd.cmdsts = (u32) 0;
511    txd.bufptr = (u32) &txb[0];
512
513    /* load Transmit Descriptor Register */
514    outl((u32) &txd, ioaddr + TxRingPtr);
515    if (natsemi_debug > 1)
516        printf("natsemi_init_txd: TX descriptor register loaded with: %X\n",
517               inl(ioaddr + TxRingPtr));
518}
519
520/* Function: natsemi_init_rxd
521 *
522 * Description: initializes the Rx descriptor ring
523 *
524 * Arguments: struct nic *nic:          NIC data structure
525 *
526 * Returns:   void.
527 */
528
529static void
530natsemi_init_rxd(struct nic *nic)
531{
532    int i;
533
534    cur_rx = 0;
535
536    /* init RX descriptor */
537    for (i = 0; i < NUM_RX_DESC; i++) {
538        rxd[i].link   = (i+1 < NUM_RX_DESC) ? (u32) &rxd[i+1] : (u32) &rxd[0];
539        rxd[i].cmdsts = (u32) RX_BUF_SIZE;
540        rxd[i].bufptr = (u32) &rxb[i*RX_BUF_SIZE];
541        if (natsemi_debug > 1)
542            printf("natsemi_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n",
543                   i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr);
544    }
545
546    /* load Receive Descriptor Register */
547    outl((u32) &rxd[0], ioaddr + RxRingPtr);
548
549    if (natsemi_debug > 1)
550        printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
551               inl(ioaddr + RxRingPtr));
552}
553
554/* Function: natsemi_set_rx_mode
555 *
556 * Description:
557 *    sets the receive mode to accept all broadcast packets and packets
558 *    with our MAC address, and reject all multicast packets.
559 *
560 * Arguments: struct nic *nic:          NIC data structure
561 *
562 * Returns:   void.
563 */
564
565static void natsemi_set_rx_mode(struct nic *nic)
566{
567    u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
568
569    outl(rx_mode, ioaddr + RxFilterAddr);
570}
571
572static void natsemi_check_duplex(struct nic *nic)
573{
574    int duplex = inl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
575
576    if (natsemi_debug)
577	printf("%s: Setting %s-duplex based on negotiated link"
578	       " capability.\n", nic_name,
579	       duplex ? "full" : "half");
580    if (duplex) {
581	rx_config |= 0x10000000;
582	tx_config |= 0xC0000000;
583    } else {
584	rx_config &= ~0x10000000;
585	tx_config &= ~0xC0000000;
586    }
587    outl(tx_config, ioaddr + TxConfig);
588    outl(rx_config, ioaddr + RxConfig);
589}
590
591/* Function: natsemi_transmit
592 *
593 * Description: transmits a packet and waits for completion or timeout.
594 *
595 * Arguments: char d[6]:          destination ethernet address.
596 *            unsigned short t:   ethernet protocol type.
597 *            unsigned short s:   size of the data-part of the packet.
598 *            char *p:            the data for the packet.
599 *
600 * Returns:   void.
601 */
602
603static void
604natsemi_transmit(struct nic  *nic,
605		 const char  *d,     /* Destination */
606		 unsigned int t,     /* Type */
607		 unsigned int s,     /* size */
608		 const char  *p)     /* Packet */
609{
610    u32 status, to, nstype;
611    u32 tx_status;
612
613    /* Stop the transmitter */
614    outl(TxOff, ioaddr + ChipCmd);
615
616    /* load Transmit Descriptor Register */
617    outl((u32) &txd, ioaddr + TxRingPtr);
618    if (natsemi_debug > 1)
619        printf("natsemi_transmit: TX descriptor register loaded with: %X\n",
620               inl(ioaddr + TxRingPtr));
621
622    memcpy(txb, d, ETH_ALEN);
623    memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
624    nstype = htons(t);
625    memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
626    memcpy(txb + ETH_HLEN, p, s);
627
628    s += ETH_HLEN;
629    s &= DSIZE;
630
631    if (natsemi_debug > 1)
632        printf("natsemi_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
633
634    /* pad to minimum packet size */
635    while (s < ETH_ZLEN)
636        txb[s++] = '\0';
637
638    /* set the transmit buffer descriptor and enable Transmit State Machine */
639    txd.bufptr = (u32) &txb[0];
640    txd.cmdsts = (u32) OWN | s;
641
642    /* restart the transmitter */
643    outl(TxOn, ioaddr + ChipCmd);
644
645    if (natsemi_debug > 1)
646        printf("natsemi_transmit: Queued Tx packet size %d.\n", (int) s);
647
648    to = currticks() + TX_TIMEOUT;
649
650    while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
651        /* wait */ ;
652
653    if (currticks() >= to) {
654        printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status);
655    }
656
657    if (!(tx_status & 0x08000000)) {
658	printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status);
659    }
660}
661
662/* Function: natsemi_poll
663 *
664 * Description: checks for a received packet and returns it if found.
665 *
666 * Arguments: struct nic *nic:          NIC data structure
667 *
668 * Returns:   1 if    packet was received.
669 *            0 if no packet was received.
670 *
671 * Side effects:
672 *            Returns (copies) the packet to the array nic->packet.
673 *            Returns the length of the packet in nic->packetlen.
674 */
675
676static int
677natsemi_poll(struct nic *nic)
678{
679    u32 rx_status = rxd[cur_rx].cmdsts;
680    int retstat = 0;
681
682    if (natsemi_debug > 2)
683        printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status);
684
685    if (!(rx_status & OWN))
686        return retstat;
687
688    if (natsemi_debug > 1)
689        printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
690               cur_rx, rx_status);
691
692    nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
693
694    if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
695        /* corrupted packet received */
696        printf("natsemi_poll: Corrupted packet received, buffer status = %X\n",
697               rx_status);
698        retstat = 0;
699    } else {
700        /* give packet to higher level routine */
701        memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
702        retstat = 1;
703    }
704
705    /* return the descriptor and buffer to receive ring */
706    rxd[cur_rx].cmdsts = RX_BUF_SIZE;
707    rxd[cur_rx].bufptr = (u32) &rxb[cur_rx*RX_BUF_SIZE];
708
709    if (++cur_rx == NUM_RX_DESC)
710        cur_rx = 0;
711
712    /* re-enable the potentially idle receive state machine */
713    outl(RxOn, ioaddr + ChipCmd);
714
715    return retstat;
716}
717
718/* Function: natsemi_disable
719 *
720 * Description: Turns off interrupts and stops Tx and Rx engines
721 *
722 * Arguments: struct nic *nic:          NIC data structure
723 *
724 * Returns:   void.
725 */
726
727static void
728natsemi_disable(struct nic *nic)
729{
730    /* Disable interrupts using the mask. */
731    outl(0, ioaddr + IntrMask);
732    outl(0, ioaddr + IntrEnable);
733
734    /* Stop the chip's Tx and Rx processes. */
735    outl(RxOff | TxOff, ioaddr + ChipCmd);
736
737    /* Restore PME enable bit */
738    outl(SavedClkRun, ioaddr + ClkRun);
739}
740