1 /* $NetBSD: dp8390.c,v 1.6 2008/12/14 18:46:33 christos Exp $ */
2
3 /*
4 * Polling driver for National Semiconductor DS8390/WD83C690 based
5 * ethernet adapters.
6 *
7 * Copyright (c) 1998 Matthias Drochner. All rights reserved.
8 *
9 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
10 *
11 * Copyright (C) 1993, David Greenman. This software may be used, modified,
12 * copied, distributed, and sold, in both source and binary form provided that
13 * the above copyright and these terms are retained. Under no circumstances is
14 * the author responsible for the proper functioning of this software, nor does
15 * the author assume any responsibility for damages incurred with its use.
16 */
17
18 #include <sys/types.h>
19 #include <machine/pio.h>
20
21 #include <lib/libsa/stand.h>
22 #include <libi386.h>
23
24 #include <dev/ic/dp8390reg.h>
25 #include "dp8390.h"
26 #ifdef SUPPORT_NE2000
27 #include "ne.h"
28 #endif
29
30 #include "etherdrv.h"
31
32 int dp8390_iobase, dp8390_membase, dp8390_memsize;
33 #if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA)
34 int dp8390_is790;
35 #endif
36 uint8_t dp8390_cr_proto;
37 uint8_t dp8390_dcr_reg;
38
39 #define WE_IOBASE dp8390_iobase
40
41 static u_short rec_page_start;
42 static u_short rec_page_stop;
43 static u_short next_packet;
44
45 extern u_char eth_myaddr[6];
46
47 #ifndef _STANDALONE
48 static void *vmembase;
49 extern void *mapmem(int, int);
50 extern void unmapmem(void *, int);
51 extern int mapio(void);
52
53 static void
bbcopy(void * src,void * dst,int len)54 bbcopy(void *src, void *dst, int len)
55 {
56 char *s = (char *)src;
57 char *d = (char *)dst;
58
59 while (len--)
60 *d++ = *s++;
61 }
62 #endif
63
64 static void dp8390_read(int, char *, u_short);
65
66 #define NIC_GET(reg) inb(WE_IOBASE + reg)
67 #define NIC_PUT(reg, val) outb(WE_IOBASE + reg, val)
68
69 static void
dp8390_init(void)70 dp8390_init(void)
71 {
72 int i;
73
74 /*
75 * Initialize the NIC in the exact order outlined in the NS manual.
76 * This init procedure is "mandatory"...don't change what or when
77 * things happen.
78 */
79
80 /* Set interface for page 0, remote DMA complete, stopped. */
81 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
82
83 if (dp8390_dcr_reg & ED_DCR_LS) {
84 NIC_PUT(ED_P0_DCR, dp8390_dcr_reg);
85 } else {
86 /*
87 * Set FIFO threshold to 8, No auto-init Remote DMA, byte
88 * order=80x86, byte-wide DMA xfers,
89 */
90 NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
91 }
92
93 /* Clear remote byte count registers. */
94 NIC_PUT(ED_P0_RBCR0, 0);
95 NIC_PUT(ED_P0_RBCR1, 0);
96
97 /* Tell RCR to do nothing for now. */
98 NIC_PUT(ED_P0_RCR, ED_RCR_MON);
99
100 /* Place NIC in internal loopback mode. */
101 NIC_PUT(ED_P0_TCR, ED_TCR_LB0);
102
103 /* Set lower bits of byte addressable framing to 0. */
104 if (dp8390_is790)
105 NIC_PUT(0x09, 0);
106
107 /* Initialize receive buffer ring. */
108 NIC_PUT(ED_P0_BNRY, rec_page_start);
109 NIC_PUT(ED_P0_PSTART, rec_page_start);
110 NIC_PUT(ED_P0_PSTOP, rec_page_stop);
111
112 /*
113 * Clear all interrupts. A '1' in each bit position clears the
114 * corresponding flag.
115 */
116 NIC_PUT(ED_P0_ISR, 0xff);
117
118 /*
119 * Disable all interrupts.
120 */
121 NIC_PUT(ED_P0_IMR, 0);
122
123 /* Program command register for page 1. */
124 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP);
125
126 /* Copy out our station address. */
127 for (i = 0; i < 6; ++i)
128 NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]);
129
130 /*
131 * Set current page pointer to one page after the boundary pointer, as
132 * recommended in the National manual.
133 */
134 next_packet = rec_page_start + 1;
135 NIC_PUT(ED_P1_CURR, next_packet);
136
137 /* Program command register for page 0. */
138 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
139
140 /* directed and broadcast */
141 NIC_PUT(ED_P0_RCR, ED_RCR_AB);
142
143 /* Take interface out of loopback. */
144 NIC_PUT(ED_P0_TCR, 0);
145
146 /* Fire up the interface. */
147 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
148 }
149
150 int
dp8390_config(void)151 dp8390_config(void)
152 {
153 #ifndef _STANDALONE
154 if (mapio()) {
155 printf("no IO access\n");
156 return -1;
157 }
158 vmembase = mapmem(dp8390_membase, dp8390_memsize);
159 if (!vmembase) {
160 printf("no memory access\n");
161 return -1;
162 }
163 #endif
164
165 rec_page_start = TX_PAGE_START + ED_TXBUF_SIZE;
166 rec_page_stop = TX_PAGE_START + (dp8390_memsize >> ED_PAGE_SHIFT);
167
168 dp8390_init();
169
170 return 0;
171 }
172
173 void
dp8390_stop(void)174 dp8390_stop(void)
175 {
176 int n = 5000;
177
178 /* Stop everything on the interface, and select page 0 registers. */
179 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
180
181 /*
182 * Wait for interface to enter stopped state, but limit # of checks to
183 * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
184 * just in case it's an old one.
185 */
186 while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n)
187 continue;
188
189 #ifndef _STANDALONE
190 unmapmem(vmembase, dp8390_memsize);
191 #endif
192 }
193
194 int
EtherSend(char * pkt,int len)195 EtherSend(char *pkt, int len)
196 {
197 #ifdef SUPPORT_NE2000
198 ne2000_writemem(pkt, dp8390_membase, len);
199 #else
200 #ifdef _STANDALONE
201 vpbcopy(pkt, (void *)dp8390_membase, len);
202 #else
203 bbcopy(pkt, vmembase, len);
204 #endif
205 #endif
206
207 /* Set TX buffer start page. */
208 NIC_PUT(ED_P0_TPSR, TX_PAGE_START);
209
210 /* Set TX length. */
211 NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len);
212 NIC_PUT(ED_P0_TBCR1, len >> 8);
213
214 /* Set page 0, remote DMA complete, transmit packet, and *start*. */
215 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA);
216
217 return len;
218 }
219
220 static void
dp8390_read(int buf,char * dest,u_short len)221 dp8390_read(int buf, char *dest, u_short len)
222 {
223 u_short tmp_amount;
224
225 /* Does copy wrap to lower addr in ring buffer? */
226 if (buf + len > dp8390_membase + dp8390_memsize) {
227 tmp_amount = dp8390_membase + dp8390_memsize - buf;
228
229 /* Copy amount up to end of NIC memory. */
230 #ifdef SUPPORT_NE2000
231 ne2000_readmem(buf, dest, tmp_amount);
232 #else
233 #ifdef _STANDALONE
234 pvbcopy((void *)buf, dest, tmp_amount);
235 #else
236 bbcopy(vmembase + buf - dp8390_membase, dest, tmp_amount);
237 #endif
238 #endif
239
240 len -= tmp_amount;
241 buf = RX_BUFBASE + (rec_page_start << ED_PAGE_SHIFT);
242 dest += tmp_amount;
243 }
244 #ifdef SUPPORT_NE2000
245 ne2000_readmem(buf, dest, len);
246 #else
247 #ifdef _STANDALONE
248 pvbcopy((void *)buf, dest, len);
249 #else
250 bbcopy(vmembase + buf - dp8390_membase, dest, len);
251 #endif
252 #endif
253 }
254
255 int
EtherReceive(char * pkt,int maxlen)256 EtherReceive(char *pkt, int maxlen)
257 {
258 struct dp8390_ring packet_hdr;
259 int packet_ptr;
260 u_short len;
261 u_char boundary, current;
262 #ifdef DP8390_OLDCHIPS
263 u_char nlen;
264 #endif
265
266 if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX))
267 return 0; /* XXX error handling */
268
269 /* Set NIC to page 1 registers to get 'current' pointer. */
270 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STA);
271
272 /*
273 * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
274 * it points to where new data has been buffered. The 'CURR' (current)
275 * register points to the logical end of the ring-buffer - i.e. it
276 * points to where additional new data will be added. We loop here
277 * until the logical beginning equals the logical end (or in other
278 * words, until the ring-buffer is empty).
279 */
280 current = NIC_GET(ED_P1_CURR);
281
282 /* Set NIC to page 0 registers to update boundary register. */
283 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
284
285 if (next_packet == current)
286 return 0;
287
288 /* Get pointer to this buffer's header structure. */
289 packet_ptr = RX_BUFBASE + (next_packet << ED_PAGE_SHIFT);
290
291 /*
292 * The byte count includes a 4 byte header that was added by
293 * the NIC.
294 */
295 #ifdef SUPPORT_NE2000
296 ne2000_readmem(packet_ptr, (void *)&packet_hdr, 4);
297 #else
298 #ifdef _STANDALONE
299 pvbcopy((void *)packet_ptr, &packet_hdr, 4);
300 #else
301 bbcopy(vmembase + packet_ptr - dp8390_membase, &packet_hdr, 4);
302 #endif
303 #endif
304
305 len = packet_hdr.count;
306
307 #ifdef DP8390_OLDCHIPS
308 /*
309 * Try do deal with old, buggy chips that sometimes duplicate
310 * the low byte of the length into the high byte. We do this
311 * by simply ignoring the high byte of the length and always
312 * recalculating it.
313 *
314 * NOTE: sc->next_packet is pointing at the current packet.
315 */
316 if (packet_hdr.next_packet >= next_packet)
317 nlen = (packet_hdr.next_packet - next_packet);
318 else
319 nlen = ((packet_hdr.next_packet - rec_page_start) +
320 (rec_page_stop - next_packet));
321 --nlen;
322 if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE)
323 --nlen;
324 len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT);
325 #ifdef DIAGNOSTIC
326 if (len != packet_hdr.count) {
327 printf(IFNAME ": length does not match next packet pointer\n");
328 printf(IFNAME ": len %04x nlen %04x start %02x "
329 "first %02x curr %02x next %02x stop %02x\n",
330 packet_hdr.count, len,
331 rec_page_start, next_packet, current,
332 packet_hdr.next_packet, rec_page_stop);
333 }
334 #endif
335 #endif
336
337 if (packet_hdr.next_packet < rec_page_start ||
338 packet_hdr.next_packet >= rec_page_stop)
339 panic(IFNAME ": RAM corrupt");
340
341 len -= sizeof(struct dp8390_ring);
342 if (len < maxlen) {
343 /* Go get packet. */
344 dp8390_read(packet_ptr + sizeof(struct dp8390_ring),
345 pkt, len);
346 } else
347 len = 0;
348
349 /* Update next packet pointer. */
350 next_packet = packet_hdr.next_packet;
351
352 /*
353 * Update NIC boundary pointer - being careful to keep it one
354 * buffer behind (as recommended by NS databook).
355 */
356 boundary = next_packet - 1;
357 if (boundary < rec_page_start)
358 boundary = rec_page_stop - 1;
359 NIC_PUT(ED_P0_BNRY, boundary);
360
361 return len;
362 }
363