2 ** File: dp.c Version 1.01, Oct. 17, 2007
3 ** Original: eth.c Version 1.00, Jan. 14, 1997
5 ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
7 ** This file contains the ethernet device driver main task.
8 ** It has to be integrated with the board specific drivers.
9 ** It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c)
10 ** to remove bord specific code. It should operate (I hope)
11 ** with any board driver.
14 #include <minix/drivers.h>
15 #include <minix/netdriver.h>
16 #include <minix/endpoint.h>
18 #include <net/gen/ether.h>
19 #include <net/gen/eth_io.h>
26 static dpeth_t de_state
;
27 static int de_instance
;
29 typedef struct dp_conf
{ /* Configuration description structure */
35 /* Device default configuration */
37 static dp_conf_t dp_conf
[DP_CONF_NR
] = {
38 /* I/O port, IRQ, Buff addr, Env. var */
39 { 0x300, 5, 0xC8000, },
40 { 0x280, 10, 0xCC000, },
41 { 0x000, 0, 0x00000, },
44 static char CopyErrMsg
[] = "unable to read/write user data";
45 static char RecvErrMsg
[] = "netdriver_receive failed";
46 static char SendErrMsg
[] = "send failed";
47 static char SizeErrMsg
[] = "illegal packet size";
48 static char TypeErrMsg
[] = "illegal message type";
49 static char DevName
[] = "eth#?";
52 ** Name: void reply(dpeth_t *dep, int err, int m_type)
53 ** Function: Fills a reply message and sends it.
55 static void reply(dpeth_t
* dep
)
61 if (dep
->de_flags
& DEF_ACK_SEND
) flags
|= DL_PACK_SEND
;
62 if (dep
->de_flags
& DEF_ACK_RECV
) flags
|= DL_PACK_RECV
;
64 reply
.m_type
= DL_TASK_REPLY
;
65 reply
.m_netdrv_net_dl_task
.flags
= flags
;
66 reply
.m_netdrv_net_dl_task
.count
= dep
->de_read_s
;
68 DEBUG(printf("\t reply %d (%lx)\n", reply
.m_type
,
69 reply
.m_netdrv_net_dl_task
.flags
));
71 if ((r
= ipc_send(dep
->de_client
, &reply
)) != OK
)
75 dep
->de_flags
&= NOT(DEF_ACK_SEND
| DEF_ACK_RECV
);
81 ** Name: void dp_confaddr(dpeth_t *dep)
82 ** Function: Checks environment for a User defined ethernet address.
84 static void dp_confaddr(dpeth_t
* dep
)
86 static char ea_fmt
[] = "x:x:x:x:x:x";
91 strlcpy(ea_key
, "DPETH0_EA", sizeof(ea_key
));
92 ea_key
[5] += de_instance
;
94 for (ix
= 0; ix
< SA_ADDR_LEN
; ix
++) {
95 val
= dep
->de_address
.ea_addr
[ix
];
96 if (env_parse(ea_key
, ea_fmt
, ix
, &val
, 0x00L
, 0xFFL
) != EP_SET
)
98 dep
->de_address
.ea_addr
[ix
] = val
;
101 if (ix
!= 0 && ix
!= SA_ADDR_LEN
)
102 /* It's all or nothing, force a panic */
103 env_parse(ea_key
, "?", 0, &val
, 0L, 0L);
108 ** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp)
109 ** Function: Gets the default settings from 'dp_conf' table and
110 ** modifies them from the environment.
112 static void update_conf(dpeth_t
* dep
, const dp_conf_t
* dcp
)
114 static char dpc_fmt
[] = "x:d:x";
118 strlcpy(ec_key
, "DPETH0", sizeof(ec_key
));
119 ec_key
[5] += de_instance
;
121 dep
->de_mode
= DEM_SINK
;
122 val
= dcp
->dpc_port
; /* Get I/O port address */
123 switch (env_parse(ec_key
, dpc_fmt
, 0, &val
, 0x000L
, 0x3FFL
)) {
124 case EP_OFF
: dep
->de_mode
= DEM_DISABLED
; break;
126 case EP_SET
: dep
->de_mode
= DEM_ENABLED
; break;
128 dep
->de_base_port
= val
;
130 val
= dcp
->dpc_irq
| DEI_DEFAULT
; /* Get Interrupt line (IRQ) */
131 env_parse(ec_key
, dpc_fmt
, 1, &val
, 0L, (long) NR_IRQ_VECTORS
- 1);
134 val
= dcp
->dpc_mem
; /* Get shared memory address */
135 env_parse(ec_key
, dpc_fmt
, 2, &val
, 0L, LONG_MAX
);
136 dep
->de_linmem
= val
;
142 ** Name: void do_dump(message *mp)
143 ** Function: Displays statistics on screen (SFx key from console)
145 static void do_dump(const message
*mp
)
153 if (dep
->de_mode
== DEM_DISABLED
) return;
155 printf("%s statistics:\t\t", dep
->de_name
);
157 /* Network interface status */
158 printf("Status: 0x%04x (%d)\n\n", dep
->de_flags
, dep
->de_int_pending
);
160 (*dep
->de_dumpstatsf
) (dep
);
162 /* Transmitted/received bytes */
163 printf("Tx bytes:%10ld\t", dep
->bytes_Tx
);
164 printf("Rx bytes:%10ld\n", dep
->bytes_Rx
);
166 /* Transmitted/received packets */
167 printf("Tx OK: %8ld\t", dep
->de_stat
.ets_packetT
);
168 printf("Rx OK: %8ld\n", dep
->de_stat
.ets_packetR
);
170 /* Transmit/receive errors */
171 printf("Tx Err: %8ld\t", dep
->de_stat
.ets_sendErr
);
172 printf("Rx Err: %8ld\n", dep
->de_stat
.ets_recvErr
);
174 /* Transmit unnerruns/receive overrruns */
175 printf("Tx Und: %8ld\t", dep
->de_stat
.ets_fifoUnder
);
176 printf("Rx Ovr: %8ld\n", dep
->de_stat
.ets_fifoOver
);
178 /* Transmit collisions/receive CRC errors */
179 printf("Tx Coll: %8ld\t", dep
->de_stat
.ets_collision
);
180 printf("Rx CRC: %8ld\n", dep
->de_stat
.ets_CRCerr
);
186 ** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
187 ** Function: Copies data from user area.
189 static void get_userdata_s(int user_proc
, cp_grant_id_t grant
,
190 vir_bytes offset
, int count
, void *loc_addr
)
195 len
= (count
> IOVEC_NR
? IOVEC_NR
: count
) * sizeof(iovec_t
);
196 if ((rc
= sys_safecopyfrom(user_proc
, grant
, 0, (vir_bytes
)loc_addr
, len
)) != OK
)
197 panic(CopyErrMsg
, rc
);
202 ** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp);
203 ** Function: Init action to setup task
205 static void do_first_init(dpeth_t
*dep
, const dp_conf_t
*dcp
)
208 dep
->de_linmem
= 0xFFFF0000;
210 /* Make sure statisics are cleared */
211 memset((void *) &(dep
->de_stat
), 0, sizeof(eth_stat_t
));
213 /* Device specific initialization */
214 (*dep
->de_initf
) (dep
);
216 /* Set the interrupt handler policy. Request interrupts not to be reenabled
217 * automatically. Return the IRQ line number when an interrupt occurs.
219 dep
->de_hook
= dep
->de_irq
;
220 if (sys_irqsetpolicy(dep
->de_irq
, 0 /*IRQ_REENABLE*/, &dep
->de_hook
) != OK
)
221 panic("unable to set IRQ policy");
222 dep
->de_int_pending
= FALSE
;
223 sys_irqenable(&dep
->de_hook
);
229 ** Name: void do_init(message *mp)
230 ** Function: Checks for hardware presence.
231 ** Provides initialization of hardware and data structures
233 static void do_init(const message
* mp
)
242 /* Pick a default configuration for this instance. */
243 confnr
= MIN(de_instance
, DP_CONF_NR
-1);
245 dcp
= &dp_conf
[confnr
];
246 strlcpy(dep
->de_name
, DevName
, sizeof(dep
->de_name
));
247 dep
->de_name
[4] = '0' + de_instance
;
249 if (dep
->de_mode
== DEM_DISABLED
) {
251 update_conf(dep
, dcp
); /* First time thru */
252 if (dep
->de_mode
== DEM_ENABLED
&&
253 !el1_probe(dep
) && /* Probe for 3c501 */
254 !wdeth_probe(dep
) && /* Probe for WD80x3 */
255 !ne_probe(dep
) && /* Probe for NEx000 */
256 !el2_probe(dep
) && /* Probe for 3c503 */
257 !el3_probe(dep
)) { /* Probe for 3c509 */
258 printf("%s: warning no ethernet card found at 0x%04X\n",
259 dep
->de_name
, dep
->de_base_port
);
260 dep
->de_mode
= DEM_DISABLED
;
266 /* 'de_mode' may change if probe routines fail, test again */
267 switch (dep
->de_mode
) {
270 /* Device is configured OFF or hardware probe failed */
275 /* Device is present and probed */
276 if (dep
->de_flags
== DEF_EMPTY
) {
277 /* These actions only the first time */
278 do_first_init(dep
, dcp
);
279 dep
->de_flags
|= DEF_ENABLED
;
281 dep
->de_flags
&= NOT(DEF_PROMISC
| DEF_MULTI
| DEF_BROAD
);
282 if (mp
->m_net_netdrv_dl_conf
.mode
& DL_PROMISC_REQ
)
283 dep
->de_flags
|= DEF_PROMISC
| DEF_MULTI
| DEF_BROAD
;
284 if (mp
->m_net_netdrv_dl_conf
.mode
& DL_MULTI_REQ
)
285 dep
->de_flags
|= DEF_MULTI
;
286 if (mp
->m_net_netdrv_dl_conf
.mode
& DL_BROAD_REQ
)
287 dep
->de_flags
|= DEF_BROAD
;
288 (*dep
->de_flagsf
) (dep
);
292 /* Device not present (sink mode) */
293 memset(dep
->de_address
.ea_addr
, 0, sizeof(ether_addr_t
));
294 dp_confaddr(dep
); /* Station address from env. */
300 reply_mess
.m_type
= DL_CONF_REPLY
;
301 reply_mess
.m_netdrv_net_dl_conf
.stat
= r
;
303 memcpy(reply_mess
.m_netdrv_net_dl_conf
.hw_addr
, dep
->de_address
.ea_addr
,
304 sizeof(reply_mess
.m_netdrv_net_dl_conf
.hw_addr
));
305 DEBUG(printf("\t reply %d\n", reply_mess
.m_type
));
306 if (ipc_send(mp
->m_source
, &reply_mess
) != OK
) /* Can't send */
307 panic(SendErrMsg
, mp
->m_source
);
313 ** Name: void dp_next_iovec(iovec_dat_t *iovp)
314 ** Function: Retrieves data from next iovec element.
316 void dp_next_iovec(iovec_dat_s_t
* iovp
)
319 iovp
->iod_iovec_s
-= IOVEC_NR
;
320 iovp
->iod_iovec_offset
+= IOVEC_NR
* sizeof(iovec_t
);
321 get_userdata_s(iovp
->iod_proc_nr
, iovp
->iod_grant
, iovp
->iod_iovec_offset
,
322 iovp
->iod_iovec_s
, iovp
->iod_iovec
);
327 ** Name: int calc_iovec_size(iovec_dat_t *iovp)
328 ** Function: Compute the size of a request.
330 static int calc_iovec_size(iovec_dat_s_t
* iovp
)
336 size
+= iovp
->iod_iovec
[ix
].iov_size
;
337 if (++ix
>= IOVEC_NR
) {
342 /* Till all vectors added */
343 } while (ix
< iovp
->iod_iovec_s
);
348 ** Name: void do_vwrite_s(message *mp)
351 static void do_vwrite_s(const message
* mp
)
358 dep
->de_client
= mp
->m_source
;
360 if (dep
->de_mode
== DEM_ENABLED
) {
362 if (dep
->de_flags
& DEF_SENDING
) /* Is sending in progress? */
363 panic("send already in progress ");
365 dep
->de_write_iovec
.iod_proc_nr
= mp
->m_source
;
366 get_userdata_s(mp
->m_source
, mp
->m_net_netdrv_dl_writev_s
.grant
, 0,
367 mp
->m_net_netdrv_dl_writev_s
.count
, dep
->de_write_iovec
.iod_iovec
);
368 dep
->de_write_iovec
.iod_iovec_s
= mp
->m_net_netdrv_dl_writev_s
.count
;
369 dep
->de_write_iovec
.iod_grant
= mp
->m_net_netdrv_dl_writev_s
.grant
;
370 dep
->de_write_iovec
.iod_iovec_offset
= 0;
371 size
= calc_iovec_size(&dep
->de_write_iovec
);
372 if (size
< ETH_MIN_PACK_SIZE
|| size
> ETH_MAX_PACK_SIZE
)
373 panic(SizeErrMsg
, size
);
375 dep
->de_flags
|= DEF_SENDING
;
376 (*dep
->de_sendf
) (dep
, FALSE
, size
);
378 } else if (dep
->de_mode
== DEM_SINK
)
379 dep
->de_flags
|= DEF_ACK_SEND
;
386 ** Name: void do_vread_s(message *mp, int vectored)
389 static void do_vread_s(const message
* mp
)
396 dep
->de_client
= mp
->m_source
;
398 if (dep
->de_mode
== DEM_ENABLED
) {
400 if (dep
->de_flags
& DEF_READING
) /* Reading in progress */
401 panic("read already in progress");
403 dep
->de_read_iovec
.iod_proc_nr
= mp
->m_source
;
404 get_userdata_s(mp
->m_source
, mp
->m_net_netdrv_dl_readv_s
.grant
, 0,
405 mp
->m_net_netdrv_dl_readv_s
.count
, dep
->de_read_iovec
.iod_iovec
);
406 dep
->de_read_iovec
.iod_iovec_s
= mp
->m_net_netdrv_dl_readv_s
.count
;
407 dep
->de_read_iovec
.iod_grant
= mp
->m_net_netdrv_dl_readv_s
.grant
;
408 dep
->de_read_iovec
.iod_iovec_offset
= 0;
409 size
= calc_iovec_size(&dep
->de_read_iovec
);
410 if (size
< ETH_MAX_PACK_SIZE
) panic(SizeErrMsg
, size
);
412 dep
->de_flags
|= DEF_READING
;
413 (*dep
->de_recvf
) (dep
, FALSE
, size
);
415 if ((dep
->de_flags
& (DEF_READING
| DEF_STOPPED
)) == (DEF_READING
| DEF_STOPPED
))
416 /* The chip is stopped, and all arrived packets delivered */
417 (*dep
->de_resetf
) (dep
);
418 dep
->de_flags
&= NOT(DEF_STOPPED
);
426 ** Name: void do_getstat_s(message *mp)
427 ** Function: Reports device statistics.
429 static void do_getstat_s(const message
* mp
)
437 if (dep
->de_mode
== DEM_ENABLED
) (*dep
->de_getstatsf
) (dep
);
438 if ((rc
= sys_safecopyto(mp
->m_source
, mp
->m_net_netdrv_dl_getstat_s
.grant
, 0,
439 (vir_bytes
)&dep
->de_stat
,
440 (vir_bytes
)sizeof(dep
->de_stat
))) != OK
)
441 panic(CopyErrMsg
, rc
);
443 reply_mess
.m_type
= DL_STAT_REPLY
;
444 rc
= ipc_send(mp
->m_source
, &reply_mess
);
446 panic("do_getname: ipc_send failed: %d", rc
);
451 ** Name: void dp_stop(dpeth_t *dep)
452 ** Function: Stops network interface.
454 static void dp_stop(dpeth_t
* dep
)
457 if (dep
->de_mode
== DEM_ENABLED
&& (dep
->de_flags
& DEF_ENABLED
)) {
460 (dep
->de_stopf
) (dep
);
461 dep
->de_flags
= DEF_EMPTY
;
462 dep
->de_mode
= DEM_DISABLED
;
467 static void do_watchdog(const void *UNUSED(message
))
470 DEBUG(printf("\t no reply"));
474 static void handle_hw_intr(void)
480 /* If device is enabled and interrupt pending */
481 if (dep
->de_mode
== DEM_ENABLED
) {
482 dep
->de_int_pending
= TRUE
;
483 (*dep
->de_interruptf
) (dep
);
484 if (dep
->de_flags
& (DEF_ACK_SEND
| DEF_ACK_RECV
))
486 dep
->de_int_pending
= FALSE
;
487 sys_irqenable(&dep
->de_hook
);
491 /* SEF functions and variables. */
492 static void sef_local_startup(void);
493 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
494 static void sef_cb_signal_handler(int signo
);
497 ** Name: int dpeth_task(void)
498 ** Function: Main entry for dp task
500 int main(int argc
, char **argv
)
506 /* SEF local startup. */
507 env_setargs(argc
, argv
);
511 if ((rc
= netdriver_receive(ANY
, &m
, &ipc_status
)) != OK
){
512 panic(RecvErrMsg
, rc
);
515 DEBUG(printf("eth: got message %d, ", m
.m_type
));
517 if (is_ipc_notify(ipc_status
)) {
518 switch(_ENDPOINT_P(m
.m_source
)) {
524 /* Interrupt from device */
528 /* Function key pressed */
532 /* Invalid message type */
533 panic(TypeErrMsg
, m
.m_type
);
536 /* message processed, get another one */
541 case DL_WRITEV_S
: /* Write message to device */
544 case DL_READV_S
: /* Read message from device */
547 case DL_CONF
: /* Initialize device */
550 case DL_GETSTAT_S
: /* Get device statistics */
553 default: /* Invalid message type */
554 panic(TypeErrMsg
, m
.m_type
);
558 return OK
; /* Never reached, but keeps compiler happy */
561 /*===========================================================================*
562 * sef_local_startup *
563 *===========================================================================*/
564 static void sef_local_startup()
566 /* Register init callbacks. */
567 sef_setcb_init_fresh(sef_cb_init_fresh
);
568 sef_setcb_init_lu(sef_cb_init_fresh
);
569 sef_setcb_init_restart(sef_cb_init_fresh
);
571 /* Register live update callbacks. */
572 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready
);
573 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree
);
575 /* Register signal callbacks. */
576 sef_setcb_signal_handler(sef_cb_signal_handler
);
578 /* Let SEF perform startup. */
582 /*===========================================================================*
583 * sef_cb_init_fresh *
584 *===========================================================================*/
585 static int sef_cb_init_fresh(int type
, sef_init_info_t
*UNUSED(info
))
587 /* Initialize the dpeth driver. */
591 /* Request function key for debug dumps */
592 fkeys
= sfkeys
= 0; bit_set(sfkeys
, 8);
593 if ((fkey_map(&fkeys
, &sfkeys
)) != OK
)
594 printf("%s: couldn't program Shift+F8 key (%d)\n", DevName
, errno
);
597 (void) env_parse("instance", "d", 0, &v
, 0, 255);
598 de_instance
= (int) v
;
600 /* Announce we are up! */
601 netdriver_announce();
606 /*===========================================================================*
607 * sef_cb_signal_handler *
608 *===========================================================================*/
609 static void sef_cb_signal_handler(int signo
)
611 /* Only check for termination signal, ignore anything else. */
612 if (signo
!= SIGTERM
) return;
614 if (de_state
.de_mode
== DEM_ENABLED
)