source: trunk/minix/drivers/dpeth/8390.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 20.6 KB
Line 
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
35static 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*/
41static 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*/
58static 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*/
73static 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*/
84static 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*/
128static 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*/
161static 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*/
183static 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*/
228static 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*/
264static 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*/
277static 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*/
288static 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*/
304static 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*/
333static 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*/
366static 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), &eth_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*/
450static 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*/
530void 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*/
616static 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*/
678static 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 **/
Note: See TracBrowser for help on using the repository browser.