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