xref: /onnv-gate/usr/src/grub/grub-0.97/netboot/natsemi.c (revision 8044:b3af80bbf173)
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