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