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