xref: /minix/minix/drivers/net/dec21140A/dec21140A.c (revision 83133719)
1 /*
2  * dec21041.c
3  *
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.
8  *
9  * Created:	Mar 2008 by Nicolas Tittley <first.last@ google's mail>
10  */
11 
12 #include <minix/drivers.h>
13 #include <minix/netdriver.h>
14 
15 #include <assert.h>
16 #include <machine/pci.h>
17 #include <minix/syslib.h>
18 #include <minix/endpoint.h>
19 #include <minix/com.h>
20 #include <minix/sef.h>
21 #include <minix/ds.h>
22 #include <net/gen/ether.h>
23 #include <net/gen/eth_io.h>
24 #include <stdlib.h>
25 
26 #include "dec21140A.h"
27 
28 
29 static u32_t io_inl(u16_t);
30 static void io_outl(u16_t, u32_t);
31 static void do_conf(const message *);
32 static void do_get_stat_s(message *);
33 static void do_interrupt(const dpeth_t *);
34 static void do_reply(dpeth_t *);
35 static void do_vread_s(const message *, int);
36 static void do_watchdog(void *);
37 
38 static void de_update_conf(dpeth_t *);
39 static int de_probe(dpeth_t *, int skip);
40 static void de_conf_addr(dpeth_t *);
41 static void de_first_init(dpeth_t *);
42 static void de_reset(const dpeth_t *);
43 static void de_hw_conf(const dpeth_t *);
44 static void de_start(const dpeth_t *);
45 static void de_setup_frame(const dpeth_t *);
46 static u16_t de_read_rom(const dpeth_t *, u8_t, u8_t);
47 static int de_calc_iov_size(iovec_dat_s_t *);
48 static void de_next_iov(iovec_dat_s_t *);
49 static void do_vwrite_s(const message *, int);
50 static void de_get_userdata_s(int, cp_grant_id_t, vir_bytes, int, void
51 	*);
52 
53 /* Error messages */
54 static char str_CopyErrMsg[]  = "unable to read/write user data";
55 static char str_SendErrMsg[]  = "send failed";
56 static char str_SizeErrMsg[]  = "illegal packet size";
57 static char str_UmapErrMsg[]  = "Unable to sys_umap";
58 static char str_BusyErrMsg[]  = "Send/Recv failed: busy";
59 static char str_StatErrMsg[]  = "Unable to send stats";
60 static char str_AlignErrMsg[] = "Bad align of buffer/descriptor";
61 static char str_DevName[]     = "dec21140A:eth#?";
62 
63 static dpeth_t de_state;
64 static int de_instance;
65 
66 /* SEF functions and variables. */
67 static void sef_local_startup(void);
68 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
69 
70 /*===========================================================================*
71  *				main					     *
72  *===========================================================================*/
73 int main(int argc, char *argv[])
74 {
75   dpeth_t *dep;
76   message m;
77   int ipc_status;
78   int r;
79 
80   /* SEF local startup. */
81   env_setargs(argc, argv);
82   sef_local_startup();
83 
84   while (TRUE)
85     {
86       if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
87 	panic("netdriver_receive failed: %d", r);
88 
89 		if(is_ipc_notify(ipc_status)) {
90 			switch(_ENDPOINT_P(m.m_source)) {
91 				case CLOCK:
92 					do_watchdog(&m);
93 					break;
94 
95 	case HARDWARE:
96 	  dep = &de_state;
97 	  if (dep->de_mode == DEM_ENABLED) {
98 	    do_interrupt(dep);
99 	    if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
100 	    do_reply(dep);
101 	    sys_irqenable(&dep->de_hook);
102 	  }
103 	  break;
104 	 default:
105 	 	printf("ignoring notify from %d\n", m.m_source);
106 	 	break;
107 			}
108 			continue;
109 		}
110 
111       switch (m.m_type)
112 	{
113 	case DL_WRITEV_S:  do_vwrite_s(&m, FALSE); break;
114 	case DL_READV_S:   do_vread_s(&m, FALSE);  break;
115 	case DL_CONF:      do_conf(&m);            break;
116 	case DL_GETSTAT_S: do_get_stat_s(&m);      break;
117 
118 	default:
119 		printf("message 0x%x; %d from %d\n",
120 			m.m_type, m.m_type-DL_RQ_BASE, m.m_source);
121 		panic("illegal message: %d", m.m_type);
122 	}
123     }
124 }
125 
126 /*===========================================================================*
127  *			       sef_local_startup			     *
128  *===========================================================================*/
129 static void sef_local_startup()
130 {
131   /* Register init callbacks. */
132   sef_setcb_init_fresh(sef_cb_init_fresh);
133   sef_setcb_init_lu(sef_cb_init_fresh);
134   sef_setcb_init_restart(sef_cb_init_fresh);
135 
136   /* Register live update callbacks. */
137   sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
138   sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
139 
140   /* Register signal callbacks. */
141   sef_setcb_signal_handler(sef_cb_signal_handler_term);
142 
143   /* Let SEF perform startup. */
144   sef_startup();
145 }
146 
147 /*===========================================================================*
148  *		            sef_cb_init_fresh                                *
149  *===========================================================================*/
150 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
151 {
152 /* Initialize the DEC 21140A driver. */
153   int fkeys, sfkeys;
154   long v;
155 
156   v = 0;
157   (void) env_parse("instance", "d", 0, &v, 0, 255);
158   de_instance = (int) v;
159 
160   /* Request function key for debug dumps */
161   fkeys = sfkeys = 0;
162   bit_set(sfkeys, DE_FKEY);
163   if ((fkey_map(&fkeys, &sfkeys)) != OK)
164     printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno);
165 
166   /* Announce we are up! */
167   netdriver_announce();
168 
169   return OK;
170 }
171 
172 static void do_get_stat_s(message * mp)
173 {
174   int rc;
175   dpeth_t *dep;
176 
177   dep = &de_state;
178 
179   if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant,
180 		  0, (vir_bytes)&dep->de_stat, sizeof(dep->de_stat))) != OK)
181         panic("%s %d", str_CopyErrMsg, rc);
182 
183   mp->m_type = DL_STAT_REPLY;
184   rc = ipc_send(mp->m_source, mp);
185   if( rc != OK )
186     panic("%s %d", str_StatErrMsg, rc);
187   return;
188 }
189 
190 static void do_conf(const message * mp)
191 {
192   int r;
193   dpeth_t *dep;
194   message reply_mess;
195 
196   dep = &de_state;
197 
198   strncpy(dep->de_name, str_DevName, strlen(str_DevName));
199   dep->de_name[strlen(dep->de_name)-1] = '0' + de_instance;
200 
201   if (dep->de_mode == DEM_DISABLED) {
202     de_update_conf(dep);
203     pci_init();
204     if (dep->de_mode == DEM_ENABLED && !de_probe(dep, de_instance)) {
205 	printf("%s: warning no ethernet card found at 0x%04X\n",
206 	       dep->de_name, dep->de_base_port);
207 	dep->de_mode = DEM_DISABLED;
208     }
209   }
210 
211   r = OK;
212 
213   /* 'de_mode' may change if probe routines fail, test again */
214   switch (dep->de_mode) {
215 
216   case DEM_DISABLED:
217     r = ENXIO;       /* Device is OFF or hardware probe failed */
218     break;
219 
220   case DEM_ENABLED:
221     if (dep->de_flags == DEF_EMPTY) {
222 	de_first_init(dep);
223 	dep->de_flags |= DEF_ENABLED;
224 	de_reset(dep);
225 	de_hw_conf(dep);
226 	de_setup_frame(dep);
227 	de_start(dep);
228     }
229 
230     /* TODO CHECK PROMISC AND MULTI */
231     dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
232     if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ)
233 	dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
234     if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ)
235 	dep->de_flags |= DEF_MULTI;
236     if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ)
237 	dep->de_flags |= DEF_BROAD;
238     break;
239 
240   case DEM_SINK:
241     DEBUG(printf("%s running in sink mode\n", str_DevName));
242     memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
243     de_conf_addr(dep);
244     break;
245 
246   default:	break;
247   }
248 
249   reply_mess.m_type = DL_CONF_REPLY;
250   reply_mess.m_netdrv_net_dl_conf.stat = r;
251   if(r == OK){
252       memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr,
253 	       sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr));
254   }
255 
256   if (ipc_send(mp->m_source, &reply_mess) != OK)
257     panic("%s %d", str_SendErrMsg, mp->m_source);
258 
259   return;
260 }
261 
262 static void do_reply(dpeth_t * dep)
263 {
264   message reply;
265   int r, flags = DL_NOFLAGS;
266 
267   if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND;
268   if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV;
269 
270   reply.m_type = DL_TASK_REPLY;
271   reply.m_netdrv_net_dl_task.flags = flags;
272   reply.m_netdrv_net_dl_task.count = dep->de_read_s;
273 
274   r = ipc_send(dep->de_client, &reply);
275 
276   if(r < 0)
277     panic("%s %d", str_SendErrMsg, r);
278 
279   dep->de_read_s = 0;
280   dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
281   return;
282 }
283 
284 static void do_watchdog(void *UNUSED(message))
285 {
286   /* nothing here yet */
287   return;
288 }
289 
290 static int de_probe(dpeth_t *dep, int skip)
291 {
292   int i, r, devind;
293   u16_t vid, did, temp16;
294 
295   DEBUG(printf("PROBING..."));
296 
297   r= pci_first_dev(&devind, &vid, &did);
298   if (r == 0)
299     return FALSE;
300 
301   while (skip--)
302     {
303       r= pci_next_dev(&devind, &vid, &did);
304       if (!r)
305 	return FALSE;
306     }
307 
308   pci_reserve(devind);
309 
310   dep->de_base_port = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
311   dep->de_irq = pci_attr_r8(devind, PCI_ILR);
312 
313   if (dep->de_base_port < DE_MIN_BASE_ADDR)
314     panic("de_probe: base address invalid: %d", dep->de_base_port);
315 
316   DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n",
317 	       dep->de_name, (unsigned long)dep->de_base_port,
318 	       dep->de_irq));
319 
320   dep->de_type = pci_attr_r8(devind, PCI_REV);
321 
322   /* device validation. We support only the DEC21140A */
323   if(dep->de_type != DEC_21140A){
324     dep->de_type = DE_TYPE_UNKNOWN;
325     printf("%s: unsupported device\n", str_DevName);
326     return FALSE;
327   }
328 
329   de_reset(dep);
330 
331   DEBUG(printf("Reading SROM...\n"));
332 
333   for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
334     temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
335     dep->srom[i*2] = temp16 & 0xFF;
336     dep->srom[i*2+1] = temp16 >> 8;
337   }
338 
339   /* TODO: validate SROM content */
340   /* acquire MAC addr */
341   DEBUG(printf("Using MAC addr= "));
342   for(i=0;i<6;i++){
343     dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
344     DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n'));
345   }
346   DEBUG(printf("probe success\n"));
347   return TRUE;
348 }
349 
350 static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
351   u16_t retVal = 0;
352   int i;
353   u32_t csr = 0;
354   u32_t csr2 = 0; /* csr2 is used to hold constant values that are
355 		     setup in the init phase, it makes this a little
356 		     more readable, the following macro is also just
357 		     to clear up the code a little.*/
358 
359   #define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0)
360 
361   /* init */
362   csr = 0;                 EMIT;
363   csr = CSR9_SR;           EMIT;
364   csr = CSR9_SR | CSR9_RD; EMIT;
365 
366   csr2 = CSR9_SR | CSR9_RD;
367   csr = 0;                 EMIT;
368   csr2 |= CSR9_CS;
369 
370   csr = 0;                 EMIT;
371   csr = CSR9_SRC;          EMIT;
372   csr = 0;                 EMIT;
373 
374   /* cmd 110 - Read */
375   csr = CSR9_DI;            EMIT;
376   csr = CSR9_DI | CSR9_SRC; EMIT;
377   csr = CSR9_DI;            EMIT;
378   csr = CSR9_DI | CSR9_SRC; EMIT;
379   csr = CSR9_DI;            EMIT;
380   csr = 0;                  EMIT;
381   csr = CSR9_SRC;           EMIT;
382   csr = 0;                  EMIT;
383 
384   /* addr to read */
385   for(i=nbAddrBits;i!=0;i--){
386     csr = (addr&(1<<(i-1))) != 0 ? CSR9_DI : 0;  EMIT;
387     csr ^= CSR9_SRC; EMIT;
388     csr ^= CSR9_SRC; EMIT;
389   }
390 
391   /* actual read */
392   retVal=0;
393   for(i=0;i<16;i++){
394     retVal <<= 1;
395     csr = CSR9_SRC; EMIT;
396     retVal |= (io_inl(CSR_ADDR(dep, CSR9)) & CSR9_DO) == 0 ? 0 : 1;
397     csr = 0; EMIT;
398   }
399 
400   /* clean up */
401   csr = 0;                 EMIT;
402 
403 #undef EMIT
404   return retVal;
405 }
406 
407 static void de_update_conf(dpeth_t * dep)
408 {
409   static char dpc_fmt[] = "x:d:x";
410   char ec_key[16];
411   long val;
412 
413   strlcpy(ec_key, "DEETH0", sizeof(ec_key));
414   ec_key[5] += de_instance;
415 
416   dep->de_mode = DEM_ENABLED;
417   switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
418   case EP_OFF:	dep->de_mode = DEM_DISABLED;	break;
419   case EP_ON:  dep->de_mode = DEM_SINK; break;
420   }
421   dep->de_base_port = 0;
422 
423   return;
424 }
425 
426 static void do_vread_s(const message * mp, int from_int)
427 {
428   u8_t *buffer;
429   u32_t size;
430   int r, ix = 0;
431   vir_bytes bytes;
432   dpeth_t *dep = NULL;
433   de_loc_descr_t *descr = NULL;
434   iovec_dat_s_t *iovp = NULL;
435 
436   dep = &de_state;
437 
438   dep->de_client = mp->m_source;
439 
440   if (dep->de_mode == DEM_ENABLED) {
441 
442     descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
443 
444     /* check if packet is in the current descr and only there */
445     if(  !( !(descr->descr->des[DES0] & DES0_OWN) &&
446 	    (descr->descr->des[DES0] & DES0_FS)   &&
447 	    (descr->descr->des[DES0] & DES0_LS)     ))
448       goto suspend;
449 
450 
451     /*TODO: multi-descr msgs...*/
452     /* We only support packets contained in a single descriptor.
453        Setting the descriptor buffer size to less then
454        ETH_MAX_PACK_SIZE will result in multi-descriptor
455        packets that we won't be able to handle
456     */
457     assert(!(descr->descr->des[DES0]&DES0_OWN));
458     assert(descr->descr->des[DES0]&DES0_FS);
459     assert(descr->descr->des[DES0]&DES0_LS);
460 
461     /* Check for abnormal messages. We assert here
462        because this driver is for a virtualized
463        envrionment where we will not get bad packets
464     */
465     assert(!(descr->descr->des[DES0]&DES0_ES));
466     assert(!(descr->descr->des[DES0]&DES0_RE));
467 
468 
469     /* Setup the iovec entry to allow copying into
470        client layer
471     */
472     dep->de_read_iovec.iod_proc_nr = mp->m_source;
473     de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0,
474 		      mp->m_net_netdrv_dl_readv_s.count,
475 		      dep->de_read_iovec.iod_iovec);
476     dep->de_read_iovec.iod_iovec_s = mp->m_net_netdrv_dl_readv_s.count;
477     dep->de_read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant;
478     dep->de_read_iovec.iod_iovec_offset = 0;
479     size = de_calc_iov_size(&dep->de_read_iovec);
480     if (size < ETH_MAX_PACK_SIZE)
481       panic("%s %d", str_SizeErrMsg, size);
482 
483     /* Copy buffer to user area  and clear ownage */
484     size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
485 
486     /*TODO: Complain to MS */
487     /*HACK: VPC2007 returns packet of invalid size. Ethernet standard
488       specify 46 bytes as the minimum for valid payload. However, this is
489       artificial in so far as for certain packet types, notably ARP, less
490       then 46 bytes are needed to contain the full information. In a non
491       virtualized environment the 46 bytes rule is enforced in order to give
492       guarantee in the collison detection scheme. Of course, this being a
493       driver for a VPC2007, we won't have collisions and I can only suppose
494       MS decided to cut packet size to true minimum, regardless of the
495       46 bytes payload standard. Note that this seems to not happen in
496       bridged mode. Note also, that the card does not return runt or
497       incomplete frames to us, so this hack is safe
498     */
499     if(size<60){
500       memset(&descr->buf1[size], 0, 60-size);
501       size=60;
502     }
503     /* End ugly hack */
504 
505     iovp = &dep->de_read_iovec;
506     buffer = descr->buf1;
507     dep->bytes_rx += size;
508     dep->de_stat.ets_packetR++;
509     dep->de_read_s = size;
510 
511     do {
512       bytes = iovp->iod_iovec[ix].iov_size;	/* Size of buffer */
513       if (bytes >= size)
514 	bytes = size;
515 
516       r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
517 			(vir_bytes)buffer, bytes);
518       if (r != OK)
519 	panic("%s %d", str_CopyErrMsg, r);
520       buffer += bytes;
521 
522       if (++ix >= IOVEC_NR) {	/* Next buffer of IO vector */
523 	de_next_iov(iovp);
524 	ix = 0;
525       }
526     } while ((size -= bytes) > 0);
527 
528     descr->descr->des[DES0]=DES0_OWN;
529     dep->cur_descr[DESCR_RECV]++;
530     if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
531       dep->cur_descr[DESCR_RECV] = 0;
532 
533     DEBUG(printf("Read returned size = %d\n", size));
534 
535     /* Reply information */
536     dep->de_flags |= DEF_ACK_RECV;
537     dep->de_flags &= NOT(DEF_READING);
538   }
539 
540   if(!from_int){
541     do_reply(dep);
542   }
543   return;
544 
545  suspend:
546   if(from_int){
547     assert(dep->de_flags & DEF_READING);
548     return;
549   }
550 
551   assert(!(dep->de_flags & DEF_READING));
552   dep->rx_return_msg = *mp;
553   dep->de_flags |= DEF_READING;
554   do_reply(dep);
555   return;
556 }
557 
558 static void de_conf_addr(dpeth_t * dep)
559 {
560   static char ea_fmt[] = "x:x:x:x:x:x";
561   char ea_key[16];
562   int ix;
563   long val;
564 
565   strlcpy(ea_key, "DEETH0_EA", sizeof(ea_key));
566   ea_key[5] += de_instance;
567 
568   for (ix = 0; ix < SA_ADDR_LEN; ix++) {
569 	val = dep->de_address.ea_addr[ix];
570 	if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
571 		break;
572 	dep->de_address.ea_addr[ix] = val;
573   }
574 
575   if (ix != 0 && ix != SA_ADDR_LEN)
576 	env_parse(ea_key, "?", 0, &val, 0L, 0L);
577   return;
578 }
579 
580 static void de_first_init(dpeth_t *dep)
581 {
582   int i,j,r;
583   vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf;
584   vir_bytes buffer_vir = (vir_bytes)dep->sendrecv_buf;
585   de_loc_descr_t *loc_descr;
586   phys_bytes temp;
587 
588 
589   for(i=0;i<2;i++){
590     loc_descr = &dep->descr[i][0];
591     for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
592 
593       /* assign buffer space for descriptor */
594       loc_descr->descr = (void*)descr_vir;
595       descr_vir += sizeof(de_descr_t);
596 
597       /* assign space for buffer */
598       loc_descr->buf1 = (u8_t*)buffer_vir;
599       buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
600       loc_descr->buf2 = 0;
601       loc_descr++;
602     }
603   }
604 
605   /* Now that we have buffer space and descriptors, we need to
606      obtain their physical address to pass to the hardware
607   */
608   for(i=0;i<2;i++){
609     loc_descr = &dep->descr[i][0];
610     temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
611     for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
612       /* translate buffers physical address */
613       r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp,
614 		   (phys_bytes *) &(loc_descr->descr->des[DES_BUF1]));
615       if(r != OK) panic("umap failed: %d", r);
616       loc_descr->descr->des[DES_BUF2] = 0;
617       memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t));
618       loc_descr->descr->des[DES1] = temp;
619       if(j==( (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR)-1))
620 	loc_descr->descr->des[DES1] |= DES1_ER;
621       if(i==DESCR_RECV)
622 	loc_descr->descr->des[DES0] |= DES0_OWN;
623       loc_descr++;
624     }
625   }
626 
627   /* record physical location of two first descriptor */
628   r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr,
629 	       sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]);
630   if(r != OK) panic("%s %d", str_UmapErrMsg, r);
631 
632   r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_TRAN][0].descr,
633 	       sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]);
634   if(r != OK) panic("%s %d", str_UmapErrMsg, r);
635 
636   DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
637 	       dep->sendrecv_descr_phys_addr[DESCR_TRAN],
638 	       dep->sendrecv_descr_phys_addr[DESCR_RECV]));
639 
640   /* check alignment just to be extra safe */
641   for(i=0;i<2;i++){
642     loc_descr = &dep->descr[i][0];
643     for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){
644       r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr),
645 			sizeof(de_descr_t), &temp);
646       if(r != OK)
647 	panic("%s %d", str_UmapErrMsg, r);
648 
649       if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
650 	  ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
651 	  ((temp&0x3)!=0) )
652 	panic("%s 0x%lx", str_AlignErrMsg, temp);
653 
654       loc_descr++;
655     }
656   }
657 
658   /* Init default values */
659   dep->cur_descr[DESCR_TRAN]=1;
660   dep->cur_descr[DESCR_RECV]=0;
661   dep->bytes_rx = 0;
662   dep->bytes_tx = 0;
663 
664   /* Set the interrupt handler policy. Request interrupts not to be reenabled
665    * automatically. Return the IRQ line number when an interrupt occurs.
666    */
667   dep->de_hook = dep->de_irq;
668   sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
669   sys_irqenable(&dep->de_hook);
670 }
671 
672 static void do_interrupt(const dpeth_t *dep){
673   u32_t val;
674   val = io_inl(CSR_ADDR(dep, CSR5));
675 
676   if(val & CSR5_AIS){
677     panic("Abnormal Int CSR5=: %d", val);
678   }
679 
680   if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){
681     do_vread_s(&dep->rx_return_msg, TRUE);
682   }
683 
684   if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){
685     do_vwrite_s(&dep->tx_return_msg, TRUE);
686   }
687 
688   /* ack and reset interrupts */
689   io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF);
690   return;
691 }
692 
693 static void de_reset(const dpeth_t *dep){
694   io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR);
695 }
696 
697 static void de_hw_conf(const dpeth_t *dep){
698   u32_t val;
699 
700   /* CSR0 - global host bus prop */
701   val = CSR0_BAR | CSR0_CAL_8;
702   io_outl(CSR_ADDR(dep, CSR0), val);
703 
704   /* CSR3 - Receive list BAR */
705   val = dep->sendrecv_descr_phys_addr[DESCR_RECV];
706   io_outl(CSR_ADDR(dep, CSR3), val);
707 
708   /* CSR4 - Transmit list BAR */
709   val = dep->sendrecv_descr_phys_addr[DESCR_TRAN];
710   io_outl(CSR_ADDR(dep, CSR4), val);
711 
712   /* CSR7 - interrupt mask */
713   val = CSR7_TI | CSR7_RI | CSR7_AI;
714   io_outl(CSR_ADDR(dep, CSR7), val);
715 
716   /* CSR6 - operating mode register */
717   val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD |
718     CSR6_PCS | CSR6_SCR | CSR6_TR_00;
719   io_outl(CSR_ADDR(dep, CSR6), val);
720 }
721 
722 static void de_start(const dpeth_t *dep){
723   u32_t val;
724   val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
725   io_outl(CSR_ADDR(dep, CSR6), val);
726 }
727 
728 static void de_setup_frame(const dpeth_t *dep){
729   int i;
730   u32_t val;
731 
732   /* this is not perfect... we assume pass all multicast and only
733      filter non-multicast frames */
734   dep->descr[DESCR_TRAN][0].buf1[0] = 0xFF;
735   dep->descr[DESCR_TRAN][0].buf1[1] = 0xFF;
736   dep->descr[DESCR_TRAN][0].buf1[4] = 0xFF;
737   dep->descr[DESCR_TRAN][0].buf1[5] = 0xFF;
738   dep->descr[DESCR_TRAN][0].buf1[8] = 0xFF;
739   dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
740   for(i=1;i<16;i++){
741     memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12);
742     dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0];
743     dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1];
744     dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2];
745     dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3];
746     dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4];
747     dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5];
748   }
749 
750   dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN;
751   dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET |
752     DE_SETUP_FRAME_SIZE | DES1_IC;
753 
754   /* start transmit process to process setup frame */
755   val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
756   io_outl(CSR_ADDR(dep, CSR6), val);
757   io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
758 
759   return;
760 }
761 
762 static int de_calc_iov_size(iovec_dat_s_t * iovp){
763   int size, ix;
764   size = ix = 0;
765 
766   do{
767     size += iovp->iod_iovec[ix].iov_size;
768     if (++ix >= IOVEC_NR) {
769       de_next_iov(iovp);
770       ix = 0;
771     }
772   } while (ix < iovp->iod_iovec_s);
773   return size;
774 }
775 
776 static void de_get_userdata_s(int user_proc, cp_grant_id_t grant,
777 	vir_bytes offset, int count, void *loc_addr){
778   int rc;
779   vir_bytes len;
780 
781   len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
782   rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len);
783   if (rc != OK)
784     panic("%s %d", str_CopyErrMsg, rc);
785   return;
786 }
787 
788 static void de_next_iov(iovec_dat_s_t * iovp){
789 
790   iovp->iod_iovec_s -= IOVEC_NR;
791   iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
792   de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
793 	     iovp->iod_iovec_s, iovp->iod_iovec);
794   return;
795 }
796 
797 static void do_vwrite_s(const message * mp, int from_int){
798   static u8_t setupDone = 0;
799   int size, r, bytes, ix, totalsize;
800   dpeth_t *dep;
801   iovec_dat_s_t *iovp = NULL;
802   de_loc_descr_t *descr = NULL;
803   u8_t *buffer = NULL;
804 
805   dep = &de_state;
806 
807   dep->de_client = mp->m_source;
808 
809   if (dep->de_mode == DEM_ENABLED) {
810 
811     if (!from_int && (dep->de_flags & DEF_SENDING))
812       panic("%s", str_BusyErrMsg);
813 
814     descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
815 
816     if(( descr->descr->des[DES0] & DES0_OWN)!=0)
817       goto suspend;
818 
819     if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){
820       dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
821       setupDone=1;
822     }
823 
824     buffer = descr->buf1;
825     iovp = &dep->de_write_iovec;
826     iovp->iod_proc_nr = mp->m_source;
827     de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0,
828 		      mp->m_net_netdrv_dl_writev_s.count, iovp->iod_iovec);
829     iovp->iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count;
830     iovp->iod_grant = mp->m_net_netdrv_dl_writev_s.grant;
831     iovp->iod_iovec_offset = 0;
832     totalsize = size = de_calc_iov_size(iovp);
833     if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
834       panic("%s %d", str_SizeErrMsg, size);
835 
836     dep->bytes_tx += size;
837     dep->de_stat.ets_packetT++;
838 
839     ix=0;
840     do {
841       bytes = iovp->iod_iovec[ix].iov_size;
842       if (bytes >= size)
843 	bytes = size;
844 
845       r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
846 			  0, (vir_bytes)buffer, bytes);
847       if (r != OK)
848 	panic("%s %d", str_CopyErrMsg, r);
849       buffer += bytes;
850 
851       if (++ix >= IOVEC_NR) {
852 	de_next_iov(iovp);
853 	ix = 0;
854       }
855     } while ((size -= bytes) > 0);
856 
857     descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
858       DES1_FS | DES1_LS | DES1_IC | totalsize;
859     descr->descr->des[DES0] = DES0_OWN;
860 
861     dep->cur_descr[DESCR_TRAN]++;
862     if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
863       dep->cur_descr[DESCR_TRAN] = 0;
864 
865     io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
866   }
867 
868   dep->de_flags |= DEF_ACK_SEND;
869   if(from_int){
870     dep->de_flags &= NOT(DEF_SENDING);
871     return;
872   }
873   do_reply(dep);
874   return;
875 
876  suspend:
877   if(from_int)
878     panic("should not happen: %d", 0);
879 
880   dep->de_stat.ets_transDef++;
881   dep->de_flags |= DEF_SENDING;
882   dep->de_stat.ets_transDef++;
883   dep->tx_return_msg = *mp;
884   do_reply(dep);
885 }
886 
887 static void warning(const char *type, int err){
888   printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err);
889   return;
890 }
891 
892 static u32_t io_inl(u16_t port){
893   u32_t value;
894   int rc;
895   if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc);
896   return value;
897 }
898 
899 static void io_outl(u16_t port, u32_t value){
900   int rc;
901   if ((rc = sys_outl(port, value)) != OK) warning("outl", rc);
902   return;
903 }
904