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
13 #include <minix/drivers.h>
14 #include <minix/netdriver.h>
15 #include <assert.h>
16 #include "dp.h"
17
18 #if (ENABLE_DP8390 == 1)
19
20 #include "8390.h"
21
22 /*
23 ** Name: ns_rw_setup
24 ** Function: Sets the board for reading/writing.
25 */
ns_rw_setup(const dpeth_t * dep,int mode,int size,u16_t offset)26 static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset)
27 {
28
29 if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
30 outb_reg0(dep, DP_RBCR0, size & 0xFF);
31 outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
32 outb_reg0(dep, DP_RSAR0, offset & 0xFF);
33 outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
34 mode |= (CR_PS_P0 | CR_STA);
35 outb_reg0(dep, DP_CR, mode);
36 }
37
38 /*
39 ** Name: ns_start_xmit
40 ** Function: Sets the board for for transmitting and fires it.
41 */
ns_start_xmit(const dpeth_t * dep,int size,int pageno)42 static void ns_start_xmit(const dpeth_t * dep, int size, int pageno)
43 {
44
45 outb_reg0(dep, DP_TPSR, pageno);
46 outb_reg0(dep, DP_TBCR1, size >> 8);
47 outb_reg0(dep, DP_TBCR0, size & 0xFF);
48 outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
49 }
50
51 /*
52 ** Name: mem_getblock
53 ** Function: Reads a block of packet from board (shared memory).
54 */
mem_getblock(dpeth_t * dep,u16_t offset,int size,void * dst)55 static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
56 {
57
58 assert(size >= 0);
59 assert(offset + (unsigned int)size <= dep->de_ramsize);
60
61 memcpy(dst, dep->de_locmem + offset, size);
62 }
63
64 /*
65 ** Name: mem_nic2user
66 ** Function: Copies a packet from board to user area (shared memory).
67 */
mem_nic2user(dpeth_t * dep,int pageno,struct netdriver_data * data,size_t size)68 static void mem_nic2user(dpeth_t *dep, int pageno, struct netdriver_data *data,
69 size_t size)
70 {
71 size_t offset, left;
72
73 /* Computes shared memory address (skipping receive header) */
74 offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
75
76 if (offset + size > dep->de_stoppage * DP_PAGESIZE) {
77 left = dep->de_stoppage * DP_PAGESIZE - offset;
78 netdriver_copyout(data, 0, dep->de_locmem + offset, left);
79 offset = dep->de_startpage * DP_PAGESIZE;
80 netdriver_copyout(data, left, dep->de_locmem + offset, size - left);
81 } else
82 netdriver_copyout(data, 0, dep->de_locmem + offset, size);
83 }
84
85 /*
86 ** Name: mem_user2nic
87 ** Function: Copies a packet from user area to board (shared memory).
88 */
mem_user2nic(dpeth_t * dep,int pageno,struct netdriver_data * data,size_t size)89 static void mem_user2nic(dpeth_t *dep, int pageno, struct netdriver_data *data,
90 size_t size)
91 {
92 size_t offset;
93
94 /* Computes shared memory address */
95 offset = pageno * DP_PAGESIZE;
96
97 netdriver_copyin(data, 0, dep->de_locmem + offset, size);
98 }
99
100 /*
101 ** Name: pio_getblock
102 ** Function: Reads a block of packet from board (Prog. I/O).
103 */
pio_getblock(dpeth_t * dep,u16_t offset,int size,void * dst)104 static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
105 {
106
107 /* Sets up board for reading */
108 ns_rw_setup(dep, CR_DM_RR, size, offset);
109
110 if (dep->de_16bit == TRUE)
111 insw(dep->de_data_port, dst, size);
112 else
113 insb(dep->de_data_port, dst, size);
114 }
115
116 /*
117 ** Name: pio_nic2user
118 ** Function: Copies a packet from board to user area (Prog. I/O).
119 */
pio_nic2user(dpeth_t * dep,int pageno,struct netdriver_data * data,size_t size)120 static void pio_nic2user(dpeth_t *dep, int pageno, struct netdriver_data *data,
121 size_t size)
122 {
123 size_t offset, left;
124
125 /* Computes memory address (skipping receive header) */
126 offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
127
128 if (offset + size > dep->de_stoppage * DP_PAGESIZE) {
129 left = dep->de_stoppage * DP_PAGESIZE - offset;
130
131 ns_rw_setup(dep, CR_DM_RR, left, offset);
132
133 if (dep->de_16bit)
134 netdriver_portinw(data, 0, dep->de_data_port, left);
135 else
136 netdriver_portinb(data, 0, dep->de_data_port, left);
137
138 offset = dep->de_startpage * DP_PAGESIZE;
139 } else
140 left = 0;
141
142 ns_rw_setup(dep, CR_DM_RR, size - left, offset);
143
144 if (dep->de_16bit)
145 netdriver_portinw(data, left, dep->de_data_port, size - left);
146 else
147 netdriver_portinb(data, left, dep->de_data_port, size - left);
148 }
149
150 /*
151 ** Name: pio_user2nic
152 ** Function: Copies a packet from user area to board (Prog. I/O).
153 */
pio_user2nic(dpeth_t * dep,int pageno,struct netdriver_data * data,size_t size)154 static void pio_user2nic(dpeth_t *dep, int pageno, struct netdriver_data *data,
155 size_t size)
156 {
157 int ix;
158
159 /* Sets up board for writing */
160 ns_rw_setup(dep, CR_DM_RW, size, pageno * DP_PAGESIZE);
161
162 if (dep->de_16bit)
163 netdriver_portoutw(data, 0, dep->de_data_port, size);
164 else
165 netdriver_portoutb(data, 0, dep->de_data_port, size);
166
167 for (ix = 0; ix < 100; ix += 1) {
168 if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
169 }
170 if (ix == 100)
171 panic("remote dma failed to complete");
172 }
173
174 /*
175 ** Name: ns_stats
176 ** Function: Updates counters reading from device
177 */
ns_stats(dpeth_t * dep)178 static void ns_stats(dpeth_t * dep)
179 {
180
181 netdriver_stat_ierror(inb_reg0(dep, DP_CNTR0));
182 netdriver_stat_ierror(inb_reg0(dep, DP_CNTR1));
183 netdriver_stat_ierror(inb_reg0(dep, DP_CNTR2));
184 }
185
186 /*
187 ** Name: ns_dodump
188 ** Function: Displays statistics (a request from a function key).
189 */
ns_dodump(dpeth_t * dep)190 static void ns_dodump(dpeth_t * dep)
191 {
192
193 ns_stats(dep); /* Forces reading of counters from board */
194 }
195
196 /*
197 ** Name: ns_reinit
198 ** Function: Updates receiver configuration.
199 */
ns_reinit(dpeth_t * dep)200 static void ns_reinit(dpeth_t * dep)
201 {
202 int dp_reg = 0;
203
204 if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
205 if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
206 if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
207 outb_reg0(dep, DP_CR, CR_PS_P0);
208 outb_reg0(dep, DP_RCR, dp_reg);
209 }
210
211 /*
212 ** Name: ns_send
213 ** Function: Transfers packet to device and starts sending.
214 */
ns_send(dpeth_t * dep,struct netdriver_data * data,size_t size)215 static int ns_send(dpeth_t *dep, struct netdriver_data *data, size_t size)
216 {
217 unsigned int queue;
218
219 queue = dep->de_sendq_head;
220 if (dep->de_sendq[queue].sq_filled)
221 return SUSPEND;
222
223 (dep->de_user2nicf)(dep, dep->de_sendq[queue].sq_sendpage, data, size);
224 dep->bytes_Tx += (long) size;
225 dep->de_sendq[queue].sq_filled = TRUE;
226 dep->de_flags |= DEF_XMIT_BUSY;
227 if (dep->de_sendq_tail == queue) { /* there it goes.. */
228 ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
229 } else
230 dep->de_sendq[queue].sq_size = size;
231
232 if (++queue == dep->de_sendq_nr) queue = 0;
233 dep->de_sendq_head = queue;
234
235 return OK;
236 }
237
238 /*
239 ** Name: ns_reset
240 ** Function: Resets device.
241 */
ns_reset(dpeth_t * dep)242 static void ns_reset(dpeth_t * dep)
243 {
244 unsigned int ix;
245
246 /* Stop chip */
247 outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
248 outb_reg0(dep, DP_RBCR0, 0);
249 outb_reg0(dep, DP_RBCR1, 0);
250 for (ix = 0; ix < 0x1000 && (inb_reg0(dep, DP_ISR) & ISR_RST) == 0; ix += 1)
251 /* Do nothing */ ;
252 outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
253 outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
254 outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
255
256 /* Acknowledge the ISR_RDC (remote dma) interrupt. */
257 for (ix = 0; ix < 0x1000 && (inb_reg0(dep, DP_ISR) & ISR_RDC) == 0; ix += 1)
258 /* Do nothing */ ;
259 outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
260
261 /* Reset the transmit ring. If we were transmitting a packet, we
262 * pretend that the packet is processed. Higher layers will
263 * retransmit if the packet wasn't actually sent. */
264 dep->de_sendq_head = dep->de_sendq_tail = 0;
265 for (ix = 0; ix < dep->de_sendq_nr; ix++)
266 dep->de_sendq[ix].sq_filled = FALSE;
267 netdriver_send();
268 }
269
270 /*
271 ** Name: ns_recv
272 ** Function: Gets a packet from device
273 */
ns_recv(dpeth_t * dep,struct netdriver_data * data,size_t max)274 static ssize_t ns_recv(dpeth_t *dep, struct netdriver_data *data, size_t max)
275 {
276 dp_rcvhdr_t header;
277 unsigned pageno, curr, next;
278 size_t length;
279 int packet_processed = FALSE;
280 #ifdef ETH_IGN_PROTO
281 u16_t eth_type;
282 #endif
283
284 pageno = inb_reg0(dep, DP_BNRY) + 1;
285 if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
286
287 do {
288 /* */
289 outb_reg0(dep, DP_CR, CR_PS_P1);
290 curr = inb_reg1(dep, DP_CURR);
291 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
292
293 if (curr == pageno)
294 return SUSPEND;
295
296 (dep->de_getblockf)(dep, pageno * DP_PAGESIZE, sizeof(header),
297 &header);
298 #ifdef ETH_IGN_PROTO
299 (dep->de_getblockf)(dep, pageno * DP_PAGESIZE + sizeof(header) +
300 2 * sizeof(netdriver_addr_t), sizeof(eth_type), ð_type);
301 #endif
302 length = (header.dr_rbcl | (header.dr_rbch << 8)) -
303 sizeof(dp_rcvhdr_t);
304 next = header.dr_next;
305
306 if (length < NDEV_ETH_PACKET_MIN || length > max) {
307 printf("%s: packet with strange length arrived: %zu\n",
308 netdriver_name(), length);
309 netdriver_stat_ierror(1);
310 next = curr;
311
312 } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
313 printf("%s: strange next page\n", netdriver_name());
314 netdriver_stat_ierror(1);
315 next = curr;
316 #ifdef ETH_IGN_PROTO
317 } else if (eth_type == eth_ign_proto) {
318 /* Hack: ignore packets of a given protocol */
319 static int first = TRUE;
320 if (first) {
321 first = FALSE;
322 printf("%s: dropping proto %04x packet\n",
323 netdriver_name(), ntohs(eth_ign_proto));
324 }
325 next = curr;
326 #endif
327 } else if (header.dr_status & RSR_FO) {
328 /* This is very serious, issue a warning and reset buffers */
329 printf("%s: fifo overrun, resetting receive buffer\n",
330 netdriver_name());
331 netdriver_stat_ierror(1);
332 next = curr;
333
334 } else if (header.dr_status & RSR_PRX) {
335 (dep->de_nic2userf)(dep, pageno, data, length);
336 packet_processed = TRUE;
337 }
338 dep->bytes_Rx += (long) length;
339 outb_reg0(dep, DP_BNRY,
340 (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
341 pageno = next;
342 } while (!packet_processed);
343
344 return length;
345 }
346
347 /*
348 ** Name: ns_interrupt
349 ** Function: Handles interrupt.
350 */
ns_interrupt(dpeth_t * dep)351 static void ns_interrupt(dpeth_t * dep)
352 {
353 int isr, tsr;
354 unsigned int queue;
355
356 while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
357
358 outb_reg0(dep, DP_ISR, isr);
359 if (isr & (ISR_PTX | ISR_TXE)) {
360
361 tsr = inb_reg0(dep, DP_TSR);
362 if (tsr & TSR_PTX) {
363 /* Packet transmission was successful. */
364 }
365 if (tsr & TSR_COL)
366 netdriver_stat_coll(1);
367 if (tsr & (TSR_ABT | TSR_FU)) {
368 netdriver_stat_oerror(1);
369 }
370 if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
371 printf("%s: got send Error (0x%02X)\n",
372 netdriver_name(), tsr);
373 netdriver_stat_oerror(1);
374 }
375 queue = dep->de_sendq_tail;
376
377 if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
378 printf("%s: transmit interrupt, but not sending\n",
379 netdriver_name());
380 continue;
381 }
382 dep->de_sendq[queue].sq_filled = FALSE;
383 if (++queue == dep->de_sendq_nr) queue = 0;
384 dep->de_sendq_tail = queue;
385 if (dep->de_sendq[queue].sq_filled) {
386 ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
387 dep->de_sendq[queue].sq_sendpage);
388 }
389 netdriver_send();
390 }
391 if (isr & ISR_PRX) {
392 netdriver_recv();
393 }
394 if (isr & ISR_RXE) {
395 printf("%s: got recv Error (0x%04X)\n",
396 netdriver_name(), inb_reg0(dep, DP_RSR));
397 netdriver_stat_ierror(1);
398 }
399 if (isr & ISR_CNT) {
400 ns_stats(dep);
401 }
402 if (isr & ISR_OVW) {
403 printf("%s: got overwrite warning\n", netdriver_name());
404 }
405 if (isr & ISR_RDC) {
406 /* Nothing to do */
407 }
408 if (isr & ISR_RST) {
409 /* This means we got an interrupt but the ethernet chip is shut
410 * down. We reset the chip right away, possibly losing received
411 * packets in the process. There used to be a more elaborate
412 * approach of resetting only after all pending packets had
413 * been accepted, but it was broken and this is simpler anyway.
414 */
415 printf("%s: network interface stopped\n",
416 netdriver_name());
417 ns_reset(dep);
418 break;
419 }
420 }
421 }
422
423 /*
424 ** Name: ns_init
425 ** Function: Initializes the NS 8390
426 */
ns_init(dpeth_t * dep)427 void ns_init(dpeth_t * dep)
428 {
429 unsigned int dp_reg;
430 unsigned int ix;
431
432 /* NS8390 initialization (as recommended in National Semiconductor specs) */
433 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
434 outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
435 DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
436 outb_reg0(dep, DP_RBCR0, 0);
437 outb_reg0(dep, DP_RBCR1, 0);
438 outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
439 outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
440 outb_reg0(dep, DP_PSTART, dep->de_startpage);
441 outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
442 outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
443 outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
444 outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */
445
446 /* Copies station address in page 1 registers */
447 outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
448 for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */
449 outb_reg1(dep, DP_PAR0 + ix, dep->de_address.na_addr[ix]);
450 for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */
451 outb_reg1(dep, ix, 0xFF);
452
453 outb_reg1(dep, DP_CURR, dep->de_startpage);
454 outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
455
456 inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */
457 inb_reg0(dep, DP_CNTR1);
458 inb_reg0(dep, DP_CNTR2);
459
460 dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
461 outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
462 outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */
463
464 dp_reg = 0;
465 if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
466 if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
467 if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
468 outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */
469 outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */
470
471 outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */
472
473 /* Initializes the send queue. */
474 for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
475 dep->de_sendq[ix].sq_filled = 0;
476 dep->de_sendq_head = dep->de_sendq_tail = 0;
477
478 /* Device specific functions */
479 if (!dep->de_prog_IO) {
480 dep->de_user2nicf = mem_user2nic;
481 dep->de_nic2userf = mem_nic2user;
482 dep->de_getblockf = mem_getblock;
483 } else {
484 dep->de_user2nicf = pio_user2nic;
485 dep->de_nic2userf = pio_nic2user;
486 dep->de_getblockf = pio_getblock;
487 }
488 dep->de_recvf = ns_recv;
489 dep->de_sendf = ns_send;
490 dep->de_flagsf = ns_reinit;
491 dep->de_resetf = ns_reset;
492 dep->de_getstatsf = ns_stats;
493 dep->de_dumpstatsf = ns_dodump;
494 dep->de_interruptf = ns_interrupt;
495 }
496
497 #endif /* ENABLE_DP8390 */
498
499 /** end 8390.c **/
500