xref: /minix/minix/drivers/net/dpeth/3c501.c (revision 7f5f010b)
1 /*
2 **  File:	3c501.c		Jan. 14, 1997
3 **
4 **  Author:	Giovanni Falzoni <gfalzoni@inwind.it>
5 **
6 **  This file contains specific implementation of the ethernet
7 **  device driver for 3Com Etherlink (3c501) boards.  This is a
8 **  very old board and its performances are very poor for today
9 **  network environments.
10 */
11 
12 #include <minix/drivers.h>
13 #include <minix/com.h>
14 #include <net/gen/ether.h>
15 #include <net/gen/eth_io.h>
16 #include "dp.h"
17 
18 #if (ENABLE_3C501 == 1)
19 
20 #include "3c501.h"
21 
22 static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
23 static buff_t *TxBuff = NULL;
24 
25 /*
26 **  Name:	void el1_getstats(dpeth_t *dep)
27 **  Function:	Reads statistics counters from board.
28 **/
29 static void el1_getstats(dpeth_t * dep)
30 {
31 
32   return;			/* Nothing to do */
33 }
34 
35 /*
36 **  Name:	void el1_reset(dpeth_t *dep)
37 **  Function:	Reset function specific for Etherlink hardware.
38 */
39 static void el1_reset(dpeth_t * dep)
40 {
41   int ix;
42 
43   for (ix = 0; ix < 8; ix += 1)	/* Resets the board */
44 	outb_el1(dep, EL1_CSR, ECSR_RESET);
45   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
46 
47   /* Set Ethernet Address on controller */
48   outb_el1(dep, EL1_CSR, ECSR_LOOP);	/* Loopback mode */
49   for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
50 	outb_el1(dep, ix, StationAddress[ix]);
51 
52   lock();
53   /* Enable DMA/Interrupt, gain control of Buffer */
54   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
55   /* Clear RX packet area */
56   outw_el1(dep, EL1_RECVPTR, 0);
57   /* Enable transmit/receive configuration and flush pending interrupts */
58   outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER);
59   outb_el1(dep, EL1_RECV, dep->de_recv_mode);
60   inb_el1(dep, EL1_RECV);
61   inb_el1(dep, EL1_XMIT);
62   dep->de_flags &= NOT(DEF_XMIT_BUSY);
63   unlock();
64   return;			/* Done */
65 }
66 
67 /*
68 **  Name:	void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size)
69 **  Function:	Dumps counter on screen (support for console display).
70 */
71 static void el1_dumpstats(dpeth_t * UNUSED(dep))
72 {
73 
74   return;
75 }
76 
77 /*
78 **  Name:	void el1_mode_init(dpeth_t *dep)
79 **  Function:	Initializes receicer mode
80 */
81 static void el1_mode_init(dpeth_t * dep)
82 {
83 
84   if (dep->de_flags & DEF_BROAD) {
85 	dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK;
86 
87   } else if (dep->de_flags & DEF_PROMISC) {
88 	dep->de_recv_mode = ERSR_ALL | ERSR_RMASK;
89 
90   } else if (dep->de_flags & DEF_MULTI) {
91 	dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK;
92 
93   } else {
94 	dep->de_recv_mode = ERSR_NONE | ERSR_RMASK;
95   }
96   outb_el1(dep, EL1_RECV, dep->de_recv_mode);
97   inb_el1(dep, EL1_RECV);
98   return;
99 }
100 
101 /*
102 **  Name:	void el1_recv(dpeth_t *dep, int from, int size)
103 **  Function:	Receive function.  Called from interrupt handler to
104 **  		unload recv. buffer or from main (packet to client)
105 */
106 static void el1_recv(dpeth_t * dep, int from, int size)
107 {
108   buff_t *rxptr;
109 
110   while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) {
111 
112 	/* Remove buffer from queue and free buffer */
113 	lock();
114 	if (dep->de_recvq_tail == dep->de_recvq_head)
115 		dep->de_recvq_head = dep->de_recvq_tail = NULL;
116 	else
117 		dep->de_recvq_head = rxptr->next;
118 	unlock();
119 
120 	/* Copy buffer to user area */
121 	mem2user(dep, rxptr);
122 
123 	/* Reply information */
124 	dep->de_read_s = rxptr->size;
125 	dep->de_flags |= DEF_ACK_RECV;
126 	dep->de_flags &= NOT(DEF_READING);
127 
128 	/* Return buffer to the idle pool */
129 	free_buff(dep, rxptr);
130   }
131   return;
132 }
133 
134 /*
135 **  Name:	void el1_send(dpeth_t *dep, int from_int, int pktsize)
136 **  Function:	Send function.  Called from main to transit a packet or
137 **  		from interrupt handler when a new packet was queued.
138 */
139 static void el1_send(dpeth_t * dep, int from_int, int pktsize)
140 {
141   buff_t *txbuff;
142   clock_t now;
143 
144   if (from_int == FALSE) {
145 
146 	if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) {
147 
148 		/*  Fill transmit buffer from user area */
149 		txbuff->next = NULL;
150 		txbuff->size = pktsize;
151 		txbuff->client = dep->de_client;
152 		user2mem(dep, txbuff);
153 	} else
154 		panic("out of memory for Tx");
155 
156   } else if ((txbuff = dep->de_xmitq_head) != NULL) {
157 
158 	/* Get first packet in queue */
159 	lock();
160 	if (dep->de_xmitq_tail == dep->de_xmitq_head)
161 		dep->de_xmitq_head = dep->de_xmitq_tail = NULL;
162 	else
163 		dep->de_xmitq_head = txbuff->next;
164 	unlock();
165 	pktsize = txbuff->size;
166 
167   } else
168 	panic("should not be sending ");
169 
170   if ((dep->de_flags & DEF_XMIT_BUSY)) {
171 	if (from_int) panic("should not be sending ");
172 	getticks(&now);
173 	if ((now - dep->de_xmit_start) > 4) {
174 		/* Transmitter timed out */
175 		DEBUG(printf("3c501: transmitter timed out ... \n"));
176 		dep->de_stat.ets_sendErr += 1;
177 		dep->de_flags &= NOT(DEF_XMIT_BUSY);
178 		el1_reset(dep);
179 	}
180 
181 	/* Queue packet */
182 	lock();			/* Queue packet to receive queue */
183 	if (dep->de_xmitq_head == NULL)
184 		dep->de_xmitq_head = txbuff;
185 	else
186 		dep->de_xmitq_tail->next = txbuff;
187 	dep->de_xmitq_tail = txbuff;
188 	unlock();
189   } else {
190 	/* Save for retransmission */
191 	TxBuff = txbuff;
192 	dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
193 
194 	/* Setup board for packet loading */
195 	lock();			/* Buffer to processor */
196 	outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
197 	inb_el1(dep, EL1_RECV);	/* Clears any spurious interrupt */
198 	inb_el1(dep, EL1_XMIT);
199 	outw_el1(dep, EL1_RECVPTR, 0);	/* Clears RX packet area */
200 
201 	/* Loads packet */
202 	outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
203 	outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize);
204 	/* Starts transmitter */
205 	outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
206 	outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);	/* There it goes... */
207 	unlock();
208 
209 	getticks(&dep->de_xmit_start);
210 	dep->de_flags &= NOT(DEF_SENDING);
211   }
212   return;
213 }
214 
215 /*
216 **  Name:	void el1_stop(dpeth_t *dep)
217 **  Function:	Stops board and disable interrupts.
218 */
219 static void el1_stop(dpeth_t * dep)
220 {
221   int ix;
222 
223   DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name));
224   for (ix = 0; ix < 8; ix += 1)	/* Reset board */
225 	outb_el1(dep, EL1_CSR, ECSR_RESET);
226   outb_el1(dep, EL1_CSR, ECSR_SYS);
227   sys_irqdisable(&dep->de_hook);	/* Disable interrupt */
228   return;
229 }
230 
231 /*
232 **  Name:	void el1_interrupt(dpeth_t *dep)
233 **  Function:	Interrupt handler.  Acknwledges transmit interrupts
234 **  		or unloads receive buffer to memory queue.
235 */
236 static void el1_interrupt(dpeth_t * dep)
237 {
238   u16_t csr, isr;
239   int pktsize;
240   buff_t *rxptr;
241 
242   csr = inb_el1(dep, EL1_CSR);
243   if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) {
244 
245 	/* Got a transmit interrupt */
246 	isr = inb_el1(dep, EL1_XMIT);
247 	if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) {
248 	DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr));
249 		if (isr & EXSR_JAM) {
250 			/* Sending, packet got a collision */
251 			dep->de_stat.ets_collision += 1;
252 			/* Put pointer back to beginning of packet */
253 			outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
254 			outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size));
255 			/* And retrigger transmission */
256 			outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);
257 			return;
258 
259 		} else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) {
260 			dep->de_stat.ets_sendErr += 1;
261 
262 		} else if (isr & EXSR_UNDER) {
263 			dep->de_stat.ets_fifoUnder += 1;
264 		}
265 		DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
266 		el1_reset(dep);
267 
268 	} else {
269 		/** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
270 		/* Packet transmitted successfully */
271 		dep->de_stat.ets_packetT += 1;
272 		dep->bytes_Tx += (long) (TxBuff->size);
273 		free_buff(dep, TxBuff);
274 		dep->de_flags &= NOT(DEF_XMIT_BUSY);
275 		if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) {
276 			/* Pending transmit request available in queue */
277 			el1_send(dep, TRUE, 0);
278 			if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND))
279 				return;
280 		}
281 	}
282 
283   } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
284 
285 	/* Got a receive interrupt */
286 	isr = inb_el1(dep, EL1_RECV);
287 	pktsize = inw_el1(dep, EL1_RECVPTR);
288 	if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) {
289 	DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
290 		dep->de_stat.ets_recvErr += 1;
291 
292 	} else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) {
293 	DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
294 		dep->de_stat.ets_recvErr += 1;
295 
296 	} else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
297 		/* Memory not available. Drop packet */
298 		dep->de_stat.ets_fifoOver += 1;
299 
300 	} else if (isr & (ERSR_GOOD | ERSR_ANY)) {
301 		/* Got a good packet. Read it from buffer */
302 		outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
303 		outw_el1(dep, EL1_XMITPTR, 0);
304 		insb(dep->de_data_port, SELF, rxptr->buffer, pktsize);
305 		rxptr->next = NULL;
306 		rxptr->size = pktsize;
307 		dep->de_stat.ets_packetR += 1;
308 		dep->bytes_Rx += (long) pktsize;
309 		lock();		/* Queue packet to receive queue */
310 		if (dep->de_recvq_head == NULL)
311 			dep->de_recvq_head = rxptr;
312 		else
313 			dep->de_recvq_tail->next = rxptr;
314 		dep->de_recvq_tail = rxptr;
315 		unlock();
316 
317 		/* Reply to pending Receive requests, if any */
318 		el1_recv(dep, TRUE, 0);
319 	}
320   } else {			/* Nasty condition, should never happen */
321 	DEBUG(
322 	      printf("3c501: got interrupt with status 0x%02X\n"
323 		     "       de_flags=0x%04X  XSR=0x%02X RSR=0x%02X \n"
324 		     "       xmit buffer = 0x%4X recv buffer = 0x%4X\n",
325 			csr, dep->de_flags,
326 			inb_el1(dep, EL1_RECV),
327 			inb_el1(dep, EL1_XMIT),
328 			inw_el1(dep, EL1_XMITPTR),
329 			inw_el1(dep, EL1_RECVPTR))
330 		);
331 	el1_reset(dep);
332   }
333 
334   /* Move into receive mode */
335   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
336   outw_el1(dep, EL1_RECVPTR, 0);
337   /* Be sure that interrupts are cleared */
338   inb_el1(dep, EL1_RECV);
339   inb_el1(dep, EL1_XMIT);
340   return;
341 }
342 
343 /*
344 **  Name:	void el1_init(dpeth_t *dep)
345 **  Function:	Initalizes board hardware and driver data structures.
346 */
347 static void el1_init(dpeth_t * dep)
348 {
349   int ix;
350 
351   dep->de_irq &= NOT(DEI_DEFAULT);	/* Strip the default flag. */
352   dep->de_offset_page = 0;
353   dep->de_data_port = dep->de_base_port + EL1_DATAPORT;
354 
355   el1_reset(dep);		/* Reset and initialize board */
356 
357   /* Start receiver (default mode) */
358   outw_el1(dep, EL1_RECVPTR, 0);
359   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
360 
361   /* Initializes buffer pool */
362   init_buff(dep, NULL);
363   el1_mode_init(dep);
364 
365   printf("%s: Etherlink (%s) at %X:%d - ",
366          dep->de_name, "3c501", dep->de_base_port, dep->de_irq);
367   for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
368 	printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]),
369 	       ix < SA_ADDR_LEN - 1 ? ':' : '\n');
370 
371   /* Device specific functions */
372   dep->de_recvf = el1_recv;
373   dep->de_sendf = el1_send;
374   dep->de_flagsf = el1_mode_init;
375   dep->de_resetf = el1_reset;
376   dep->de_getstatsf = el1_getstats;
377   dep->de_dumpstatsf = el1_dumpstats;
378   dep->de_interruptf = el1_interrupt;
379 
380   return;			/* Done */
381 }
382 
383 /*
384 **  Name:	int el1_probe(dpeth_t *dep)
385 **  Function:	Checks for presence of the board.
386 */
387 int el1_probe(dpeth_t * dep)
388 {
389   int ix;
390 
391   for (ix = 0; ix < 8; ix += 1)	/* Reset the board */
392 	outb_el1(dep, EL1_CSR, ECSR_RESET);
393   outb_el1(dep, EL1_CSR, ECSR_SYS);	/* Leaves buffer to system */
394 
395   /* Check station address */
396   for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
397 	outw_el1(dep, EL1_XMITPTR, ix);
398 	StationAddress[ix] = inb_el1(dep, EL1_SAPROM);
399   }
400   if (StationAddress[0] != 0x02 ||	/* Etherlink Station address  */
401       StationAddress[1] != 0x60 ||	/* MUST be 02:60:8c:xx:xx:xx  */
402       StationAddress[2] != 0x8C)
403 	return FALSE;		/* No Etherlink board at this address */
404 
405   dep->de_ramsize = 0;		/* RAM size is meaningless */
406   dep->de_linmem = 0L;		/* Access is via I/O port  */
407 
408   /* Device specific functions */
409   dep->de_initf = el1_init;
410   dep->de_stopf = el1_stop;
411 
412   return TRUE;			/* Etherlink board found */
413 }
414 
415 #endif				/* ENABLE_3C501 */
416 
417 /** 3c501.c **/
418