2 ** File: 3c501.c Jan. 14, 1997
4 ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
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.
12 #include <minix/drivers.h>
13 #include <minix/com.h>
14 #include <net/gen/ether.h>
15 #include <net/gen/eth_io.h>
18 #if (ENABLE_3C501 == 1)
22 static unsigned char StationAddress
[SA_ADDR_LEN
] = {0, 0, 0, 0, 0, 0,};
23 static buff_t
*TxBuff
= NULL
;
26 ** Name: void el1_getstats(dpeth_t *dep)
27 ** Function: Reads statistics counters from board.
29 static void el1_getstats(dpeth_t
* dep
)
32 return; /* Nothing to do */
36 ** Name: void el1_reset(dpeth_t *dep)
37 ** Function: Reset function specific for Etherlink hardware.
39 static void el1_reset(dpeth_t
* dep
)
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
);
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
]);
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
);
68 ** Name: void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size)
69 ** Function: Dumps counter on screen (support for console display).
71 static void el1_dumpstats(dpeth_t
* UNUSED(dep
))
78 ** Name: void el1_mode_init(dpeth_t *dep)
79 ** Function: Initializes receicer mode
81 static void el1_mode_init(dpeth_t
* dep
)
84 if (dep
->de_flags
& DEF_BROAD
) {
85 dep
->de_recv_mode
= ERSR_BROAD
| ERSR_RMASK
;
87 } else if (dep
->de_flags
& DEF_PROMISC
) {
88 dep
->de_recv_mode
= ERSR_ALL
| ERSR_RMASK
;
90 } else if (dep
->de_flags
& DEF_MULTI
) {
91 dep
->de_recv_mode
= ERSR_MULTI
| ERSR_RMASK
;
94 dep
->de_recv_mode
= ERSR_NONE
| ERSR_RMASK
;
96 outb_el1(dep
, EL1_RECV
, dep
->de_recv_mode
);
97 inb_el1(dep
, EL1_RECV
);
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)
106 static void el1_recv(dpeth_t
* dep
, int from
, int size
)
110 while ((dep
->de_flags
& DEF_READING
) && (rxptr
= dep
->de_recvq_head
)) {
112 /* Remove buffer from queue and free buffer */
114 if (dep
->de_recvq_tail
== dep
->de_recvq_head
)
115 dep
->de_recvq_head
= dep
->de_recvq_tail
= NULL
;
117 dep
->de_recvq_head
= rxptr
->next
;
120 /* Copy buffer to user area */
121 mem2user(dep
, rxptr
);
123 /* Reply information */
124 dep
->de_read_s
= rxptr
->size
;
125 dep
->de_flags
|= DEF_ACK_RECV
;
126 dep
->de_flags
&= NOT(DEF_READING
);
128 /* Return buffer to the idle pool */
129 free_buff(dep
, rxptr
);
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.
139 static void el1_send(dpeth_t
* dep
, int from_int
, int pktsize
)
144 if (from_int
== FALSE
) {
146 if ((txbuff
= alloc_buff(dep
, pktsize
+ sizeof(buff_t
))) != NULL
) {
148 /* Fill transmit buffer from user area */
150 txbuff
->size
= pktsize
;
151 txbuff
->client
= dep
->de_client
;
152 user2mem(dep
, txbuff
);
154 panic("out of memory for Tx");
156 } else if ((txbuff
= dep
->de_xmitq_head
) != NULL
) {
158 /* Get first packet in queue */
160 if (dep
->de_xmitq_tail
== dep
->de_xmitq_head
)
161 dep
->de_xmitq_head
= dep
->de_xmitq_tail
= NULL
;
163 dep
->de_xmitq_head
= txbuff
->next
;
165 pktsize
= txbuff
->size
;
168 panic("should not be sending ");
170 if ((dep
->de_flags
& DEF_XMIT_BUSY
)) {
171 if (from_int
) panic("should not be sending ");
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
);
182 lock(); /* Queue packet to receive queue */
183 if (dep
->de_xmitq_head
== NULL
)
184 dep
->de_xmitq_head
= txbuff
;
186 dep
->de_xmitq_tail
->next
= txbuff
;
187 dep
->de_xmitq_tail
= txbuff
;
190 /* Save for retransmission */
192 dep
->de_flags
|= (DEF_XMIT_BUSY
| DEF_ACK_SEND
);
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 */
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... */
209 getuptime(&dep
->de_xmit_start
);
210 dep
->de_flags
&= NOT(DEF_SENDING
);
216 ** Name: void el1_stop(dpeth_t *dep)
217 ** Function: Stops board and disable interrupts.
219 static void el1_stop(dpeth_t
* dep
)
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 */
232 ** Name: void el1_interrupt(dpeth_t *dep)
233 ** Function: Interrupt handler. Acknwledges transmit interrupts
234 ** or unloads receive buffer to memory queue.
236 static void el1_interrupt(dpeth_t
* dep
)
242 csr
= inb_el1(dep
, EL1_CSR
);
243 if ((csr
& ECSR_XMIT
) && (dep
->de_flags
& DEF_XMIT_BUSY
)) {
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
);
259 } else if ((isr
& EXSR_16JAM
) || !(isr
& EXSR_IDLE
)) {
260 dep
->de_stat
.ets_sendErr
+= 1;
262 } else if (isr
& EXSR_UNDER
) {
263 dep
->de_stat
.ets_fifoUnder
+= 1;
265 DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr
));
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
))
283 } else if ((csr
& (ECSR_RECV
| ECSR_XMTBSY
)) == (ECSR_RECV
| ECSR_XMTBSY
)) {
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;
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;
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;
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
);
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
;
313 dep
->de_recvq_tail
->next
= rxptr
;
314 dep
->de_recvq_tail
= rxptr
;
317 /* Reply to pending Receive requests, if any */
318 el1_recv(dep
, TRUE
, 0);
320 } else { /* Nasty condition, should never happen */
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",
326 inb_el1(dep
, EL1_RECV
),
327 inb_el1(dep
, EL1_XMIT
),
328 inw_el1(dep
, EL1_XMITPTR
),
329 inw_el1(dep
, EL1_RECVPTR
))
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
);
344 ** Name: void el1_init(dpeth_t *dep)
345 ** Function: Initalizes board hardware and driver data structures.
347 static void el1_init(dpeth_t
* dep
)
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
;
355 el1_reset(dep
); /* Reset and initialize board */
357 /* Start receiver (default mode) */
358 outw_el1(dep
, EL1_RECVPTR
, 0);
359 outb_el1(dep
, EL1_CSR
, ECSR_RIDE
| ECSR_RECV
);
361 /* Initializes buffer pool */
362 init_buff(dep
, NULL
);
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');
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
;
384 ** Name: int el1_probe(dpeth_t *dep)
385 ** Function: Checks for presence of the board.
387 int el1_probe(dpeth_t
* dep
)
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 */
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
);
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 */
405 dep
->de_ramsize
= 0; /* RAM size is meaningless */
406 dep
->de_linmem
= 0L; /* Access is via I/O port */
408 /* Device specific functions */
409 dep
->de_initf
= el1_init
;
410 dep
->de_stopf
= el1_stop
;
412 return TRUE
; /* Etherlink board found */
415 #endif /* ENABLE_3C501 */