unstack - fix ipcvecs
[minix.git] / sys / arch / i386 / stand / lib / netif / dp8390.c
blob754abb6eab5926008364bbef76efc63e720bbaf1
1 /* $NetBSD: dp8390.c,v 1.6 2008/12/14 18:46:33 christos Exp $ */
3 /*
4 * Polling driver for National Semiconductor DS8390/WD83C690 based
5 * ethernet adapters.
7 * Copyright (c) 1998 Matthias Drochner. All rights reserved.
9 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
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.
18 #include <sys/types.h>
19 #include <machine/pio.h>
21 #include <lib/libsa/stand.h>
22 #include <libi386.h>
24 #include <dev/ic/dp8390reg.h>
25 #include "dp8390.h"
26 #ifdef SUPPORT_NE2000
27 #include "ne.h"
28 #endif
30 #include "etherdrv.h"
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;
39 #define WE_IOBASE dp8390_iobase
41 static u_short rec_page_start;
42 static u_short rec_page_stop;
43 static u_short next_packet;
45 extern u_char eth_myaddr[6];
47 #ifndef _STANDALONE
48 static void *vmembase;
49 extern void *mapmem(int, int);
50 extern void unmapmem(void *, int);
51 extern int mapio(void);
53 static void
54 bbcopy(void *src, void *dst, int len)
56 char *s = (char *)src;
57 char *d = (char *)dst;
59 while (len--)
60 *d++ = *s++;
62 #endif
64 static void dp8390_read(int, char *, u_short);
66 #define NIC_GET(reg) inb(WE_IOBASE + reg)
67 #define NIC_PUT(reg, val) outb(WE_IOBASE + reg, val)
69 static void
70 dp8390_init(void)
72 int i;
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.
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);
83 if (dp8390_dcr_reg & ED_DCR_LS) {
84 NIC_PUT(ED_P0_DCR, dp8390_dcr_reg);
85 } else {
87 * Set FIFO threshold to 8, No auto-init Remote DMA, byte
88 * order=80x86, byte-wide DMA xfers,
90 NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
93 /* Clear remote byte count registers. */
94 NIC_PUT(ED_P0_RBCR0, 0);
95 NIC_PUT(ED_P0_RBCR1, 0);
97 /* Tell RCR to do nothing for now. */
98 NIC_PUT(ED_P0_RCR, ED_RCR_MON);
100 /* Place NIC in internal loopback mode. */
101 NIC_PUT(ED_P0_TCR, ED_TCR_LB0);
103 /* Set lower bits of byte addressable framing to 0. */
104 if (dp8390_is790)
105 NIC_PUT(0x09, 0);
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);
113 * Clear all interrupts. A '1' in each bit position clears the
114 * corresponding flag.
116 NIC_PUT(ED_P0_ISR, 0xff);
119 * Disable all interrupts.
121 NIC_PUT(ED_P0_IMR, 0);
123 /* Program command register for page 1. */
124 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP);
126 /* Copy out our station address. */
127 for (i = 0; i < 6; ++i)
128 NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]);
131 * Set current page pointer to one page after the boundary pointer, as
132 * recommended in the National manual.
134 next_packet = rec_page_start + 1;
135 NIC_PUT(ED_P1_CURR, next_packet);
137 /* Program command register for page 0. */
138 NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
140 /* directed and broadcast */
141 NIC_PUT(ED_P0_RCR, ED_RCR_AB);
143 /* Take interface out of loopback. */
144 NIC_PUT(ED_P0_TCR, 0);
146 /* Fire up the interface. */
147 NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
151 dp8390_config(void)
153 #ifndef _STANDALONE
154 if (mapio()) {
155 printf("no IO access\n");
156 return -1;
158 vmembase = mapmem(dp8390_membase, dp8390_memsize);
159 if (!vmembase) {
160 printf("no memory access\n");
161 return -1;
163 #endif
165 rec_page_start = TX_PAGE_START + ED_TXBUF_SIZE;
166 rec_page_stop = TX_PAGE_START + (dp8390_memsize >> ED_PAGE_SHIFT);
168 dp8390_init();
170 return 0;
173 void
174 dp8390_stop(void)
176 int n = 5000;
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);
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.
186 while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n)
187 continue;
189 #ifndef _STANDALONE
190 unmapmem(vmembase, dp8390_memsize);
191 #endif
195 EtherSend(char *pkt, int len)
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
207 /* Set TX buffer start page. */
208 NIC_PUT(ED_P0_TPSR, TX_PAGE_START);
210 /* Set TX length. */
211 NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len);
212 NIC_PUT(ED_P0_TBCR1, len >> 8);
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);
217 return len;
220 static void
221 dp8390_read(int buf, char *dest, u_short len)
223 u_short tmp_amount;
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;
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
240 len -= tmp_amount;
241 buf = RX_BUFBASE + (rec_page_start << ED_PAGE_SHIFT);
242 dest += tmp_amount;
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
256 EtherReceive(char *pkt, int maxlen)
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
266 if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX))
267 return 0; /* XXX error handling */
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);
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).
280 current = NIC_GET(ED_P1_CURR);
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);
285 if (next_packet == current)
286 return 0;
288 /* Get pointer to this buffer's header structure. */
289 packet_ptr = RX_BUFBASE + (next_packet << ED_PAGE_SHIFT);
292 * The byte count includes a 4 byte header that was added by
293 * the NIC.
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
305 len = packet_hdr.count;
307 #ifdef DP8390_OLDCHIPS
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.
314 * NOTE: sc->next_packet is pointing at the current packet.
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);
334 #endif
335 #endif
337 if (packet_hdr.next_packet < rec_page_start ||
338 packet_hdr.next_packet >= rec_page_stop)
339 panic(IFNAME ": RAM corrupt");
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;
349 /* Update next packet pointer. */
350 next_packet = packet_hdr.next_packet;
353 * Update NIC boundary pointer - being careful to keep it one
354 * buffer behind (as recommended by NS databook).
356 boundary = next_packet - 1;
357 if (boundary < rec_page_start)
358 boundary = rec_page_stop - 1;
359 NIC_PUT(ED_P0_BNRY, boundary);
361 return len;