1 /* 2 ** File: dp.c Version 1.01, Oct. 17, 2007 3 ** Original: eth.c Version 1.00, Jan. 14, 1997 4 ** 5 ** Author: Giovanni Falzoni <gfalzoni@inwind.it> 6 ** 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. 12 */ 13 14 #include <minix/drivers.h> 15 #include <minix/netdriver.h> 16 #include <minix/endpoint.h> 17 #include <minix/ds.h> 18 #include <net/gen/ether.h> 19 #include <net/gen/eth_io.h> 20 21 #include "dp.h" 22 23 /* 24 ** Local data 25 */ 26 static dpeth_t de_state; 27 static int de_instance; 28 29 typedef struct dp_conf { /* Configuration description structure */ 30 port_t dpc_port; 31 int dpc_irq; 32 phys_bytes dpc_mem; 33 } dp_conf_t; 34 35 /* Device default configuration */ 36 #define DP_CONF_NR 3 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, }, 42 }; 43 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#?"; 50 51 /* 52 ** Name: void reply(dpeth_t *dep, int err, int m_type) 53 ** Function: Fills a reply message and sends it. 54 */ 55 static void reply(dpeth_t * dep) 56 { 57 message reply; 58 int r, flags; 59 60 flags = DL_NOFLAGS; 61 if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND; 62 if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV; 63 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; 67 68 DEBUG(printf("\t reply %d (%lx)\n", reply.m_type, 69 reply.m_netdrv_net_dl_task.flags)); 70 71 if ((r = ipc_send(dep->de_client, &reply)) != OK) 72 panic(SendErrMsg, r); 73 74 dep->de_read_s = 0; 75 dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV); 76 77 return; 78 } 79 80 /* 81 ** Name: void dp_confaddr(dpeth_t *dep) 82 ** Function: Checks environment for a User defined ethernet address. 83 */ 84 static void dp_confaddr(dpeth_t * dep) 85 { 86 static char ea_fmt[] = "x:x:x:x:x:x"; 87 char ea_key[16]; 88 int ix; 89 long val; 90 91 strlcpy(ea_key, "DPETH0_EA", sizeof(ea_key)); 92 ea_key[5] += de_instance; 93 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) 97 break; 98 dep->de_address.ea_addr[ix] = val; 99 } 100 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); 104 return; 105 } 106 107 /* 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. 111 */ 112 static void update_conf(dpeth_t * dep, const dp_conf_t * dcp) 113 { 114 static char dpc_fmt[] = "x:d:x"; 115 char ec_key[16]; 116 long val; 117 118 strlcpy(ec_key, "DPETH0", sizeof(ec_key)); 119 ec_key[5] += de_instance; 120 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; 125 case EP_ON: 126 case EP_SET: dep->de_mode = DEM_ENABLED; break; 127 } 128 dep->de_base_port = val; 129 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); 132 dep->de_irq = val; 133 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; 137 138 return; 139 } 140 141 /* 142 ** Name: void do_dump(message *mp) 143 ** Function: Displays statistics on screen (SFx key from console) 144 */ 145 static void do_dump(const message *mp) 146 { 147 dpeth_t *dep; 148 149 dep = &de_state; 150 151 printf("\n\n"); 152 153 if (dep->de_mode == DEM_DISABLED) return; 154 155 printf("%s statistics:\t\t", dep->de_name); 156 157 /* Network interface status */ 158 printf("Status: 0x%04x (%d)\n\n", dep->de_flags, dep->de_int_pending); 159 160 (*dep->de_dumpstatsf) (dep); 161 162 /* Transmitted/received bytes */ 163 printf("Tx bytes:%10ld\t", dep->bytes_Tx); 164 printf("Rx bytes:%10ld\n", dep->bytes_Rx); 165 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); 169 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); 173 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); 177 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); 181 182 return; 183 } 184 185 /* 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. 188 */ 189 static void get_userdata_s(int user_proc, cp_grant_id_t grant, 190 vir_bytes offset, int count, void *loc_addr) 191 { 192 int rc; 193 vir_bytes len; 194 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); 198 return; 199 } 200 201 /* 202 ** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp); 203 ** Function: Init action to setup task 204 */ 205 static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp) 206 { 207 208 dep->de_linmem = 0xFFFF0000; 209 210 /* Make sure statisics are cleared */ 211 memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t)); 212 213 /* Device specific initialization */ 214 (*dep->de_initf) (dep); 215 216 /* Set the interrupt handler policy. Request interrupts not to be reenabled 217 * automatically. Return the IRQ line number when an interrupt occurs. 218 */ 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); 224 225 return; 226 } 227 228 /* 229 ** Name: void do_init(message *mp) 230 ** Function: Checks for hardware presence. 231 ** Provides initialization of hardware and data structures 232 */ 233 static void do_init(const message * mp) 234 { 235 dpeth_t *dep; 236 dp_conf_t *dcp; 237 message reply_mess; 238 int r, confnr; 239 240 dep = &de_state; 241 242 /* Pick a default configuration for this instance. */ 243 confnr = MIN(de_instance, DP_CONF_NR-1); 244 245 dcp = &dp_conf[confnr]; 246 strlcpy(dep->de_name, DevName, sizeof(dep->de_name)); 247 dep->de_name[4] = '0' + de_instance; 248 249 if (dep->de_mode == DEM_DISABLED) { 250 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; 261 } 262 } 263 264 r = OK; 265 266 /* 'de_mode' may change if probe routines fail, test again */ 267 switch (dep->de_mode) { 268 269 case DEM_DISABLED: 270 /* Device is configured OFF or hardware probe failed */ 271 r = ENXIO; 272 break; 273 274 case DEM_ENABLED: 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; 280 } 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); 289 break; 290 291 case DEM_SINK: 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. */ 295 break; 296 297 default: break; 298 } 299 300 reply_mess.m_type = DL_CONF_REPLY; 301 reply_mess.m_netdrv_net_dl_conf.stat = r; 302 if (r == OK) 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); 308 309 return; 310 } 311 312 /* 313 ** Name: void dp_next_iovec(iovec_dat_t *iovp) 314 ** Function: Retrieves data from next iovec element. 315 */ 316 void dp_next_iovec(iovec_dat_s_t * iovp) 317 { 318 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); 323 return; 324 } 325 326 /* 327 ** Name: int calc_iovec_size(iovec_dat_t *iovp) 328 ** Function: Compute the size of a request. 329 */ 330 static int calc_iovec_size(iovec_dat_s_t * iovp) 331 { 332 int size, ix; 333 334 size = ix = 0; 335 do { 336 size += iovp->iod_iovec[ix].iov_size; 337 if (++ix >= IOVEC_NR) { 338 dp_next_iovec(iovp); 339 ix = 0; 340 } 341 342 /* Till all vectors added */ 343 } while (ix < iovp->iod_iovec_s); 344 return size; 345 } 346 347 /* 348 ** Name: void do_vwrite_s(message *mp) 349 ** Function: 350 */ 351 static void do_vwrite_s(const message * mp) 352 { 353 int size; 354 dpeth_t *dep; 355 356 dep = &de_state; 357 358 dep->de_client = mp->m_source; 359 360 if (dep->de_mode == DEM_ENABLED) { 361 362 if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */ 363 panic("send already in progress "); 364 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); 374 375 dep->de_flags |= DEF_SENDING; 376 (*dep->de_sendf) (dep, FALSE, size); 377 378 } else if (dep->de_mode == DEM_SINK) 379 dep->de_flags |= DEF_ACK_SEND; 380 381 reply(dep); 382 return; 383 } 384 385 /* 386 ** Name: void do_vread_s(message *mp, int vectored) 387 ** Function: 388 */ 389 static void do_vread_s(const message * mp) 390 { 391 int size; 392 dpeth_t *dep; 393 394 dep = &de_state; 395 396 dep->de_client = mp->m_source; 397 398 if (dep->de_mode == DEM_ENABLED) { 399 400 if (dep->de_flags & DEF_READING) /* Reading in progress */ 401 panic("read already in progress"); 402 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); 411 412 dep->de_flags |= DEF_READING; 413 (*dep->de_recvf) (dep, FALSE, size); 414 #if 0 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); 419 #endif 420 } 421 reply(dep); 422 return; 423 } 424 425 /* 426 ** Name: void do_getstat_s(message *mp) 427 ** Function: Reports device statistics. 428 */ 429 static void do_getstat_s(const message * mp) 430 { 431 int rc; 432 dpeth_t *dep; 433 message reply_mess; 434 435 dep = &de_state; 436 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); 442 443 reply_mess.m_type = DL_STAT_REPLY; 444 rc= ipc_send(mp->m_source, &reply_mess); 445 if (rc != OK) 446 panic("do_getname: ipc_send failed: %d", rc); 447 return; 448 } 449 450 /* 451 ** Name: void dp_stop(dpeth_t *dep) 452 ** Function: Stops network interface. 453 */ 454 static void dp_stop(dpeth_t * dep) 455 { 456 457 if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) { 458 459 /* Stop device */ 460 (dep->de_stopf) (dep); 461 dep->de_flags = DEF_EMPTY; 462 dep->de_mode = DEM_DISABLED; 463 } 464 return; 465 } 466 467 static void do_watchdog(const void *UNUSED(message)) 468 { 469 470 DEBUG(printf("\t no reply")); 471 return; 472 } 473 474 static void handle_hw_intr(void) 475 { 476 dpeth_t *dep; 477 478 dep = &de_state; 479 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)) 485 reply(dep); 486 dep->de_int_pending = FALSE; 487 sys_irqenable(&dep->de_hook); 488 } 489 } 490 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); 495 496 /* 497 ** Name: int dpeth_task(void) 498 ** Function: Main entry for dp task 499 */ 500 int main(int argc, char **argv) 501 { 502 message m; 503 int ipc_status; 504 int rc; 505 506 /* SEF local startup. */ 507 env_setargs(argc, argv); 508 sef_local_startup(); 509 510 while (TRUE) { 511 if ((rc = netdriver_receive(ANY, &m, &ipc_status)) != OK){ 512 panic(RecvErrMsg, rc); 513 } 514 515 DEBUG(printf("eth: got message %d, ", m.m_type)); 516 517 if (is_ipc_notify(ipc_status)) { 518 switch(_ENDPOINT_P(m.m_source)) { 519 case CLOCK: 520 /* to be defined */ 521 do_watchdog(&m); 522 break; 523 case HARDWARE: 524 /* Interrupt from device */ 525 handle_hw_intr(); 526 break; 527 case TTY_PROC_NR: 528 /* Function key pressed */ 529 do_dump(&m); 530 break; 531 default: 532 /* Invalid message type */ 533 panic(TypeErrMsg, m.m_type); 534 break; 535 } 536 /* message processed, get another one */ 537 continue; 538 } 539 540 switch (m.m_type) { 541 case DL_WRITEV_S: /* Write message to device */ 542 do_vwrite_s(&m); 543 break; 544 case DL_READV_S: /* Read message from device */ 545 do_vread_s(&m); 546 break; 547 case DL_CONF: /* Initialize device */ 548 do_init(&m); 549 break; 550 case DL_GETSTAT_S: /* Get device statistics */ 551 do_getstat_s(&m); 552 break; 553 default: /* Invalid message type */ 554 panic(TypeErrMsg, m.m_type); 555 break; 556 } 557 } 558 return OK; /* Never reached, but keeps compiler happy */ 559 } 560 561 /*===========================================================================* 562 * sef_local_startup * 563 *===========================================================================*/ 564 static void sef_local_startup() 565 { 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); 570 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); 574 575 /* Register signal callbacks. */ 576 sef_setcb_signal_handler(sef_cb_signal_handler); 577 578 /* Let SEF perform startup. */ 579 sef_startup(); 580 } 581 582 /*===========================================================================* 583 * sef_cb_init_fresh * 584 *===========================================================================*/ 585 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) 586 { 587 /* Initialize the dpeth driver. */ 588 int fkeys, sfkeys; 589 long v; 590 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); 595 596 v = 0; 597 (void) env_parse("instance", "d", 0, &v, 0, 255); 598 de_instance = (int) v; 599 600 /* Announce we are up! */ 601 netdriver_announce(); 602 603 return(OK); 604 } 605 606 /*===========================================================================* 607 * sef_cb_signal_handler * 608 *===========================================================================*/ 609 static void sef_cb_signal_handler(int signo) 610 { 611 /* Only check for termination signal, ignore anything else. */ 612 if (signo != SIGTERM) return; 613 614 if (de_state.de_mode == DEM_ENABLED) 615 dp_stop(&de_state); 616 617 exit(0); 618 } 619 620 /** dp.c **/ 621