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