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
.DL_FLAGS
= flags
;
66 reply
.DL_COUNT
= dep
->de_read_s
;
68 DEBUG(printf("\t reply %d (%lx)\n", reply
.m_type
, reply
.DL_FLAGS
));
70 if ((r
= send(dep
->de_client
, &reply
)) != OK
)
74 dep
->de_flags
&= NOT(DEF_ACK_SEND
| DEF_ACK_RECV
);
80 ** Name: void dp_confaddr(dpeth_t *dep)
81 ** Function: Checks environment for a User defined ethernet address.
83 static void dp_confaddr(dpeth_t
* dep
)
85 static char ea_fmt
[] = "x:x:x:x:x:x";
90 strlcpy(ea_key
, "DPETH0_EA", sizeof(ea_key
));
91 ea_key
[5] += de_instance
;
93 for (ix
= 0; ix
< SA_ADDR_LEN
; ix
++) {
94 val
= dep
->de_address
.ea_addr
[ix
];
95 if (env_parse(ea_key
, ea_fmt
, ix
, &val
, 0x00L
, 0xFFL
) != EP_SET
)
97 dep
->de_address
.ea_addr
[ix
] = val
;
100 if (ix
!= 0 && ix
!= SA_ADDR_LEN
)
101 /* It's all or nothing, force a panic */
102 env_parse(ea_key
, "?", 0, &val
, 0L, 0L);
107 ** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp)
108 ** Function: Gets the default settings from 'dp_conf' table and
109 ** modifies them from the environment.
111 static void update_conf(dpeth_t
* dep
, const dp_conf_t
* dcp
)
113 static char dpc_fmt
[] = "x:d:x";
117 strlcpy(ec_key
, "DPETH0", sizeof(ec_key
));
118 ec_key
[5] += de_instance
;
120 dep
->de_mode
= DEM_SINK
;
121 val
= dcp
->dpc_port
; /* Get I/O port address */
122 switch (env_parse(ec_key
, dpc_fmt
, 0, &val
, 0x000L
, 0x3FFL
)) {
123 case EP_OFF
: dep
->de_mode
= DEM_DISABLED
; break;
125 case EP_SET
: dep
->de_mode
= DEM_ENABLED
; break;
127 dep
->de_base_port
= val
;
129 val
= dcp
->dpc_irq
| DEI_DEFAULT
; /* Get Interrupt line (IRQ) */
130 env_parse(ec_key
, dpc_fmt
, 1, &val
, 0L, (long) NR_IRQ_VECTORS
- 1);
133 val
= dcp
->dpc_mem
; /* Get shared memory address */
134 env_parse(ec_key
, dpc_fmt
, 2, &val
, 0L, LONG_MAX
);
135 dep
->de_linmem
= val
;
141 ** Name: void do_dump(message *mp)
142 ** Function: Displays statistics on screen (SFx key from console)
144 static void do_dump(const message
*mp
)
152 if (dep
->de_mode
== DEM_DISABLED
) return;
154 printf("%s statistics:\t\t", dep
->de_name
);
156 /* Network interface status */
157 printf("Status: 0x%04x (%d)\n\n", dep
->de_flags
, dep
->de_int_pending
);
159 (*dep
->de_dumpstatsf
) (dep
);
161 /* Transmitted/received bytes */
162 printf("Tx bytes:%10ld\t", dep
->bytes_Tx
);
163 printf("Rx bytes:%10ld\n", dep
->bytes_Rx
);
165 /* Transmitted/received packets */
166 printf("Tx OK: %8ld\t", dep
->de_stat
.ets_packetT
);
167 printf("Rx OK: %8ld\n", dep
->de_stat
.ets_packetR
);
169 /* Transmit/receive errors */
170 printf("Tx Err: %8ld\t", dep
->de_stat
.ets_sendErr
);
171 printf("Rx Err: %8ld\n", dep
->de_stat
.ets_recvErr
);
173 /* Transmit unnerruns/receive overrruns */
174 printf("Tx Und: %8ld\t", dep
->de_stat
.ets_fifoUnder
);
175 printf("Rx Ovr: %8ld\n", dep
->de_stat
.ets_fifoOver
);
177 /* Transmit collisions/receive CRC errors */
178 printf("Tx Coll: %8ld\t", dep
->de_stat
.ets_collision
);
179 printf("Rx CRC: %8ld\n", dep
->de_stat
.ets_CRCerr
);
185 ** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
186 ** Function: Copies data from user area.
188 static void get_userdata_s(int user_proc
, cp_grant_id_t grant
,
189 vir_bytes offset
, int count
, void *loc_addr
)
194 len
= (count
> IOVEC_NR
? IOVEC_NR
: count
) * sizeof(iovec_t
);
195 if ((rc
= sys_safecopyfrom(user_proc
, grant
, 0, (vir_bytes
)loc_addr
, len
)) != OK
)
196 panic(CopyErrMsg
, rc
);
201 ** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp);
202 ** Function: Init action to setup task
204 static void do_first_init(dpeth_t
*dep
, const dp_conf_t
*dcp
)
207 dep
->de_linmem
= 0xFFFF0000;
209 /* Make sure statisics are cleared */
210 memset((void *) &(dep
->de_stat
), 0, sizeof(eth_stat_t
));
212 /* Device specific initialization */
213 (*dep
->de_initf
) (dep
);
215 /* Set the interrupt handler policy. Request interrupts not to be reenabled
216 * automatically. Return the IRQ line number when an interrupt occurs.
218 dep
->de_hook
= dep
->de_irq
;
219 if (sys_irqsetpolicy(dep
->de_irq
, 0 /*IRQ_REENABLE*/, &dep
->de_hook
) != OK
)
220 panic("unable to set IRQ policy");
221 dep
->de_int_pending
= FALSE
;
222 sys_irqenable(&dep
->de_hook
);
228 ** Name: void do_init(message *mp)
229 ** Function: Checks for hardware presence.
230 ** Provides initialization of hardware and data structures
232 static void do_init(const message
* mp
)
241 /* Pick a default configuration for this instance. */
242 confnr
= MIN(de_instance
, DP_CONF_NR
-1);
244 dcp
= &dp_conf
[confnr
];
245 strlcpy(dep
->de_name
, DevName
, sizeof(dep
->de_name
));
246 dep
->de_name
[4] = '0' + de_instance
;
248 if (dep
->de_mode
== DEM_DISABLED
) {
250 update_conf(dep
, dcp
); /* First time thru */
251 if (dep
->de_mode
== DEM_ENABLED
&&
252 !el1_probe(dep
) && /* Probe for 3c501 */
253 !wdeth_probe(dep
) && /* Probe for WD80x3 */
254 !ne_probe(dep
) && /* Probe for NEx000 */
255 !el2_probe(dep
) && /* Probe for 3c503 */
256 !el3_probe(dep
)) { /* Probe for 3c509 */
257 printf("%s: warning no ethernet card found at 0x%04X\n",
258 dep
->de_name
, dep
->de_base_port
);
259 dep
->de_mode
= DEM_DISABLED
;
265 /* 'de_mode' may change if probe routines fail, test again */
266 switch (dep
->de_mode
) {
269 /* Device is configured OFF or hardware probe failed */
274 /* Device is present and probed */
275 if (dep
->de_flags
== DEF_EMPTY
) {
276 /* These actions only the first time */
277 do_first_init(dep
, dcp
);
278 dep
->de_flags
|= DEF_ENABLED
;
280 dep
->de_flags
&= NOT(DEF_PROMISC
| DEF_MULTI
| DEF_BROAD
);
281 if (mp
->DL_MODE
& DL_PROMISC_REQ
)
282 dep
->de_flags
|= DEF_PROMISC
| DEF_MULTI
| DEF_BROAD
;
283 if (mp
->DL_MODE
& DL_MULTI_REQ
) dep
->de_flags
|= DEF_MULTI
;
284 if (mp
->DL_MODE
& DL_BROAD_REQ
) dep
->de_flags
|= DEF_BROAD
;
285 (*dep
->de_flagsf
) (dep
);
289 /* Device not present (sink mode) */
290 memset(dep
->de_address
.ea_addr
, 0, sizeof(ether_addr_t
));
291 dp_confaddr(dep
); /* Station address from env. */
297 reply_mess
.m_type
= DL_CONF_REPLY
;
298 reply_mess
.DL_STAT
= r
;
300 *(ether_addr_t
*) reply_mess
.DL_HWADDR
= dep
->de_address
;
301 DEBUG(printf("\t reply %d\n", reply_mess
.m_type
));
302 if (send(mp
->m_source
, &reply_mess
) != OK
) /* Can't send */
303 panic(SendErrMsg
, mp
->m_source
);
309 ** Name: void dp_next_iovec(iovec_dat_t *iovp)
310 ** Function: Retrieves data from next iovec element.
312 void dp_next_iovec(iovec_dat_s_t
* iovp
)
315 iovp
->iod_iovec_s
-= IOVEC_NR
;
316 iovp
->iod_iovec_offset
+= IOVEC_NR
* sizeof(iovec_t
);
317 get_userdata_s(iovp
->iod_proc_nr
, iovp
->iod_grant
, iovp
->iod_iovec_offset
,
318 iovp
->iod_iovec_s
, iovp
->iod_iovec
);
323 ** Name: int calc_iovec_size(iovec_dat_t *iovp)
324 ** Function: Compute the size of a request.
326 static int calc_iovec_size(iovec_dat_s_t
* iovp
)
332 size
+= iovp
->iod_iovec
[ix
].iov_size
;
333 if (++ix
>= IOVEC_NR
) {
338 /* Till all vectors added */
339 } while (ix
< iovp
->iod_iovec_s
);
344 ** Name: void do_vwrite_s(message *mp)
347 static void do_vwrite_s(const message
* mp
)
354 dep
->de_client
= mp
->m_source
;
356 if (dep
->de_mode
== DEM_ENABLED
) {
358 if (dep
->de_flags
& DEF_SENDING
) /* Is sending in progress? */
359 panic("send already in progress ");
361 dep
->de_write_iovec
.iod_proc_nr
= mp
->m_source
;
362 get_userdata_s(mp
->m_source
, mp
->DL_GRANT
, 0,
363 mp
->DL_COUNT
, dep
->de_write_iovec
.iod_iovec
);
364 dep
->de_write_iovec
.iod_iovec_s
= mp
->DL_COUNT
;
365 dep
->de_write_iovec
.iod_grant
= (cp_grant_id_t
) mp
->DL_GRANT
;
366 dep
->de_write_iovec
.iod_iovec_offset
= 0;
367 size
= calc_iovec_size(&dep
->de_write_iovec
);
368 if (size
< ETH_MIN_PACK_SIZE
|| size
> ETH_MAX_PACK_SIZE
)
369 panic(SizeErrMsg
, size
);
371 dep
->de_flags
|= DEF_SENDING
;
372 (*dep
->de_sendf
) (dep
, FALSE
, size
);
374 } else if (dep
->de_mode
== DEM_SINK
)
375 dep
->de_flags
|= DEF_ACK_SEND
;
382 ** Name: void do_vread_s(message *mp, int vectored)
385 static void do_vread_s(const message
* mp
)
392 dep
->de_client
= mp
->m_source
;
394 if (dep
->de_mode
== DEM_ENABLED
) {
396 if (dep
->de_flags
& DEF_READING
) /* Reading in progress */
397 panic("read already in progress");
399 dep
->de_read_iovec
.iod_proc_nr
= mp
->m_source
;
400 get_userdata_s(mp
->m_source
, (cp_grant_id_t
) mp
->DL_GRANT
, 0,
401 mp
->DL_COUNT
, dep
->de_read_iovec
.iod_iovec
);
402 dep
->de_read_iovec
.iod_iovec_s
= mp
->DL_COUNT
;
403 dep
->de_read_iovec
.iod_grant
= (cp_grant_id_t
) mp
->DL_GRANT
;
404 dep
->de_read_iovec
.iod_iovec_offset
= 0;
405 size
= calc_iovec_size(&dep
->de_read_iovec
);
406 if (size
< ETH_MAX_PACK_SIZE
) panic(SizeErrMsg
, size
);
408 dep
->de_flags
|= DEF_READING
;
409 (*dep
->de_recvf
) (dep
, FALSE
, size
);
411 if ((dep
->de_flags
& (DEF_READING
| DEF_STOPPED
)) == (DEF_READING
| DEF_STOPPED
))
412 /* The chip is stopped, and all arrived packets delivered */
413 (*dep
->de_resetf
) (dep
);
414 dep
->de_flags
&= NOT(DEF_STOPPED
);
422 ** Name: void do_getstat_s(message *mp)
423 ** Function: Reports device statistics.
425 static void do_getstat_s(const message
* mp
)
433 if (dep
->de_mode
== DEM_ENABLED
) (*dep
->de_getstatsf
) (dep
);
434 if ((rc
= sys_safecopyto(mp
->m_source
, mp
->DL_GRANT
, 0,
435 (vir_bytes
)&dep
->de_stat
,
436 (vir_bytes
) sizeof(dep
->de_stat
))) != OK
)
437 panic(CopyErrMsg
, rc
);
439 reply_mess
.m_type
= DL_STAT_REPLY
;
440 rc
= send(mp
->m_source
, &reply_mess
);
442 panic("do_getname: send failed: %d", rc
);
447 ** Name: void dp_stop(dpeth_t *dep)
448 ** Function: Stops network interface.
450 static void dp_stop(dpeth_t
* dep
)
453 if (dep
->de_mode
== DEM_ENABLED
&& (dep
->de_flags
& DEF_ENABLED
)) {
456 (dep
->de_stopf
) (dep
);
457 dep
->de_flags
= DEF_EMPTY
;
458 dep
->de_mode
= DEM_DISABLED
;
463 static void do_watchdog(const void *UNUSED(message
))
466 DEBUG(printf("\t no reply"));
470 static void handle_hw_intr(void)
476 /* If device is enabled and interrupt pending */
477 if (dep
->de_mode
== DEM_ENABLED
) {
478 dep
->de_int_pending
= TRUE
;
479 (*dep
->de_interruptf
) (dep
);
480 if (dep
->de_flags
& (DEF_ACK_SEND
| DEF_ACK_RECV
))
482 dep
->de_int_pending
= FALSE
;
483 sys_irqenable(&dep
->de_hook
);
487 /* SEF functions and variables. */
488 static void sef_local_startup(void);
489 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
490 static void sef_cb_signal_handler(int signo
);
493 ** Name: int dpeth_task(void)
494 ** Function: Main entry for dp task
496 int main(int argc
, char **argv
)
502 /* SEF local startup. */
503 env_setargs(argc
, argv
);
507 if ((rc
= netdriver_receive(ANY
, &m
, &ipc_status
)) != OK
){
508 panic(RecvErrMsg
, rc
);
511 DEBUG(printf("eth: got message %d, ", m
.m_type
));
513 if (is_ipc_notify(ipc_status
)) {
514 switch(_ENDPOINT_P(m
.m_source
)) {
520 /* Interrupt from device */
524 /* Function key pressed */
528 /* Invalid message type */
529 panic(TypeErrMsg
, m
.m_type
);
532 /* message processed, get another one */
537 case DL_WRITEV_S
: /* Write message to device */
540 case DL_READV_S
: /* Read message from device */
543 case DL_CONF
: /* Initialize device */
546 case DL_GETSTAT_S
: /* Get device statistics */
549 default: /* Invalid message type */
550 panic(TypeErrMsg
, m
.m_type
);
554 return OK
; /* Never reached, but keeps compiler happy */
557 /*===========================================================================*
558 * sef_local_startup *
559 *===========================================================================*/
560 static void sef_local_startup()
562 /* Register init callbacks. */
563 sef_setcb_init_fresh(sef_cb_init_fresh
);
564 sef_setcb_init_lu(sef_cb_init_fresh
);
565 sef_setcb_init_restart(sef_cb_init_fresh
);
567 /* Register live update callbacks. */
568 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready
);
569 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree
);
571 /* Register signal callbacks. */
572 sef_setcb_signal_handler(sef_cb_signal_handler
);
574 /* Let SEF perform startup. */
578 /*===========================================================================*
579 * sef_cb_init_fresh *
580 *===========================================================================*/
581 static int sef_cb_init_fresh(int type
, sef_init_info_t
*UNUSED(info
))
583 /* Initialize the dpeth driver. */
587 /* Request function key for debug dumps */
588 fkeys
= sfkeys
= 0; bit_set(sfkeys
, 8);
589 if ((fkey_map(&fkeys
, &sfkeys
)) != OK
)
590 printf("%s: couldn't program Shift+F8 key (%d)\n", DevName
, errno
);
593 (void) env_parse("instance", "d", 0, &v
, 0, 255);
594 de_instance
= (int) v
;
596 /* Announce we are up! */
597 netdriver_announce();
602 /*===========================================================================*
603 * sef_cb_signal_handler *
604 *===========================================================================*/
605 static void sef_cb_signal_handler(int signo
)
607 /* Only check for termination signal, ignore anything else. */
608 if (signo
!= SIGTERM
) return;
610 if (de_state
.de_mode
== DEM_ENABLED
)