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