1 | /*
|
---|
2 | ** File: 8390.c May 02, 2000
|
---|
3 | **
|
---|
4 | ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
|
---|
5 | **
|
---|
6 | ** This file contains an ethernet device driver for NICs
|
---|
7 | ** equipped with the National Semiconductor NS 8390 chip.
|
---|
8 | ** It has to be associated with the board specific driver.
|
---|
9 | ** Rewritten from Minix 2.0.0 ethernet driver dp8390.c
|
---|
10 | ** to extract the NS 8390 common functions.
|
---|
11 | **
|
---|
12 | ** $Id: 8390.c,v 1.4 2005/09/04 18:52:16 beng Exp $
|
---|
13 | */
|
---|
14 |
|
---|
15 | #include "drivers.h"
|
---|
16 | #include <minix/com.h>
|
---|
17 | #include <net/hton.h>
|
---|
18 | #include <net/gen/ether.h>
|
---|
19 | #include <net/gen/eth_io.h>
|
---|
20 | #include "dp.h"
|
---|
21 |
|
---|
22 | #if (ENABLE_DP8390 == 1)
|
---|
23 |
|
---|
24 | #define PIO16 0 /* NOTE: pio 16 functions missing */
|
---|
25 |
|
---|
26 | #include "8390.h"
|
---|
27 |
|
---|
28 | #define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
|
---|
29 | sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
|
---|
30 | (dstProc),D,(vir_bytes)(dstOffs),length)
|
---|
31 | #define sys_user2nic(srcProc,srcOffs,dstOffs,length) \
|
---|
32 | sys_vircopy((srcProc),D,(vir_bytes)(srcOffs),\
|
---|
33 | SELF,dep->de_memsegm,(vir_bytes)(dstOffs),length)
|
---|
34 |
|
---|
35 | static const char RdmaErrMsg[] = "remote dma failed to complete";
|
---|
36 |
|
---|
37 | /*
|
---|
38 | ** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
|
---|
39 | ** Function: Sets the board for reading/writing.
|
---|
40 | */
|
---|
41 | static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset)
|
---|
42 | {
|
---|
43 |
|
---|
44 | if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
|
---|
45 | outb_reg0(dep, DP_RBCR0, size & 0xFF);
|
---|
46 | outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
|
---|
47 | outb_reg0(dep, DP_RSAR0, offset & 0xFF);
|
---|
48 | outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
|
---|
49 | mode |= (CR_PS_P0 | CR_STA);
|
---|
50 | outb_reg0(dep, DP_CR, mode);
|
---|
51 | return;
|
---|
52 | }
|
---|
53 |
|
---|
54 | /*
|
---|
55 | ** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno);
|
---|
56 | ** Function: Sets the board for for transmitting and fires it.
|
---|
57 | */
|
---|
58 | static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
|
---|
59 | {
|
---|
60 |
|
---|
61 | outb_reg0(dep, DP_TPSR, pageno);
|
---|
62 | outb_reg0(dep, DP_TBCR1, size >> 8);
|
---|
63 | outb_reg0(dep, DP_TBCR0, size & 0xFF);
|
---|
64 | outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
|
---|
65 | return;
|
---|
66 | }
|
---|
67 |
|
---|
68 | /*
|
---|
69 | ** Name: void mem_getblock(dpeth_t *dep, u16_t offset,
|
---|
70 | ** int size, void *dst)
|
---|
71 | ** Function: Reads a block of packet from board (shared memory).
|
---|
72 | */
|
---|
73 | static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
---|
74 | {
|
---|
75 |
|
---|
76 | sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
|
---|
77 | return;
|
---|
78 | }
|
---|
79 |
|
---|
80 | /*
|
---|
81 | ** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
|
---|
82 | ** Function: Copies a packet from board to user area (shared memory).
|
---|
83 | */
|
---|
84 | static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
|
---|
85 | {
|
---|
86 | phys_bytes offset, phys_user;
|
---|
87 | iovec_dat_t *iovp = &dep->de_read_iovec;
|
---|
88 | int bytes, ix = 0;
|
---|
89 |
|
---|
90 | /* Computes shared memory address (skipping receive header) */
|
---|
91 | offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
---|
92 |
|
---|
93 | do { /* Reads chuncks of packet into user area */
|
---|
94 |
|
---|
95 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
---|
96 | if (bytes > pktsize) bytes = pktsize;
|
---|
97 |
|
---|
98 | /* Reads from board to user area */
|
---|
99 | if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
---|
100 |
|
---|
101 | /* Circular buffer wrap-around */
|
---|
102 | bytes = dep->de_stoppage * DP_PAGESIZE - offset;
|
---|
103 | sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
|
---|
104 | iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
105 | pktsize -= bytes;
|
---|
106 | phys_user += bytes;
|
---|
107 | bytes = iovp->iod_iovec[ix].iov_size - bytes;
|
---|
108 | if (bytes > pktsize) bytes = pktsize;
|
---|
109 | offset = dep->de_startpage * DP_PAGESIZE;
|
---|
110 | }
|
---|
111 | sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
|
---|
112 | iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
113 | offset += bytes;
|
---|
114 |
|
---|
115 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
116 | dp_next_iovec(iovp);
|
---|
117 | ix = 0;
|
---|
118 | }
|
---|
119 | /* Till packet done */
|
---|
120 | } while ((pktsize -= bytes) > 0);
|
---|
121 | return;
|
---|
122 | }
|
---|
123 |
|
---|
124 | /*
|
---|
125 | ** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
126 | ** Function: Copies a packet from user area to board (shared memory).
|
---|
127 | */
|
---|
128 | static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
129 | {
|
---|
130 | phys_bytes offset, phys_user;
|
---|
131 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
132 | int bytes, ix = 0;
|
---|
133 |
|
---|
134 | /* Computes shared memory address */
|
---|
135 | offset = pageno * DP_PAGESIZE;
|
---|
136 |
|
---|
137 | do { /* Reads chuncks of packet from user area */
|
---|
138 |
|
---|
139 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
---|
140 | if (bytes > pktsize) bytes = pktsize;
|
---|
141 |
|
---|
142 | /* Reads from user area to board (shared memory) */
|
---|
143 | sys_user2nic(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
|
---|
144 | dep->de_linmem + offset, bytes);
|
---|
145 | offset += bytes;
|
---|
146 |
|
---|
147 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
148 | dp_next_iovec(iovp);
|
---|
149 | ix = 0;
|
---|
150 | }
|
---|
151 | /* Till packet done */
|
---|
152 | } while ((pktsize -= bytes) > 0);
|
---|
153 | return;
|
---|
154 | }
|
---|
155 |
|
---|
156 | /*
|
---|
157 | ** Name: void pio_getblock(dpeth_t *dep, u16_t offset,
|
---|
158 | ** int size, void *dst)
|
---|
159 | ** Function: Reads a block of packet from board (Prog. I/O).
|
---|
160 | */
|
---|
161 | static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
|
---|
162 | {
|
---|
163 |
|
---|
164 | /* Sets up board for reading */
|
---|
165 | ns_rw_setup(dep, CR_DM_RR, size, offset);
|
---|
166 |
|
---|
167 | #if PIO16 == 0
|
---|
168 | insb(dep->de_data_port, SELF, dst, size);
|
---|
169 | #else
|
---|
170 | if (dep->de_16bit == TRUE) {
|
---|
171 | insw(dep->de_data_port, dst, size);
|
---|
172 | } else {
|
---|
173 | insb(dep->de_data_port, dst, size);
|
---|
174 | }
|
---|
175 | #endif
|
---|
176 | return;
|
---|
177 | }
|
---|
178 |
|
---|
179 | /*
|
---|
180 | ** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
---|
181 | ** Function: Copies a packet from board to user area (Prog. I/O).
|
---|
182 | */
|
---|
183 | static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
---|
184 | {
|
---|
185 | phys_bytes phys_user;
|
---|
186 | iovec_dat_t *iovp = &dep->de_read_iovec;
|
---|
187 | unsigned offset; int bytes, ix = 0;
|
---|
188 |
|
---|
189 | /* Computes memory address (skipping receive header) */
|
---|
190 | offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
|
---|
191 | /* Sets up board for reading */
|
---|
192 | ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
|
---|
193 | (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
|
---|
194 |
|
---|
195 | do { /* Reads chuncks of packet into user area */
|
---|
196 |
|
---|
197 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
|
---|
198 | if (bytes > pktsize) bytes = pktsize;
|
---|
199 |
|
---|
200 | if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
|
---|
201 |
|
---|
202 | /* Circular buffer wrap-around */
|
---|
203 | bytes = dep->de_stoppage * DP_PAGESIZE - offset;
|
---|
204 | insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
---|
205 | pktsize -= bytes;
|
---|
206 | iovp->iod_iovec[ix].iov_addr += bytes;
|
---|
207 | bytes = iovp->iod_iovec[ix].iov_size - bytes;
|
---|
208 | if (bytes > pktsize) bytes = pktsize;
|
---|
209 | offset = dep->de_startpage * DP_PAGESIZE;
|
---|
210 | ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
|
---|
211 | }
|
---|
212 | insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
---|
213 | offset += bytes;
|
---|
214 |
|
---|
215 | if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
|
---|
216 | dp_next_iovec(iovp);
|
---|
217 | ix = 0;
|
---|
218 | }
|
---|
219 | /* Till packet done */
|
---|
220 | } while ((pktsize -= bytes) > 0);
|
---|
221 | return;
|
---|
222 | }
|
---|
223 |
|
---|
224 | /*
|
---|
225 | ** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
226 | ** Function: Copies a packet from user area to board (Prog. I/O).
|
---|
227 | */
|
---|
228 | static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
229 | {
|
---|
230 | phys_bytes phys_user;
|
---|
231 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
232 | int bytes, ix = 0;
|
---|
233 |
|
---|
234 | /* Sets up board for writing */
|
---|
235 | ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
|
---|
236 |
|
---|
237 | do { /* Reads chuncks of packet from user area */
|
---|
238 |
|
---|
239 | bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
|
---|
240 | if (bytes > pktsize) bytes = pktsize;
|
---|
241 | outsb(dep->de_data_port, iovp->iod_proc_nr,
|
---|
242 | (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
|
---|
243 |
|
---|
244 | if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
|
---|
245 | dp_next_iovec(iovp);
|
---|
246 | ix = 0;
|
---|
247 | }
|
---|
248 | /* Till packet done */
|
---|
249 | } while ((pktsize -= bytes) > 0);
|
---|
250 |
|
---|
251 | for (ix = 0; ix < 100; ix += 1) {
|
---|
252 | if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
---|
253 | }
|
---|
254 | if (ix == 100) {
|
---|
255 | panic(dep->de_name, RdmaErrMsg, NO_NUM);
|
---|
256 | }
|
---|
257 | return;
|
---|
258 | }
|
---|
259 |
|
---|
260 | /*
|
---|
261 | ** Name: void ns_stats(dpeth_t * dep)
|
---|
262 | ** Function: Updates counters reading from device
|
---|
263 | */
|
---|
264 | static void ns_stats(dpeth_t * dep)
|
---|
265 | {
|
---|
266 |
|
---|
267 | dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
|
---|
268 | dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
|
---|
269 | dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
---|
270 | return;
|
---|
271 | }
|
---|
272 |
|
---|
273 | /*
|
---|
274 | ** Name: void ns_dodump(dpeth_t * dep)
|
---|
275 | ** Function: Displays statistics (a request from F5 key).
|
---|
276 | */
|
---|
277 | static void ns_dodump(dpeth_t * dep)
|
---|
278 | {
|
---|
279 |
|
---|
280 | ns_stats(dep); /* Forces reading fo counters from board */
|
---|
281 | return;
|
---|
282 | }
|
---|
283 |
|
---|
284 | /*
|
---|
285 | ** Name: void ns_reinit(dpeth_t *dep)
|
---|
286 | ** Function: Updates receiver configuration.
|
---|
287 | */
|
---|
288 | static void ns_reinit(dpeth_t * dep)
|
---|
289 | {
|
---|
290 | int dp_reg = 0;
|
---|
291 |
|
---|
292 | if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
|
---|
293 | if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
|
---|
294 | if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
|
---|
295 | outb_reg0(dep, DP_CR, CR_PS_P0);
|
---|
296 | outb_reg0(dep, DP_RCR, dp_reg);
|
---|
297 | return;
|
---|
298 | }
|
---|
299 |
|
---|
300 | /*
|
---|
301 | ** Name: void ns_send(dpeth_t * dep, int from_int, int size)
|
---|
302 | ** Function: Transfers packet to device and starts sending.
|
---|
303 | */
|
---|
304 | static void ns_send(dpeth_t * dep, int from_int, int size)
|
---|
305 | {
|
---|
306 | int queue;
|
---|
307 |
|
---|
308 | if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
|
---|
309 | if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
|
---|
310 | dep->de_send_s = size;
|
---|
311 | return;
|
---|
312 | }
|
---|
313 | (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
|
---|
314 | dep->bytes_Tx += (long) size;
|
---|
315 | dep->de_sendq[queue].sq_filled = TRUE;
|
---|
316 | dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
|
---|
317 | if (dep->de_sendq_tail == queue) { /* there it goes.. */
|
---|
318 | ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
|
---|
319 | } else
|
---|
320 | dep->de_sendq[queue].sq_size = size;
|
---|
321 |
|
---|
322 | if (++queue == dep->de_sendq_nr) queue = 0;
|
---|
323 | dep->de_sendq_head = queue;
|
---|
324 | dep->de_flags &= NOT(DEF_SENDING);
|
---|
325 |
|
---|
326 | return;
|
---|
327 | }
|
---|
328 |
|
---|
329 | /*
|
---|
330 | ** Name: void ns_reset(dpeth_t *dep)
|
---|
331 | ** Function: Resets device.
|
---|
332 | */
|
---|
333 | static void ns_reset(dpeth_t * dep)
|
---|
334 | {
|
---|
335 | int ix;
|
---|
336 |
|
---|
337 | /* Stop chip */
|
---|
338 | outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
|
---|
339 | outb_reg0(dep, DP_RBCR0, 0);
|
---|
340 | outb_reg0(dep, DP_RBCR1, 0);
|
---|
341 | for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
|
---|
342 | /* Do nothing */ ;
|
---|
343 | outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
|
---|
344 | outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
|
---|
345 | outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
|
---|
346 |
|
---|
347 | /* Acknowledge the ISR_RDC (remote dma) interrupt. */
|
---|
348 | for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
|
---|
349 | /* Do nothing */ ;
|
---|
350 | outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
|
---|
351 |
|
---|
352 | /* Reset the transmit ring. If we were transmitting a packet, we
|
---|
353 | * pretend that the packet is processed. Higher layers will
|
---|
354 | * retransmit if the packet wasn't actually sent. */
|
---|
355 | dep->de_sendq_head = dep->de_sendq_tail = 0;
|
---|
356 | for (ix = 0; ix < dep->de_sendq_nr; ix++)
|
---|
357 | dep->de_sendq[ix].sq_filled = FALSE;
|
---|
358 | ns_send(dep, TRUE, dep->de_send_s);
|
---|
359 | return;
|
---|
360 | }
|
---|
361 |
|
---|
362 | /*
|
---|
363 | ** Name: void ns_recv(dpeth_t *dep, int fromint, int size)
|
---|
364 | ** Function: Gets a packet from device
|
---|
365 | */
|
---|
366 | static void ns_recv(dpeth_t *dep, int fromint, int size)
|
---|
367 | {
|
---|
368 | dp_rcvhdr_t header;
|
---|
369 | dp_rcvhdr_t dummy;
|
---|
370 | unsigned pageno, curr, next;
|
---|
371 | vir_bytes length;
|
---|
372 | int packet_processed = FALSE;
|
---|
373 | #ifdef ETH_IGN_PROTO
|
---|
374 | u16_t eth_type;
|
---|
375 | #endif
|
---|
376 |
|
---|
377 | pageno = inb_reg0(dep, DP_BNRY) + 1;
|
---|
378 | if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
|
---|
379 |
|
---|
380 | do {
|
---|
381 | /* */
|
---|
382 | outb_reg0(dep, DP_CR, CR_PS_P1);
|
---|
383 | curr = inb_reg1(dep, DP_CURR);
|
---|
384 | outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
|
---|
385 |
|
---|
386 | if (curr == pageno) break;
|
---|
387 |
|
---|
388 | (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
|
---|
389 | #ifdef ETH_IGN_PROTO
|
---|
390 | (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type);
|
---|
391 | #endif
|
---|
392 | length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
|
---|
393 | next = header.dr_next;
|
---|
394 |
|
---|
395 | if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
|
---|
396 | printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
|
---|
397 | dep->de_stat.ets_recvErr += 1;
|
---|
398 | next = curr;
|
---|
399 |
|
---|
400 | } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
|
---|
401 | printf("%s: strange next page\n", dep->de_name);
|
---|
402 | dep->de_stat.ets_recvErr += 1;
|
---|
403 | next = curr;
|
---|
404 |
|
---|
405 | #ifdef ETH_IGN_PROTO
|
---|
406 | } else if (eth_type == eth_ign_proto) {
|
---|
407 | /* Hack: ignore packets of a given protocol */
|
---|
408 | static int first = TRUE;
|
---|
409 | if (first) {
|
---|
410 | first = FALSE;
|
---|
411 | printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
|
---|
412 | }
|
---|
413 | next = curr;
|
---|
414 | #endif
|
---|
415 | } else if (header.dr_status & RSR_FO) {
|
---|
416 | /* This is very serious, issue a warning and reset buffers */
|
---|
417 | printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
|
---|
418 | dep->de_stat.ets_fifoOver += 1;
|
---|
419 | next = curr;
|
---|
420 |
|
---|
421 | } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
|
---|
422 |
|
---|
423 | if (!(dep->de_flags & DEF_READING)) break;
|
---|
424 |
|
---|
425 | (dep->de_nic2userf) (dep, pageno, length);
|
---|
426 | dep->de_read_s = length;
|
---|
427 | dep->de_flags |= DEF_ACK_RECV;
|
---|
428 | dep->de_flags &= NOT(DEF_READING);
|
---|
429 | packet_processed = TRUE;
|
---|
430 | }
|
---|
431 | dep->bytes_Rx += (long) length;
|
---|
432 | dep->de_stat.ets_packetR += 1;
|
---|
433 | outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
|
---|
434 | pageno = next;
|
---|
435 |
|
---|
436 | } while (!packet_processed);
|
---|
437 | #if 0
|
---|
438 | if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
|
---|
439 | /* The chip is stopped, and all arrived packets delivered */
|
---|
440 | (*dep->de_resetf) (dep);
|
---|
441 | dep->de_flags &= NOT(DEF_STOPPED);
|
---|
442 | #endif
|
---|
443 | return;
|
---|
444 | }
|
---|
445 |
|
---|
446 | /*
|
---|
447 | ** Name: void ns_interrupt(dpeth_t * dep)
|
---|
448 | ** Function: Handles interrupt.
|
---|
449 | */
|
---|
450 | static void ns_interrupt(dpeth_t * dep)
|
---|
451 | {
|
---|
452 | int isr, tsr;
|
---|
453 | int size, queue;
|
---|
454 |
|
---|
455 | while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
|
---|
456 |
|
---|
457 | outb_reg0(dep, DP_ISR, isr);
|
---|
458 | if (isr & (ISR_PTX | ISR_TXE)) {
|
---|
459 |
|
---|
460 | tsr = inb_reg0(dep, DP_TSR);
|
---|
461 | if (tsr & TSR_PTX) {
|
---|
462 | dep->de_stat.ets_packetT++;
|
---|
463 | }
|
---|
464 | if (tsr & TSR_COL) dep->de_stat.ets_collision++;
|
---|
465 | if (tsr & (TSR_ABT | TSR_FU)) {
|
---|
466 | dep->de_stat.ets_fifoUnder++;
|
---|
467 | }
|
---|
468 | if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
|
---|
469 | printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
|
---|
470 | dep->de_stat.ets_sendErr++;
|
---|
471 | }
|
---|
472 | queue = dep->de_sendq_tail;
|
---|
473 |
|
---|
474 | if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
|
---|
475 | printf("%s: transmit interrupt, but not sending\n", dep->de_name);
|
---|
476 | continue;
|
---|
477 | }
|
---|
478 | dep->de_sendq[queue].sq_filled = FALSE;
|
---|
479 | if (++queue == dep->de_sendq_nr) queue = 0;
|
---|
480 | dep->de_sendq_tail = queue;
|
---|
481 | if (dep->de_sendq[queue].sq_filled) {
|
---|
482 | ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
|
---|
483 | dep->de_sendq[queue].sq_sendpage);
|
---|
484 | }
|
---|
485 | if (dep->de_flags & DEF_SENDING) {
|
---|
486 | ns_send(dep, TRUE, dep->de_send_s);
|
---|
487 | }
|
---|
488 | }
|
---|
489 | if (isr & ISR_PRX) {
|
---|
490 | ns_recv(dep, TRUE, 0);
|
---|
491 | }
|
---|
492 | if (isr & ISR_RXE) {
|
---|
493 | printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
|
---|
494 | dep->de_stat.ets_recvErr++;
|
---|
495 | }
|
---|
496 | if (isr & ISR_CNT) {
|
---|
497 | dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
|
---|
498 | dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
|
---|
499 | dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
|
---|
500 | }
|
---|
501 | if (isr & ISR_OVW) {
|
---|
502 | printf("%s: got overwrite warning\n", dep->de_name);
|
---|
503 | }
|
---|
504 | if (isr & ISR_RDC) {
|
---|
505 | /* Nothing to do */
|
---|
506 | }
|
---|
507 | if (isr & ISR_RST) {
|
---|
508 | /* This means we got an interrupt but the ethernet
|
---|
509 | * chip is shutdown. We set the flag DEF_STOPPED, and
|
---|
510 | * continue processing arrived packets. When the
|
---|
511 | * receive buffer is empty, we reset the dp8390. */
|
---|
512 | printf("%s: network interface stopped\n", dep->de_name);
|
---|
513 | dep->de_flags |= DEF_STOPPED;
|
---|
514 | break;
|
---|
515 | }
|
---|
516 | }
|
---|
517 | if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
|
---|
518 |
|
---|
519 | /* The chip is stopped, and all arrived packets delivered */
|
---|
520 | ns_reset(dep);
|
---|
521 | dep->de_flags &= NOT(DEF_STOPPED);
|
---|
522 | }
|
---|
523 | return;
|
---|
524 | }
|
---|
525 |
|
---|
526 | /*
|
---|
527 | ** Name: void ns_init(dpeth_t *dep)
|
---|
528 | ** Function: Initializes the NS 8390
|
---|
529 | */
|
---|
530 | void ns_init(dpeth_t * dep)
|
---|
531 | {
|
---|
532 | int dp_reg;
|
---|
533 | int ix;
|
---|
534 |
|
---|
535 | /* NS8390 initialization (as recommended in National Semiconductor specs) */
|
---|
536 | outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
|
---|
537 | #if PIO16 == 0
|
---|
538 | outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
---|
539 | #else
|
---|
540 | outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
|
---|
541 | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
|
---|
542 | #endif
|
---|
543 | outb_reg0(dep, DP_RBCR0, 0);
|
---|
544 | outb_reg0(dep, DP_RBCR1, 0);
|
---|
545 | outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
|
---|
546 | outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
|
---|
547 | outb_reg0(dep, DP_PSTART, dep->de_startpage);
|
---|
548 | outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
|
---|
549 | outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
|
---|
550 | outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
|
---|
551 | outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */
|
---|
552 |
|
---|
553 | /* Copies station address in page 1 registers */
|
---|
554 | outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
|
---|
555 | for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */
|
---|
556 | outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
|
---|
557 | for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */
|
---|
558 | outb_reg1(dep, ix, 0xFF);
|
---|
559 |
|
---|
560 | outb_reg1(dep, DP_CURR, dep->de_startpage);
|
---|
561 | outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
|
---|
562 |
|
---|
563 | inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */
|
---|
564 | inb_reg0(dep, DP_CNTR1);
|
---|
565 | inb_reg0(dep, DP_CNTR2);
|
---|
566 |
|
---|
567 | dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
|
---|
568 | outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
|
---|
569 | outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */
|
---|
570 |
|
---|
571 | dp_reg = 0;
|
---|
572 | if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
|
---|
573 | if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
|
---|
574 | if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
|
---|
575 | outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */
|
---|
576 | outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */
|
---|
577 |
|
---|
578 | outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */
|
---|
579 |
|
---|
580 | /* Initializes the send queue. */
|
---|
581 | for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
|
---|
582 | dep->de_sendq[ix].sq_filled = 0;
|
---|
583 | dep->de_sendq_head = dep->de_sendq_tail = 0;
|
---|
584 |
|
---|
585 | /* Device specific functions */
|
---|
586 | if (!dep->de_prog_IO) {
|
---|
587 | dep->de_user2nicf = mem_user2nic;
|
---|
588 | dep->de_nic2userf = mem_nic2user;
|
---|
589 | dep->de_getblockf = mem_getblock;
|
---|
590 | } else {
|
---|
591 | #if PIO16 == 0
|
---|
592 | dep->de_user2nicf = pio_user2nic;
|
---|
593 | dep->de_nic2userf = pio_nic2user;
|
---|
594 | dep->de_getblockf = pio_getblock;
|
---|
595 | #else
|
---|
596 | #error Missing I/O functions for pio 16 bits
|
---|
597 | #endif
|
---|
598 | }
|
---|
599 | dep->de_recvf = ns_recv;
|
---|
600 | dep->de_sendf = ns_send;
|
---|
601 | dep->de_flagsf = ns_reinit;
|
---|
602 | dep->de_resetf = ns_reset;
|
---|
603 | dep->de_getstatsf = ns_stats;
|
---|
604 | dep->de_dumpstatsf = ns_dodump;
|
---|
605 | dep->de_interruptf = ns_interrupt;
|
---|
606 |
|
---|
607 | return; /* Done */
|
---|
608 | }
|
---|
609 |
|
---|
610 | #if PIO16 == 1
|
---|
611 |
|
---|
612 | /*
|
---|
613 | ** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
614 | ** Function: Copies a packet from user area to board (Prog. I/O, 16bits).
|
---|
615 | */
|
---|
616 | static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
|
---|
617 | {
|
---|
618 | u8_t two_bytes[2];
|
---|
619 | phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
|
---|
620 | vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
|
---|
621 | int bytes, ix = 0, odd_byte = 0;
|
---|
622 | iovec_dat_t *iovp = &dep->de_write_iovec;
|
---|
623 |
|
---|
624 | outb_reg0(dep, DP_ISR, ISR_RDC);
|
---|
625 | dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
|
---|
626 |
|
---|
627 | do {
|
---|
628 | bytes = iovp->iod_iovec[ix].iov_size;
|
---|
629 | if (bytes > pktsize) bytes = pktsize;
|
---|
630 |
|
---|
631 | phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
|
---|
632 | if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
|
---|
633 |
|
---|
634 | if (odd_byte) {
|
---|
635 | phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
|
---|
636 | out_word(dep->de_data_port, *(u16_t *)two_bytes);
|
---|
637 | pktsize--;
|
---|
638 | bytes--;
|
---|
639 | phys_user++;
|
---|
640 | odd_byte = 0;
|
---|
641 | if (!bytes) continue;
|
---|
642 | }
|
---|
643 | ecount = bytes & NOT(0x0001);
|
---|
644 | if (ecount != 0) {
|
---|
645 | phys_outsw(dep->de_data_port, phys_user, ecount);
|
---|
646 | pktsize -= ecount;
|
---|
647 | bytes -= ecount;
|
---|
648 | phys_user += ecount;
|
---|
649 | }
|
---|
650 | if (bytes) {
|
---|
651 | phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
|
---|
652 | pktsize--;
|
---|
653 | bytes--;
|
---|
654 | phys_user++;
|
---|
655 | odd_byte = 1;
|
---|
656 | }
|
---|
657 | if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
|
---|
658 | dp_next_iovec(iovp);
|
---|
659 | ix = 0;
|
---|
660 | }
|
---|
661 |
|
---|
662 | } while (bytes > 0);
|
---|
663 |
|
---|
664 | if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
|
---|
665 | for (ix = 0; ix < 100; ix++) {
|
---|
666 | if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
|
---|
667 | }
|
---|
668 | if (ix == 100) {
|
---|
669 | panic(dep->de_name, RdmaErrMsg, NO_NUM);
|
---|
670 | }
|
---|
671 | return;
|
---|
672 | }
|
---|
673 |
|
---|
674 | /*
|
---|
675 | ** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
|
---|
676 | ** Function: Copies a packet from board to user area (Prog. I/O, 16bits).
|
---|
677 | */
|
---|
678 | static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
|
---|
679 | {
|
---|
680 | phys_bytes phys_user;
|
---|
681 | vir_bytes ecount;
|
---|
682 | int bytes, i;
|
---|
683 | u8_t two_bytes[2];
|
---|
684 | phys_bytes phys_2bytes;
|
---|
685 | int odd_byte;
|
---|
686 |
|
---|
687 | ecount = (count + 1) & ~1;
|
---|
688 | phys_2bytes = vir2phys(two_bytes);
|
---|
689 | odd_byte = 0;
|
---|
690 |
|
---|
691 | dp_read_setup(dep, ecount, nic_addr);
|
---|
692 |
|
---|
693 | i = 0;
|
---|
694 | while (count > 0) {
|
---|
695 | if (i >= IOVEC_NR) {
|
---|
696 | dp_next_iovec(iovp);
|
---|
697 | i = 0;
|
---|
698 | continue;
|
---|
699 | }
|
---|
700 | bytes = iovp->iod_iovec[i].iov_size;
|
---|
701 | if (bytes > count) bytes = count;
|
---|
702 |
|
---|
703 | phys_user = numap(iovp->iod_proc_nr,
|
---|
704 | iovp->iod_iovec[i].iov_addr, bytes);
|
---|
705 | if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
|
---|
706 | if (odd_byte) {
|
---|
707 | phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
|
---|
708 | count--;
|
---|
709 | bytes--;
|
---|
710 | phys_user++;
|
---|
711 | odd_byte = 0;
|
---|
712 | if (!bytes) continue;
|
---|
713 | }
|
---|
714 | ecount = bytes & ~1;
|
---|
715 | if (ecount != 0) {
|
---|
716 | phys_insw(dep->de_data_port, phys_user, ecount);
|
---|
717 | count -= ecount;
|
---|
718 | bytes -= ecount;
|
---|
719 | phys_user += ecount;
|
---|
720 | }
|
---|
721 | if (bytes) {
|
---|
722 | *(u16_t *) two_bytes = in_word(dep->de_data_port);
|
---|
723 | phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
|
---|
724 | count--;
|
---|
725 | bytes--;
|
---|
726 | phys_user++;
|
---|
727 | odd_byte = 1;
|
---|
728 | }
|
---|
729 | }
|
---|
730 | return;
|
---|
731 | }
|
---|
732 |
|
---|
733 | #endif /* PIO16 == 1 */
|
---|
734 |
|
---|
735 | #endif /* ENABLE_DP8390 */
|
---|
736 |
|
---|
737 | /** end 8390.c **/
|
---|