• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
74 typedef unsigned char  u8;
75 typedef   signed char  s8;
76 typedef unsigned short u16;
77 typedef   signed short s16;
78 typedef unsigned int   u32;
79 typedef   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 
91 enum 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 */
107 enum 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. */
146 enum 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. */
157 enum 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 
167 typedef 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 */
175 enum 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 
186 static int natsemi_debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
187 
188 const char *nic_name;
189 
190 static u32 SavedClkRun;
191 
192 
193 static unsigned short vendor, dev_id;
194 static unsigned long ioaddr;
195 
196 static unsigned int cur_rx;
197 
198 static unsigned int advertising;
199 
200 static unsigned int rx_config;
201 static unsigned int tx_config;
202 
203 /* Note: transmit and receive buffers and descriptors must be
204    longword aligned
205 */
206 
207 static BufferDesc txd              __attribute__ ((aligned(4)));
208 static 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
214 static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
215 static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE] __attribute__ ((aligned(4)));
216 #endif
217 
218 /* Function Prototypes */
219 
220 struct nic *natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci);
221 static int eeprom_read(long addr, int location);
222 static int mdio_read(int phy_id, int location);
223 static void natsemi_init(struct nic *nic);
224 static void natsemi_reset(struct nic *nic);
225 static void natsemi_init_rxfilter(struct nic *nic);
226 static void natsemi_init_txd(struct nic *nic);
227 static void natsemi_init_rxd(struct nic *nic);
228 static void natsemi_set_rx_mode(struct nic *nic);
229 static void natsemi_check_duplex(struct nic *nic);
230 static void natsemi_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
231 static int  natsemi_poll(struct nic *nic);
232 static 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 
248 struct nic *
natsemi_probe(struct nic * nic,unsigned short * io_addrs,struct pci_device * pci)249 natsemi_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 
337 enum 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. */
348 enum EEPROM_Cmds {
349     EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
350 };
351 
eeprom_read(long addr,int location)352 static 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 
mdio_read(int phy_id,int location)390 static 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 
408 static void
natsemi_init(struct nic * nic)409 natsemi_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  */
454 static void
natsemi_reset(struct nic * nic)455 natsemi_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 
485 static void
natsemi_init_rxfilter(struct nic * nic)486 natsemi_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 
506 static void
natsemi_init_txd(struct nic * nic)507 natsemi_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 
529 static void
natsemi_init_rxd(struct nic * nic)530 natsemi_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 
natsemi_set_rx_mode(struct nic * nic)565 static void natsemi_set_rx_mode(struct nic *nic)
566 {
567     u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
568 
569     outl(rx_mode, ioaddr + RxFilterAddr);
570 }
571 
natsemi_check_duplex(struct nic * nic)572 static 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 
603 static void
natsemi_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)604 natsemi_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 
676 static int
natsemi_poll(struct nic * nic)677 natsemi_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 
727 static void
natsemi_disable(struct nic * nic)728 natsemi_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