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