dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / dec21140A / dec21140A.c
blob06d635669e3cb0118f4c5000d6aafe7640497c0a
1 /*
2 * dec21041.c
4 * This file contains an ethernet device driver for DEC 21140A
5 * fast ethernet controllers as emulated by VirtualPC 2007. It is not
6 * intended to support the real card, as much more error checking
7 * and testing would be needed. It supports both bridged and NAT mode.
9 * Created: Mar 2008 by Nicolas Tittley <first.last@ google's mail>
12 #include "../drivers.h"
14 #include <assert.h>
15 #include <ibm/pci.h>
16 #include <minix/syslib.h>
17 #include <minix/endpoint.h>
18 #include <minix/com.h>
19 #include <minix/sef.h>
20 #include <minix/ds.h>
21 #include <net/hton.h>
22 #include <net/gen/ether.h>
23 #include <net/gen/eth_io.h>
24 #include <stdlib.h>
26 #include "dec21140A.h"
29 _PROTOTYPE( PRIVATE u32_t io_inl, (u16_t); );
30 _PROTOTYPE( PRIVATE void io_outl, (u16_t, u32_t); );
31 _PROTOTYPE( PRIVATE void do_conf, (message *); );
32 _PROTOTYPE( PRIVATE void do_fkey, (message *); );
33 _PROTOTYPE( PRIVATE void do_get_name, (message *); );
34 _PROTOTYPE( PRIVATE void do_get_stat_s, (message *); );
35 _PROTOTYPE( PRIVATE void do_interrupt, (dpeth_t *); );
36 _PROTOTYPE( PRIVATE void do_reply, (dpeth_t *, int, int); );
37 _PROTOTYPE( PRIVATE void do_vread_s, (message *, int); );
38 _PROTOTYPE( PRIVATE void do_watchdog, (void *); );
40 _PROTOTYPE( PRIVATE void de_update_conf, (dpeth_t *); );
41 _PROTOTYPE( PRIVATE int de_probe, (dpeth_t *); );
42 _PROTOTYPE( PRIVATE void de_conf_addr, (dpeth_t *); );
43 _PROTOTYPE( PRIVATE void de_first_init, (dpeth_t *); );
44 _PROTOTYPE( PRIVATE void de_reset, (dpeth_t *); );
45 _PROTOTYPE( PRIVATE void de_hw_conf, (dpeth_t *); );
46 _PROTOTYPE( PRIVATE void de_start, (dpeth_t *); );
47 _PROTOTYPE( PRIVATE void de_setup_frame, (dpeth_t *); );
48 _PROTOTYPE( PRIVATE u16_t de_read_rom, (dpeth_t *, u8_t, u8_t); );
49 _PROTOTYPE( PRIVATE int de_calc_iov_size, (iovec_dat_s_t *); );
50 _PROTOTYPE( PRIVATE void de_next_iov, (iovec_dat_s_t *); );
51 _PROTOTYPE( PRIVATE void do_vwrite_s, (message *, int); );
52 _PROTOTYPE( PRIVATE void de_get_userdata_s, (int, cp_grant_id_t,
53 vir_bytes, int, void *); );
55 /* Error messages */
56 static char str_CopyErrMsg[] = "unable to read/write user data";
57 static char str_PortErrMsg[] = "illegal port";
58 static char str_RecvErrMsg[] = "receive failed";
59 static char str_SendErrMsg[] = "send failed";
60 static char str_SizeErrMsg[] = "illegal packet size";
61 static char str_TypeErrMsg[] = "illegal message type";
62 static char str_UmapErrMsg[] = "Unable to sys_umap";
63 static char str_BusyErrMsg[] = "Send/Recv failed: busy";
64 static char str_StatErrMsg[] = "Unable to send stats";
65 static char str_AlignErrMsg[] = "Bad align of buffer/descriptor";
66 static char str_DevName[] = "dec21140A:eth#?";
68 extern int errno;
69 static dpeth_t de_table[DE_PORT_NR];
70 static char *progname;
72 int sef_cb_init(int type, sef_init_info_t *info)
74 int r;
75 int fkeys, sfkeys;
76 endpoint_t tasknr;
77 /* Request function key for debug dumps */
78 fkeys = sfkeys = 0; bit_set(sfkeys, DE_FKEY);
79 if ((fkey_map(&fkeys, &sfkeys)) != OK)
80 printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno);
82 /* Try to notify inet that we are present (again) */
83 r = ds_retrieve_label_num("inet", &tasknr);
84 if (r == OK)
85 notify(tasknr);
86 else if(r != ESRCH)
87 printf("%s unable to notify inet: %d\n", str_DevName, r);
90 /*===========================================================================*
91 * main *
92 *===========================================================================*/
93 int main(int argc, char *argv[])
95 dpeth_t *dep;
96 message m;
97 int r;
99 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
101 env_setargs(argc, argv);
103 sef_setcb_init_fresh(sef_cb_init);
104 sef_setcb_init_restart(sef_cb_init);
105 sef_startup();
107 while (TRUE)
109 if ((r= sef_receive(ANY, &m)) != OK)
110 panic(str_DevName, "minix msg sef_receive failed", r);
112 if(is_notify(m.m_type)) {
113 switch(_ENDPOINT_P(m.m_source)) {
114 case RS_PROC_NR:
115 notify(m.m_source);
116 break;
117 case CLOCK:
118 do_watchdog(&m);
119 break;
121 case HARDWARE:
122 for (dep = de_table; dep < &de_table[DE_PORT_NR]; dep += 1) {
123 if (dep->de_mode == DEM_ENABLED) {
124 do_interrupt(dep);
125 if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
126 do_reply(dep, OK, TRUE);
127 sys_irqenable(&dep->de_hook);
130 break;
131 case PM_PROC_NR:
132 exit(0);
133 break;
134 default:
135 printf("ignoring notify from %d\n", m.m_source);
136 break;
138 continue;
141 switch (m.m_type)
143 case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break;
144 case DL_READV_S: do_vread_s(&m, FALSE); break;
145 case DL_CONF: do_conf(&m); break;
146 case DL_GETSTAT_S: do_get_stat_s(&m); break;
147 case DL_GETNAME: do_get_name(&m); break;
148 case DL_STOP: /* nothing */ break;
150 default:
151 printf("message 0x%lx; %d from %d\n",
152 m.m_type, m.m_type-DL_RQ_BASE, m.m_source);
153 panic(str_DevName, "illegal message", m.m_type);
158 PRIVATE void do_get_stat_s(message * mp)
160 int port, rc;
161 dpeth_t *dep;
163 port = mp->DL_PORT;
164 if (port < 0 || port >= DE_PORT_NR)
165 panic(str_DevName, str_PortErrMsg, port);
167 dep = &de_table[port];
168 dep->de_client = mp->DL_PROC;
170 if ((rc = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
171 (vir_bytes)&dep->de_stat,
172 (vir_bytes) sizeof(dep->de_stat), 0)) != OK)
173 panic(str_DevName, str_CopyErrMsg, rc);
175 mp->m_type = DL_STAT_REPLY;
176 mp->DL_PORT = port;
177 mp->DL_STAT = OK;
178 rc = send(mp->m_source, mp);
179 if( rc != OK )
180 panic(str_DevName, str_StatErrMsg, rc);
181 return;
184 PRIVATE void do_conf(message * mp)
186 int port;
187 dpeth_t *dep;
188 message reply_mess;
190 port = mp->DL_PORT;
191 if (port >= 0 && port < DE_PORT_NR) {
193 dep = &de_table[port];
194 strncpy(dep->de_name, str_DevName, strlen(str_DevName));
195 dep->de_name[strlen(dep->de_name)-1] = '0' + port;
197 if (dep->de_mode == DEM_DISABLED) {
198 de_update_conf(dep);
199 pci_init();
200 if (dep->de_mode == DEM_ENABLED && !de_probe(dep)) {
201 printf("%s: warning no ethernet card found at 0x%04X\n",
202 dep->de_name, dep->de_base_port);
203 dep->de_mode = DEM_DISABLED;
207 /* 'de_mode' may change if probe routines fail, test again */
208 switch (dep->de_mode) {
210 case DEM_DISABLED:
211 port = ENXIO; /* Device is OFF or hardware probe failed */
212 break;
214 case DEM_ENABLED:
215 if (dep->de_flags == DEF_EMPTY) {
216 de_first_init(dep);
217 dep->de_flags |= DEF_ENABLED;
218 de_reset(dep);
219 de_hw_conf(dep);
220 de_setup_frame(dep);
221 de_start(dep);
224 /* TODO CHECK PROMISC AND MULTI */
225 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
226 if (mp->DL_MODE & DL_PROMISC_REQ)
227 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
228 if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI;
229 if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD;
230 dep->de_client = mp->m_source;
231 break;
233 case DEM_SINK:
234 DEBUG(printf("%s running in sink mode\n", str_DevName));
235 memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
236 de_conf_addr(dep);
237 break;
239 default: break;
241 } else /* Port number is out of range */
242 port = ENXIO;
244 reply_mess.m_type = DL_CONF_REPLY;
245 reply_mess.m3_i1 = port;
246 reply_mess.m3_i2 = DE_PORT_NR;
247 *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
249 if (send(mp->m_source, &reply_mess) != OK)
250 panic(str_DevName, str_SendErrMsg, mp->m_source);
252 return;
256 PRIVATE void do_get_name(mp)
257 message *mp;
259 int r;
260 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
261 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
262 mp->m_type= DL_NAME_REPLY;
263 r = send(mp->m_source, mp);
264 if (r!= OK)
265 panic(str_DevName, "do_getname: send failed", r);
268 PRIVATE void do_reply(dpeth_t * dep, int err, int may_block)
270 message reply;
271 int status = FALSE;
273 if (dep->de_flags & DEF_ACK_SEND) status |= DL_PACK_SEND;
274 if (dep->de_flags & DEF_ACK_RECV) status |= DL_PACK_RECV;
276 reply.m_type = DL_TASK_REPLY;
277 reply.DL_PORT = dep - de_table;
278 reply.DL_PROC = dep->de_client;
279 reply.DL_STAT = status | ((u32_t) err << 16);
280 reply.DL_COUNT = dep->de_read_s;
281 reply.DL_CLCK = 0;
283 status = send(dep->de_client, &reply);
285 if(status == ELOCKED && may_block){
286 /*printf("Warning: Dec21041 send lock prevented\n\n");*/
287 return;
290 if(status < 0)
291 panic(dep->de_name, str_SendErrMsg, status);
293 dep->de_read_s = 0;
294 dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
295 return;
298 PRIVATE void do_watchdog(void *message)
300 /* nothing here yet */
301 return;
304 PRIVATE int de_probe(dpeth_t *dep){
305 int i, r, devind;
306 u16_t vid, did, temp16;
308 DEBUG(printf("PROBING..."));
310 r= pci_first_dev(&devind, &vid, &did);
311 if (r == 0)
312 return FALSE;
314 for(;;)
316 if ( DEC21140A_VID == vid &&
317 DEC21140A_DID == did)
318 break;
320 r= pci_next_dev(&devind, &vid, &did);
321 if (!r)
322 return FALSE;
325 pci_reserve(devind);
327 dep->de_base_port = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
328 dep->de_irq = pci_attr_r8(devind, PCI_ILR);
330 if (dep->de_base_port < DE_MIN_BASE_ADDR)
331 panic(str_DevName,"de_probe: base address invalid ", dep->de_base_port);
333 DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n",
334 dep->de_name, (unsigned long)dep->de_base_port,
335 dep->de_irq));
337 dep->de_type = pci_attr_r8(devind, PCI_REV);
339 /* device validation. We support only the DEC21140A */
340 if(dep->de_type != DEC_21140A){
341 dep->de_type = DE_TYPE_UNKNOWN;
342 printf("%s: unsupported device\n", str_DevName);
343 return FALSE;
346 de_reset(dep);
348 DEBUG(printf("Reading SROM...\n"));
350 for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
351 temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
352 dep->srom[i*2] = temp16 & 0xFF;
353 dep->srom[i*2+1] = temp16 >> 8;
356 /* TODO: validate SROM content */
357 /* acquire MAC addr */
358 DEBUG(printf("Using MAC addr= "));
359 for(i=0;i<6;i++){
360 dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
361 DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n'));
363 DEBUG(printf("probe success\n"));
364 return TRUE;
367 PRIVATE u16_t de_read_rom(dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
368 u16_t retVal = 0;
369 int i;
370 u32_t csr = 0;
371 u32_t csr2 = 0; /* csr2 is used to hold constant values that are
372 setup in the init phase, it makes this a little
373 more readable, the following macro is also just
374 to clear up the code a little.*/
376 #define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0)
378 /* init */
379 csr = 0; EMIT;
380 csr = CSR9_SR; EMIT;
381 csr = CSR9_SR | CSR9_RD; EMIT;
383 csr2 = CSR9_SR | CSR9_RD;
384 csr = 0; EMIT;
385 csr2 |= CSR9_CS;
387 csr = 0; EMIT;
388 csr = CSR9_SRC; EMIT;
389 csr = 0; EMIT;
391 /* cmd 110 - Read */
392 csr = CSR9_DI; EMIT;
393 csr = CSR9_DI | CSR9_SRC; EMIT;
394 csr = CSR9_DI; EMIT;
395 csr = CSR9_DI | CSR9_SRC; EMIT;
396 csr = CSR9_DI; EMIT;
397 csr = 0; EMIT;
398 csr = CSR9_SRC; EMIT;
399 csr = 0; EMIT;
401 /* addr to read */
402 for(i=nbAddrBits;i!=0;i--){
403 csr = (addr&(1<<(i-1))) != 0 ? CSR9_DI : 0; EMIT;
404 csr ^= CSR9_SRC; EMIT;
405 csr ^= CSR9_SRC; EMIT;
408 /* actual read */
409 retVal=0;
410 for(i=0;i<16;i++){
411 retVal <<= 1;
412 csr = CSR9_SRC; EMIT;
413 retVal |= (io_inl(CSR_ADDR(dep, CSR9)) & CSR9_DO) == 0 ? 0 : 1;
414 csr = 0; EMIT;
417 /* clean up */
418 csr = 0; EMIT;
420 #undef EMIT
421 return retVal;
424 static void de_update_conf(dpeth_t * dep)
426 static char dpc_fmt[] = "x:d:x";
427 long val;
429 dep->de_mode = DEM_ENABLED;
430 switch (env_parse("DEETH0", dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
431 case EP_OFF: dep->de_mode = DEM_DISABLED; break;
432 case EP_ON: dep->de_mode = DEM_SINK; break;
434 dep->de_base_port = 0;
436 return;
439 PRIVATE void do_vread_s(message * mp, int from_int)
441 char *buffer;
442 u32_t size;
443 int r, bytes, ix = 0;
444 dpeth_t *dep = NULL;
445 de_loc_descr_t *descr = NULL;
446 iovec_dat_s_t *iovp = NULL;
448 if (mp->DL_PORT < 0 || mp->DL_PORT >= DE_PORT_NR)
449 panic(dep->de_name, str_PortErrMsg, mp->DL_PORT);
451 dep = &de_table[mp->DL_PORT];
452 dep->de_client = mp->DL_PROC;
454 if (dep->de_mode == DEM_ENABLED) {
456 descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
458 /* check if packet is in the current descr and only there */
459 if( !( !(descr->descr->des[DES0] & DES0_OWN) &&
460 (descr->descr->des[DES0] & DES0_FS) &&
461 (descr->descr->des[DES0] & DES0_LS) ))
462 goto suspend;
465 /*TODO: multi-descr msgs...*/
466 /* We only support packets contained in a single descriptor.
467 Setting the descriptor buffer size to less then
468 ETH_MAX_PACK_SIZE will result in multi-descriptor
469 packets that we won't be able to handle
471 assert(!(descr->descr->des[DES0]&DES0_OWN));
472 assert(descr->descr->des[DES0]&DES0_FS);
473 assert(descr->descr->des[DES0]&DES0_LS);
475 /* Check for abnormal messages. We assert here
476 because this driver is for a virtualized
477 envrionment where we will not get bad packets
479 assert(!(descr->descr->des[DES0]&DES0_ES));
480 assert(!(descr->descr->des[DES0]&DES0_RE));
483 /* Setup the iovec entry to allow copying into
484 client layer
486 dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
487 de_get_userdata_s(mp->DL_PROC, (vir_bytes) mp->DL_GRANT, 0,
488 mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
489 dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
490 dep->de_read_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
491 dep->de_read_iovec.iod_iovec_offset = 0;
492 size = de_calc_iov_size(&dep->de_read_iovec);
493 if (size < ETH_MAX_PACK_SIZE)
494 panic(str_DevName, str_SizeErrMsg, size);
496 /* Copy buffer to user area and clear ownage */
497 size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
499 /*TODO: Complain to MS */
500 /*HACK: VPC2007 returns packet of invalid size. Ethernet standard
501 specify 46 bytes as the minimum for valid payload. However, this is
502 artificial in so far as for certain packet types, notably ARP, less
503 then 46 bytes are needed to contain the full information. In a non
504 virtualized environment the 46 bytes rule is enforced in order to give
505 guarantee in the collison detection scheme. Of course, this being a
506 driver for a VPC2007, we won't have collisions and I can only suppose
507 MS decided to cut packet size to true minimum, regardless of the
508 46 bytes payload standard. Note that this seems to not happen in
509 bridged mode. Note also, that the card does not return runt or
510 incomplete frames to us, so this hack is safe
512 if(size<60){
513 bzero(&descr->buf1[size], 60-size);
514 size=60;
516 /* End ugly hack */
518 iovp = &dep->de_read_iovec;
519 buffer = descr->buf1;
520 dep->bytes_rx += size;
521 dep->de_stat.ets_packetR++;
522 dep->de_read_s = size;
524 do {
525 bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
526 if (bytes >= size)
527 bytes = size;
529 r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
530 (vir_bytes)buffer, bytes, D);
531 if (r != OK)
532 panic(str_DevName, str_CopyErrMsg, r);
533 buffer += bytes;
535 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
536 de_next_iov(iovp);
537 ix = 0;
539 } while ((size -= bytes) > 0);
541 descr->descr->des[DES0]=DES0_OWN;
542 dep->cur_descr[DESCR_RECV]++;
543 if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
544 dep->cur_descr[DESCR_RECV] = 0;
546 DEBUG(printf("Read returned size = %d\n", size));
548 /* Reply information */
549 dep->de_flags |= DEF_ACK_RECV;
550 dep->de_flags &= NOT(DEF_READING);
553 if(!from_int){
554 do_reply(dep, OK, FALSE);
556 return;
558 suspend:
559 if(from_int){
560 assert(dep->de_flags & DEF_READING);
561 return;
564 assert(!(dep->de_flags & DEF_READING));
565 dep->rx_return_msg = *mp;
566 dep->de_flags |= DEF_READING;
567 do_reply(dep, OK, FALSE);
568 return;
571 PRIVATE void de_conf_addr(dpeth_t * dep)
573 static char ea_fmt[] = "x:x:x:x:x:x";
574 char ea_key[16];
575 int ix;
576 long val;
578 /* TODO: should be configurable... */
579 strcpy(ea_key, "DEETH0");
580 strcat(ea_key, "_EA");
582 for (ix = 0; ix < SA_ADDR_LEN; ix++) {
583 val = dep->de_address.ea_addr[ix];
584 if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
585 break;
586 dep->de_address.ea_addr[ix] = val;
589 if (ix != 0 && ix != SA_ADDR_LEN)
590 env_parse(ea_key, "?", 0, &val, 0L, 0L);
591 return;
594 PRIVATE void do_fkey(message *mp)
596 dpeth_t *dep;
597 int port,i;
599 printf("\n");
600 for (port = 0, dep = de_table; port < DE_PORT_NR; port += 1, dep += 1) {
601 if (dep->de_mode == DEM_DISABLED) continue;
602 printf("%s status:\n", dep->de_name);
603 printf("hwaddr: ");
604 for(i=0;i<6;i++)
605 printf("%02X%c",dep->de_address.ea_addr[i], i!=5?':':'\n');
606 printf("Tx packets: %-16d Tx kb: %d.%02d\n", dep->de_stat.ets_packetT,
607 dep->bytes_tx/1024,
608 (int)(((dep->bytes_tx%1024)/1024.0)*100));
609 printf("Rx packets: %-16d Rx kb: %d.%02d\n", dep->de_stat.ets_packetR,
610 dep->bytes_rx/1024,
611 (int)(((dep->bytes_rx%1024)/1024.0)*100));
612 printf("Rx errors: %-16d Tx errors: %d\n",
613 dep->de_stat.ets_recvErr,
614 dep->de_stat.ets_sendErr);
616 return;
619 PRIVATE void de_first_init(dpeth_t *dep){
620 int i,j,r;
621 vir_bytes descr_vir = dep->sendrecv_descr_buf;
622 vir_bytes buffer_vir = dep->sendrecv_buf;
623 de_descr_t *phys_descr;
624 de_loc_descr_t *loc_descr;
625 u32_t temp;
628 for(i=0;i<2;i++){
629 loc_descr = &dep->descr[i][0];
630 for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
632 /* assign buffer space for descriptor */
633 loc_descr->descr = descr_vir;
634 descr_vir += sizeof(de_descr_t);
636 /* assign space for buffer */
637 loc_descr->buf1 = buffer_vir;
638 buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
639 loc_descr->buf2 = 0;
640 loc_descr++;
644 /* Now that we have buffer space and descriptors, we need to
645 obtain their physical address to pass to the hardware
647 for(i=0;i<2;i++){
648 loc_descr = &dep->descr[i][0];
649 temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
650 for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
651 /* translate buffers physical address */
652 r = sys_umap(SELF, VM_D, loc_descr->buf1, temp,
653 &(loc_descr->descr->des[DES_BUF1]));
654 if(r != OK) panic(dep->de_name, "umap failed", r);
655 loc_descr->descr->des[DES_BUF2] = 0;
656 memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t));
657 loc_descr->descr->des[DES1] = temp;
658 if(j==( (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR)-1))
659 loc_descr->descr->des[DES1] |= DES1_ER;
660 if(i==DESCR_RECV)
661 loc_descr->descr->des[DES0] |= DES0_OWN;
662 loc_descr++;
666 /* record physical location of two first descriptor */
667 r = sys_umap(SELF, VM_D, dep->descr[DESCR_RECV][0].descr,
668 sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]);
669 if(r != OK) panic(str_DevName, str_UmapErrMsg, r);
671 r = sys_umap(SELF, VM_D, dep->descr[DESCR_TRAN][0].descr,
672 sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]);
673 if(r != OK) panic(str_DevName, str_UmapErrMsg, r);
675 DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
676 dep->sendrecv_descr_phys_addr[DESCR_TRAN],
677 dep->sendrecv_descr_phys_addr[DESCR_RECV]));
679 /* check alignment just to be extra safe */
680 for(i=0;i<2;i++){
681 loc_descr = &dep->descr[i][0];
682 for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){
683 r = sys_umap(SELF, VM_D, &(loc_descr->descr), sizeof(de_descr_t),
684 &temp);
685 if(r != OK)
686 panic(str_DevName, str_UmapErrMsg, r);
688 if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
689 ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
690 ((temp&0x3)!=0) )
691 panic(str_DevName, str_AlignErrMsg, temp);
693 loc_descr++;
697 /* Init default values */
698 dep->cur_descr[DESCR_TRAN]=1;
699 dep->cur_descr[DESCR_RECV]=0;
700 dep->bytes_rx = 0;
701 dep->bytes_tx = 0;
703 /* Set the interrupt handler policy. Request interrupts not to be reenabled
704 * automatically. Return the IRQ line number when an interrupt occurs.
706 dep->de_hook = dep->de_irq;
707 sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
708 sys_irqenable(&dep->de_hook);
711 PRIVATE void do_interrupt(dpeth_t *dep){
712 u32_t val;
713 val = io_inl(CSR_ADDR(dep, CSR5));
715 if(val & CSR5_AIS){
716 panic(dep->de_name, "Abnormal Int CSR5=", val);
719 if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){
720 do_vread_s(&dep->rx_return_msg, TRUE);
723 if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){
724 do_vwrite_s(&dep->tx_return_msg, TRUE);
727 /* ack and reset interrupts */
728 io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF);
729 return;
732 PRIVATE void de_reset(dpeth_t *dep){
733 io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR);
734 micro_delay(1000000);
737 PRIVATE void de_hw_conf(dpeth_t *dep){
738 u32_t val;
740 /* CSR0 - global host bus prop */
741 val = CSR0_BAR | CSR0_CAL_8;
742 io_outl(CSR_ADDR(dep, CSR0), val);
744 /* CSR3 - Receive list BAR */
745 val = dep->sendrecv_descr_phys_addr[DESCR_RECV];
746 io_outl(CSR_ADDR(dep, CSR3), val);
748 /* CSR4 - Transmit list BAR */
749 val = dep->sendrecv_descr_phys_addr[DESCR_TRAN];
750 io_outl(CSR_ADDR(dep, CSR4), val);
752 /* CSR7 - interrupt mask */
753 val = CSR7_TI | CSR7_RI | CSR7_AI;
754 io_outl(CSR_ADDR(dep, CSR7), val);
756 /* CSR6 - operating mode register */
757 val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD |
758 CSR6_PCS | CSR6_SCR | CSR6_TR_00;
759 io_outl(CSR_ADDR(dep, CSR6), val);
762 PRIVATE void de_start(dpeth_t *dep){
763 u32_t val;
764 val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
765 io_outl(CSR_ADDR(dep, CSR6), val);
768 PRIVATE void de_setup_frame(dpeth_t *dep){
769 int i;
770 u32_t val;
772 /* this is not perfect... we assume pass all multicast and only
773 filter non-multicast frames */
774 dep->descr[DESCR_TRAN][0].buf1[0] = 0xFF;
775 dep->descr[DESCR_TRAN][0].buf1[1] = 0xFF;
776 dep->descr[DESCR_TRAN][0].buf1[4] = 0xFF;
777 dep->descr[DESCR_TRAN][0].buf1[5] = 0xFF;
778 dep->descr[DESCR_TRAN][0].buf1[8] = 0xFF;
779 dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
780 for(i=1;i<16;i++){
781 memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12);
782 dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0];
783 dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1];
784 dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2];
785 dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3];
786 dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4];
787 dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5];
790 dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN;
791 dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET |
792 DE_SETUP_FRAME_SIZE | DES1_IC;
794 /* start transmit process to process setup frame */
795 val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
796 io_outl(CSR_ADDR(dep, CSR6), val);
797 io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
799 return;
802 PRIVATE int de_calc_iov_size(iovec_dat_s_t * iovp){
803 int size, ix;
804 size = ix = 0;
807 size += iovp->iod_iovec[ix].iov_size;
808 if (++ix >= IOVEC_NR) {
809 de_next_iov(iovp);
810 ix = 0;
812 } while (ix < iovp->iod_iovec_s);
813 return size;
816 PRIVATE void de_get_userdata_s(int user_proc, cp_grant_id_t grant,
817 vir_bytes offset, int count, void *loc_addr){
818 int rc;
819 vir_bytes len;
821 len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
822 rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len, D);
823 if (rc != OK)
824 panic(str_DevName, str_CopyErrMsg, rc);
825 return;
828 PRIVATE void de_next_iov(iovec_dat_s_t * iovp){
830 iovp->iod_iovec_s -= IOVEC_NR;
831 iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
832 de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
833 iovp->iod_iovec_s, iovp->iod_iovec);
834 return;
837 PRIVATE void do_vwrite_s(message * mp, int from_int){
838 static u8_t setupDone = 0;
839 int size, r, bytes, ix, totalsize;
840 dpeth_t *dep = NULL;
841 iovec_dat_s_t *iovp = NULL;
842 de_loc_descr_t *descr = NULL;
843 char *buffer = NULL;
845 if( mp->DL_PORT < 0 || mp->DL_PORT >= DE_PORT_NR)
846 panic(str_DevName, str_PortErrMsg, mp->DL_PORT);
848 dep = &de_table[mp->DL_PORT];
849 dep->de_client = mp->DL_PROC;
851 if (dep->de_mode == DEM_ENABLED) {
853 if (!from_int && (dep->de_flags & DEF_SENDING))
854 panic(str_DevName, str_BusyErrMsg, NO_NUM);
856 descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
858 if(( descr->descr->des[DES0] & DES0_OWN)!=0)
859 goto suspend;
861 if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){
862 dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
863 setupDone=1;
866 buffer = descr->buf1;
867 iovp = &dep->de_write_iovec;
868 iovp->iod_proc_nr = mp->DL_PROC;
869 de_get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
870 mp->DL_COUNT, iovp->iod_iovec);
871 iovp->iod_iovec_s = mp->DL_COUNT;
872 iovp->iod_grant = (vir_bytes) mp->DL_GRANT;
873 iovp->iod_iovec_offset = 0;
874 totalsize = size = de_calc_iov_size(iovp);
875 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
876 panic(str_DevName, str_SizeErrMsg, size);
878 dep->bytes_tx += size;
879 dep->de_stat.ets_packetT++;
881 ix=0;
882 do {
883 bytes = iovp->iod_iovec[ix].iov_size;
884 if (bytes >= size)
885 bytes = size;
887 r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
888 0, (vir_bytes)buffer, bytes, D);
889 if (r != OK)
890 panic(str_DevName, str_CopyErrMsg, r);
891 buffer += bytes;
893 if (++ix >= IOVEC_NR) {
894 de_next_iov(iovp);
895 ix = 0;
897 } while ((size -= bytes) > 0);
899 descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
900 DES1_FS | DES1_LS | DES1_IC | totalsize;
901 descr->descr->des[DES0] = DES0_OWN;
903 dep->cur_descr[DESCR_TRAN]++;
904 if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
905 dep->cur_descr[DESCR_TRAN] = 0;
907 io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
910 dep->de_flags |= DEF_ACK_SEND;
911 if(from_int){
912 dep->de_flags &= NOT(DEF_SENDING);
913 return;
915 do_reply(dep, OK, FALSE);
916 return;
918 suspend:
919 if(from_int)
920 panic(str_DevName, "should not happen", 0);
922 dep->de_stat.ets_transDef++;
923 dep->de_flags |= DEF_SENDING;
924 dep->de_stat.ets_transDef++;
925 dep->tx_return_msg = *mp;
926 do_reply(dep, OK, FALSE);
929 PRIVATE void warning(const char *type, int err){
930 printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err);
931 return;
934 PRIVATE u32_t io_inl(u16_t port){
935 u32_t value;
936 int rc;
937 if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc);
938 return value;
941 PRIVATE void io_outl(u16_t port, u32_t value){
942 int rc;
943 if ((rc = sys_outl(port, value)) != OK) warning("outl", rc);
944 return;