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