panic() cleanup.
[minix.git] / drivers / dec21140A / dec21140A.c
blob99481e310fcbccbf18c9860ee7ecc8921c6483b4
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/gen/ether.h>
22 #include <net/gen/eth_io.h>
23 #include <stdlib.h>
25 #include "dec21140A.h"
28 _PROTOTYPE( PRIVATE u32_t io_inl, (u16_t); );
29 _PROTOTYPE( PRIVATE void io_outl, (u16_t, u32_t); );
30 _PROTOTYPE( PRIVATE void do_conf, (message *); );
31 _PROTOTYPE( PRIVATE void do_get_name, (message *); );
32 _PROTOTYPE( PRIVATE void do_get_stat_s, (message *); );
33 _PROTOTYPE( PRIVATE void do_interrupt, (dpeth_t *); );
34 _PROTOTYPE( PRIVATE void do_reply, (dpeth_t *, int, int); );
35 _PROTOTYPE( PRIVATE void do_vread_s, (message *, int); );
36 _PROTOTYPE( PRIVATE void do_watchdog, (void *); );
38 _PROTOTYPE( PRIVATE void de_update_conf, (dpeth_t *); );
39 _PROTOTYPE( PRIVATE int de_probe, (dpeth_t *); );
40 _PROTOTYPE( PRIVATE void de_conf_addr, (dpeth_t *); );
41 _PROTOTYPE( PRIVATE void de_first_init, (dpeth_t *); );
42 _PROTOTYPE( PRIVATE void de_reset, (dpeth_t *); );
43 _PROTOTYPE( PRIVATE void de_hw_conf, (dpeth_t *); );
44 _PROTOTYPE( PRIVATE void de_start, (dpeth_t *); );
45 _PROTOTYPE( PRIVATE void de_setup_frame, (dpeth_t *); );
46 _PROTOTYPE( PRIVATE u16_t de_read_rom, (dpeth_t *, u8_t, u8_t); );
47 _PROTOTYPE( PRIVATE int de_calc_iov_size, (iovec_dat_s_t *); );
48 _PROTOTYPE( PRIVATE void de_next_iov, (iovec_dat_s_t *); );
49 _PROTOTYPE( PRIVATE void do_vwrite_s, (message *, int); );
50 _PROTOTYPE( PRIVATE void de_get_userdata_s, (int, cp_grant_id_t,
51 vir_bytes, int, void *); );
53 /* Error messages */
54 static char str_CopyErrMsg[] = "unable to read/write user data";
55 static char str_PortErrMsg[] = "illegal port";
56 static char str_SendErrMsg[] = "send failed";
57 static char str_SizeErrMsg[] = "illegal packet size";
58 static char str_UmapErrMsg[] = "Unable to sys_umap";
59 static char str_BusyErrMsg[] = "Send/Recv failed: busy";
60 static char str_StatErrMsg[] = "Unable to send stats";
61 static char str_AlignErrMsg[] = "Bad align of buffer/descriptor";
62 static char str_DevName[] = "dec21140A:eth#?";
64 PRIVATE dpeth_t de_table[DE_PORT_NR];
65 PRIVATE const char *progname;
67 int sef_cb_init(int type, sef_init_info_t *info)
69 int r;
70 int fkeys, sfkeys;
71 endpoint_t tasknr;
72 /* Request function key for debug dumps */
73 fkeys = sfkeys = 0; bit_set(sfkeys, DE_FKEY);
74 if ((fkey_map(&fkeys, &sfkeys)) != OK)
75 printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno);
77 /* Try to notify inet that we are present (again) */
78 r = ds_retrieve_label_num("inet", &tasknr);
79 if (r == OK)
80 notify(tasknr);
81 else if(r != ESRCH)
82 printf("%s unable to notify inet: %d\n", str_DevName, r);
84 return OK;
87 /*===========================================================================*
88 * main *
89 *===========================================================================*/
90 int main(int argc, char *argv[])
92 dpeth_t *dep;
93 message m;
94 int r;
96 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
98 env_setargs(argc, argv);
100 sef_setcb_init_fresh(sef_cb_init);
101 sef_setcb_init_restart(sef_cb_init);
102 sef_startup();
104 while (TRUE)
106 if ((r= sef_receive(ANY, &m)) != OK)
107 panic("minix msg sef_receive failed: %d", r);
109 if(is_notify(m.m_type)) {
110 switch(_ENDPOINT_P(m.m_source)) {
111 case RS_PROC_NR:
112 notify(m.m_source);
113 break;
114 case CLOCK:
115 do_watchdog(&m);
116 break;
118 case HARDWARE:
119 for (dep = de_table; dep < &de_table[DE_PORT_NR]; dep += 1) {
120 if (dep->de_mode == DEM_ENABLED) {
121 do_interrupt(dep);
122 if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
123 do_reply(dep, OK, TRUE);
124 sys_irqenable(&dep->de_hook);
127 break;
128 case PM_PROC_NR:
129 exit(0);
130 break;
131 default:
132 printf("ignoring notify from %d\n", m.m_source);
133 break;
135 continue;
138 switch (m.m_type)
140 case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break;
141 case DL_READV_S: do_vread_s(&m, FALSE); break;
142 case DL_CONF: do_conf(&m); break;
143 case DL_GETSTAT_S: do_get_stat_s(&m); break;
144 case DL_GETNAME: do_get_name(&m); break;
145 case DL_STOP: /* nothing */ break;
147 default:
148 printf("message 0x%lx; %d from %d\n",
149 m.m_type, m.m_type-DL_RQ_BASE, m.m_source);
150 panic("illegal message: %d", m.m_type);
155 PRIVATE void do_get_stat_s(message * mp)
157 int port, rc;
158 dpeth_t *dep;
160 port = mp->DL_PORT;
161 if (port < 0 || port >= DE_PORT_NR)
162 panic(str_PortErrMsg, port);
164 dep = &de_table[port];
165 dep->de_client = mp->DL_PROC;
167 if ((rc = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
168 (vir_bytes)&dep->de_stat,
169 (vir_bytes) sizeof(dep->de_stat), 0)) != OK)
170 panic(str_CopyErrMsg, rc);
172 mp->m_type = DL_STAT_REPLY;
173 mp->DL_PORT = port;
174 mp->DL_STAT = OK;
175 rc = send(mp->m_source, mp);
176 if( rc != OK )
177 panic(str_StatErrMsg, rc);
178 return;
181 PRIVATE void do_conf(message * mp)
183 int port;
184 dpeth_t *dep;
185 message reply_mess;
187 port = mp->DL_PORT;
188 if (port >= 0 && port < DE_PORT_NR) {
190 dep = &de_table[port];
191 strncpy(dep->de_name, str_DevName, strlen(str_DevName));
192 dep->de_name[strlen(dep->de_name)-1] = '0' + port;
194 if (dep->de_mode == DEM_DISABLED) {
195 de_update_conf(dep);
196 pci_init();
197 if (dep->de_mode == DEM_ENABLED && !de_probe(dep)) {
198 printf("%s: warning no ethernet card found at 0x%04X\n",
199 dep->de_name, dep->de_base_port);
200 dep->de_mode = DEM_DISABLED;
204 /* 'de_mode' may change if probe routines fail, test again */
205 switch (dep->de_mode) {
207 case DEM_DISABLED:
208 port = ENXIO; /* Device is OFF or hardware probe failed */
209 break;
211 case DEM_ENABLED:
212 if (dep->de_flags == DEF_EMPTY) {
213 de_first_init(dep);
214 dep->de_flags |= DEF_ENABLED;
215 de_reset(dep);
216 de_hw_conf(dep);
217 de_setup_frame(dep);
218 de_start(dep);
221 /* TODO CHECK PROMISC AND MULTI */
222 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
223 if (mp->DL_MODE & DL_PROMISC_REQ)
224 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
225 if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI;
226 if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD;
227 dep->de_client = mp->m_source;
228 break;
230 case DEM_SINK:
231 DEBUG(printf("%s running in sink mode\n", str_DevName));
232 memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
233 de_conf_addr(dep);
234 break;
236 default: break;
238 } else /* Port number is out of range */
239 port = ENXIO;
241 reply_mess.m_type = DL_CONF_REPLY;
242 reply_mess.m3_i1 = port;
243 reply_mess.m3_i2 = DE_PORT_NR;
244 *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
246 if (send(mp->m_source, &reply_mess) != OK)
247 panic(str_SendErrMsg, mp->m_source);
249 return;
253 PRIVATE void do_get_name(mp)
254 message *mp;
256 int r;
257 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
258 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
259 mp->m_type= DL_NAME_REPLY;
260 r = send(mp->m_source, mp);
261 if (r!= OK)
262 panic("do_getname: send failed: %d", r);
265 PRIVATE void do_reply(dpeth_t * dep, int err, int may_block)
267 message reply;
268 int status = FALSE;
270 if (dep->de_flags & DEF_ACK_SEND) status |= DL_PACK_SEND;
271 if (dep->de_flags & DEF_ACK_RECV) status |= DL_PACK_RECV;
273 reply.m_type = DL_TASK_REPLY;
274 reply.DL_PORT = dep - de_table;
275 reply.DL_PROC = dep->de_client;
276 reply.DL_STAT = status | ((u32_t) err << 16);
277 reply.DL_COUNT = dep->de_read_s;
278 reply.DL_CLCK = 0;
280 status = send(dep->de_client, &reply);
282 if(status == ELOCKED && may_block){
283 /*printf("Warning: Dec21041 send lock prevented\n\n");*/
284 return;
287 if(status < 0)
288 panic(str_SendErrMsg, status);
290 dep->de_read_s = 0;
291 dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
292 return;
295 PRIVATE void do_watchdog(void *message)
297 /* nothing here yet */
298 return;
301 PRIVATE int de_probe(dpeth_t *dep){
302 int i, r, devind;
303 u16_t vid, did, temp16;
305 DEBUG(printf("PROBING..."));
307 r= pci_first_dev(&devind, &vid, &did);
308 if (r == 0)
309 return FALSE;
311 for(;;)
313 if ( DEC21140A_VID == vid &&
314 DEC21140A_DID == did)
315 break;
317 r= pci_next_dev(&devind, &vid, &did);
318 if (!r)
319 return FALSE;
322 pci_reserve(devind);
324 dep->de_base_port = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
325 dep->de_irq = pci_attr_r8(devind, PCI_ILR);
327 if (dep->de_base_port < DE_MIN_BASE_ADDR)
328 panic("de_probe: base address invalid: %d", dep->de_base_port);
330 DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n",
331 dep->de_name, (unsigned long)dep->de_base_port,
332 dep->de_irq));
334 dep->de_type = pci_attr_r8(devind, PCI_REV);
336 /* device validation. We support only the DEC21140A */
337 if(dep->de_type != DEC_21140A){
338 dep->de_type = DE_TYPE_UNKNOWN;
339 printf("%s: unsupported device\n", str_DevName);
340 return FALSE;
343 de_reset(dep);
345 DEBUG(printf("Reading SROM...\n"));
347 for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
348 temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
349 dep->srom[i*2] = temp16 & 0xFF;
350 dep->srom[i*2+1] = temp16 >> 8;
353 /* TODO: validate SROM content */
354 /* acquire MAC addr */
355 DEBUG(printf("Using MAC addr= "));
356 for(i=0;i<6;i++){
357 dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
358 DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n'));
360 DEBUG(printf("probe success\n"));
361 return TRUE;
364 PRIVATE u16_t de_read_rom(dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
365 u16_t retVal = 0;
366 int i;
367 u32_t csr = 0;
368 u32_t csr2 = 0; /* csr2 is used to hold constant values that are
369 setup in the init phase, it makes this a little
370 more readable, the following macro is also just
371 to clear up the code a little.*/
373 #define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0)
375 /* init */
376 csr = 0; EMIT;
377 csr = CSR9_SR; EMIT;
378 csr = CSR9_SR | CSR9_RD; EMIT;
380 csr2 = CSR9_SR | CSR9_RD;
381 csr = 0; EMIT;
382 csr2 |= CSR9_CS;
384 csr = 0; EMIT;
385 csr = CSR9_SRC; EMIT;
386 csr = 0; EMIT;
388 /* cmd 110 - Read */
389 csr = CSR9_DI; EMIT;
390 csr = CSR9_DI | CSR9_SRC; EMIT;
391 csr = CSR9_DI; EMIT;
392 csr = CSR9_DI | CSR9_SRC; EMIT;
393 csr = CSR9_DI; EMIT;
394 csr = 0; EMIT;
395 csr = CSR9_SRC; EMIT;
396 csr = 0; EMIT;
398 /* addr to read */
399 for(i=nbAddrBits;i!=0;i--){
400 csr = (addr&(1<<(i-1))) != 0 ? CSR9_DI : 0; EMIT;
401 csr ^= CSR9_SRC; EMIT;
402 csr ^= CSR9_SRC; EMIT;
405 /* actual read */
406 retVal=0;
407 for(i=0;i<16;i++){
408 retVal <<= 1;
409 csr = CSR9_SRC; EMIT;
410 retVal |= (io_inl(CSR_ADDR(dep, CSR9)) & CSR9_DO) == 0 ? 0 : 1;
411 csr = 0; EMIT;
414 /* clean up */
415 csr = 0; EMIT;
417 #undef EMIT
418 return retVal;
421 static void de_update_conf(dpeth_t * dep)
423 static char dpc_fmt[] = "x:d:x";
424 long val;
426 dep->de_mode = DEM_ENABLED;
427 switch (env_parse("DEETH0", dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
428 case EP_OFF: dep->de_mode = DEM_DISABLED; break;
429 case EP_ON: dep->de_mode = DEM_SINK; break;
431 dep->de_base_port = 0;
433 return;
436 PRIVATE void do_vread_s(message * mp, int from_int)
438 char *buffer;
439 u32_t size;
440 int r, bytes, ix = 0;
441 dpeth_t *dep = NULL;
442 de_loc_descr_t *descr = NULL;
443 iovec_dat_s_t *iovp = NULL;
445 if (mp->DL_PORT < 0 || mp->DL_PORT >= DE_PORT_NR)
446 panic(str_PortErrMsg, mp->DL_PORT);
448 dep = &de_table[mp->DL_PORT];
449 dep->de_client = mp->DL_PROC;
451 if (dep->de_mode == DEM_ENABLED) {
453 descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
455 /* check if packet is in the current descr and only there */
456 if( !( !(descr->descr->des[DES0] & DES0_OWN) &&
457 (descr->descr->des[DES0] & DES0_FS) &&
458 (descr->descr->des[DES0] & DES0_LS) ))
459 goto suspend;
462 /*TODO: multi-descr msgs...*/
463 /* We only support packets contained in a single descriptor.
464 Setting the descriptor buffer size to less then
465 ETH_MAX_PACK_SIZE will result in multi-descriptor
466 packets that we won't be able to handle
468 assert(!(descr->descr->des[DES0]&DES0_OWN));
469 assert(descr->descr->des[DES0]&DES0_FS);
470 assert(descr->descr->des[DES0]&DES0_LS);
472 /* Check for abnormal messages. We assert here
473 because this driver is for a virtualized
474 envrionment where we will not get bad packets
476 assert(!(descr->descr->des[DES0]&DES0_ES));
477 assert(!(descr->descr->des[DES0]&DES0_RE));
480 /* Setup the iovec entry to allow copying into
481 client layer
483 dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
484 de_get_userdata_s(mp->DL_PROC, (cp_grant_id_t) mp->DL_GRANT, 0,
485 mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
486 dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
487 dep->de_read_iovec.iod_grant = (cp_grant_id_t) mp->DL_GRANT;
488 dep->de_read_iovec.iod_iovec_offset = 0;
489 size = de_calc_iov_size(&dep->de_read_iovec);
490 if (size < ETH_MAX_PACK_SIZE)
491 panic(str_SizeErrMsg, size);
493 /* Copy buffer to user area and clear ownage */
494 size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
496 /*TODO: Complain to MS */
497 /*HACK: VPC2007 returns packet of invalid size. Ethernet standard
498 specify 46 bytes as the minimum for valid payload. However, this is
499 artificial in so far as for certain packet types, notably ARP, less
500 then 46 bytes are needed to contain the full information. In a non
501 virtualized environment the 46 bytes rule is enforced in order to give
502 guarantee in the collison detection scheme. Of course, this being a
503 driver for a VPC2007, we won't have collisions and I can only suppose
504 MS decided to cut packet size to true minimum, regardless of the
505 46 bytes payload standard. Note that this seems to not happen in
506 bridged mode. Note also, that the card does not return runt or
507 incomplete frames to us, so this hack is safe
509 if(size<60){
510 bzero(&descr->buf1[size], 60-size);
511 size=60;
513 /* End ugly hack */
515 iovp = &dep->de_read_iovec;
516 buffer = descr->buf1;
517 dep->bytes_rx += size;
518 dep->de_stat.ets_packetR++;
519 dep->de_read_s = size;
521 do {
522 bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
523 if (bytes >= size)
524 bytes = size;
526 r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
527 (vir_bytes)buffer, bytes, D);
528 if (r != OK)
529 panic(str_CopyErrMsg, r);
530 buffer += bytes;
532 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
533 de_next_iov(iovp);
534 ix = 0;
536 } while ((size -= bytes) > 0);
538 descr->descr->des[DES0]=DES0_OWN;
539 dep->cur_descr[DESCR_RECV]++;
540 if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
541 dep->cur_descr[DESCR_RECV] = 0;
543 DEBUG(printf("Read returned size = %d\n", size));
545 /* Reply information */
546 dep->de_flags |= DEF_ACK_RECV;
547 dep->de_flags &= NOT(DEF_READING);
550 if(!from_int){
551 do_reply(dep, OK, FALSE);
553 return;
555 suspend:
556 if(from_int){
557 assert(dep->de_flags & DEF_READING);
558 return;
561 assert(!(dep->de_flags & DEF_READING));
562 dep->rx_return_msg = *mp;
563 dep->de_flags |= DEF_READING;
564 do_reply(dep, OK, FALSE);
565 return;
568 PRIVATE void de_conf_addr(dpeth_t * dep)
570 static char ea_fmt[] = "x:x:x:x:x:x";
571 char ea_key[16];
572 int ix;
573 long val;
575 /* TODO: should be configurable... */
576 strcpy(ea_key, "DEETH0");
577 strcat(ea_key, "_EA");
579 for (ix = 0; ix < SA_ADDR_LEN; ix++) {
580 val = dep->de_address.ea_addr[ix];
581 if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
582 break;
583 dep->de_address.ea_addr[ix] = val;
586 if (ix != 0 && ix != SA_ADDR_LEN)
587 env_parse(ea_key, "?", 0, &val, 0L, 0L);
588 return;
591 PRIVATE void de_first_init(dpeth_t *dep)
593 int i,j,r;
594 vir_bytes descr_vir = dep->sendrecv_descr_buf;
595 vir_bytes buffer_vir = dep->sendrecv_buf;
596 de_descr_t *phys_descr;
597 de_loc_descr_t *loc_descr;
598 u32_t temp;
601 for(i=0;i<2;i++){
602 loc_descr = &dep->descr[i][0];
603 for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
605 /* assign buffer space for descriptor */
606 loc_descr->descr = descr_vir;
607 descr_vir += sizeof(de_descr_t);
609 /* assign space for buffer */
610 loc_descr->buf1 = buffer_vir;
611 buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
612 loc_descr->buf2 = 0;
613 loc_descr++;
617 /* Now that we have buffer space and descriptors, we need to
618 obtain their physical address to pass to the hardware
620 for(i=0;i<2;i++){
621 loc_descr = &dep->descr[i][0];
622 temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
623 for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
624 /* translate buffers physical address */
625 r = sys_umap(SELF, VM_D, loc_descr->buf1, temp,
626 &(loc_descr->descr->des[DES_BUF1]));
627 if(r != OK) panic("umap failed: %d", r);
628 loc_descr->descr->des[DES_BUF2] = 0;
629 memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t));
630 loc_descr->descr->des[DES1] = temp;
631 if(j==( (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR)-1))
632 loc_descr->descr->des[DES1] |= DES1_ER;
633 if(i==DESCR_RECV)
634 loc_descr->descr->des[DES0] |= DES0_OWN;
635 loc_descr++;
639 /* record physical location of two first descriptor */
640 r = sys_umap(SELF, VM_D, dep->descr[DESCR_RECV][0].descr,
641 sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]);
642 if(r != OK) panic(str_UmapErrMsg, r);
644 r = sys_umap(SELF, VM_D, dep->descr[DESCR_TRAN][0].descr,
645 sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]);
646 if(r != OK) panic(str_UmapErrMsg, r);
648 DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
649 dep->sendrecv_descr_phys_addr[DESCR_TRAN],
650 dep->sendrecv_descr_phys_addr[DESCR_RECV]));
652 /* check alignment just to be extra safe */
653 for(i=0;i<2;i++){
654 loc_descr = &dep->descr[i][0];
655 for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){
656 r = sys_umap(SELF, VM_D, &(loc_descr->descr), sizeof(de_descr_t),
657 &temp);
658 if(r != OK)
659 panic(str_UmapErrMsg, r);
661 if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
662 ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
663 ((temp&0x3)!=0) )
664 panic(str_AlignErrMsg, temp);
666 loc_descr++;
670 /* Init default values */
671 dep->cur_descr[DESCR_TRAN]=1;
672 dep->cur_descr[DESCR_RECV]=0;
673 dep->bytes_rx = 0;
674 dep->bytes_tx = 0;
676 /* Set the interrupt handler policy. Request interrupts not to be reenabled
677 * automatically. Return the IRQ line number when an interrupt occurs.
679 dep->de_hook = dep->de_irq;
680 sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
681 sys_irqenable(&dep->de_hook);
684 PRIVATE void do_interrupt(dpeth_t *dep){
685 u32_t val;
686 val = io_inl(CSR_ADDR(dep, CSR5));
688 if(val & CSR5_AIS){
689 panic("Abnormal Int CSR5=: %d", val);
692 if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){
693 do_vread_s(&dep->rx_return_msg, TRUE);
696 if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){
697 do_vwrite_s(&dep->tx_return_msg, TRUE);
700 /* ack and reset interrupts */
701 io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF);
702 return;
705 PRIVATE void de_reset(dpeth_t *dep){
706 io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR);
709 PRIVATE void de_hw_conf(dpeth_t *dep){
710 u32_t val;
712 /* CSR0 - global host bus prop */
713 val = CSR0_BAR | CSR0_CAL_8;
714 io_outl(CSR_ADDR(dep, CSR0), val);
716 /* CSR3 - Receive list BAR */
717 val = dep->sendrecv_descr_phys_addr[DESCR_RECV];
718 io_outl(CSR_ADDR(dep, CSR3), val);
720 /* CSR4 - Transmit list BAR */
721 val = dep->sendrecv_descr_phys_addr[DESCR_TRAN];
722 io_outl(CSR_ADDR(dep, CSR4), val);
724 /* CSR7 - interrupt mask */
725 val = CSR7_TI | CSR7_RI | CSR7_AI;
726 io_outl(CSR_ADDR(dep, CSR7), val);
728 /* CSR6 - operating mode register */
729 val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD |
730 CSR6_PCS | CSR6_SCR | CSR6_TR_00;
731 io_outl(CSR_ADDR(dep, CSR6), val);
734 PRIVATE void de_start(dpeth_t *dep){
735 u32_t val;
736 val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
737 io_outl(CSR_ADDR(dep, CSR6), val);
740 PRIVATE void de_setup_frame(dpeth_t *dep){
741 int i;
742 u32_t val;
744 /* this is not perfect... we assume pass all multicast and only
745 filter non-multicast frames */
746 dep->descr[DESCR_TRAN][0].buf1[0] = 0xFF;
747 dep->descr[DESCR_TRAN][0].buf1[1] = 0xFF;
748 dep->descr[DESCR_TRAN][0].buf1[4] = 0xFF;
749 dep->descr[DESCR_TRAN][0].buf1[5] = 0xFF;
750 dep->descr[DESCR_TRAN][0].buf1[8] = 0xFF;
751 dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
752 for(i=1;i<16;i++){
753 memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12);
754 dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0];
755 dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1];
756 dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2];
757 dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3];
758 dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4];
759 dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5];
762 dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN;
763 dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET |
764 DE_SETUP_FRAME_SIZE | DES1_IC;
766 /* start transmit process to process setup frame */
767 val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
768 io_outl(CSR_ADDR(dep, CSR6), val);
769 io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
771 return;
774 PRIVATE int de_calc_iov_size(iovec_dat_s_t * iovp){
775 int size, ix;
776 size = ix = 0;
779 size += iovp->iod_iovec[ix].iov_size;
780 if (++ix >= IOVEC_NR) {
781 de_next_iov(iovp);
782 ix = 0;
784 } while (ix < iovp->iod_iovec_s);
785 return size;
788 PRIVATE void de_get_userdata_s(int user_proc, cp_grant_id_t grant,
789 vir_bytes offset, int count, void *loc_addr){
790 int rc;
791 vir_bytes len;
793 len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
794 rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len, D);
795 if (rc != OK)
796 panic(str_CopyErrMsg, rc);
797 return;
800 PRIVATE void de_next_iov(iovec_dat_s_t * iovp){
802 iovp->iod_iovec_s -= IOVEC_NR;
803 iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
804 de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
805 iovp->iod_iovec_s, iovp->iod_iovec);
806 return;
809 PRIVATE void do_vwrite_s(message * mp, int from_int){
810 static u8_t setupDone = 0;
811 int size, r, bytes, ix, totalsize;
812 dpeth_t *dep = NULL;
813 iovec_dat_s_t *iovp = NULL;
814 de_loc_descr_t *descr = NULL;
815 char *buffer = NULL;
817 if( mp->DL_PORT < 0 || mp->DL_PORT >= DE_PORT_NR)
818 panic(str_PortErrMsg, mp->DL_PORT);
820 dep = &de_table[mp->DL_PORT];
821 dep->de_client = mp->DL_PROC;
823 if (dep->de_mode == DEM_ENABLED) {
825 if (!from_int && (dep->de_flags & DEF_SENDING))
826 panic(str_BusyErrMsg);
828 descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
830 if(( descr->descr->des[DES0] & DES0_OWN)!=0)
831 goto suspend;
833 if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){
834 dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
835 setupDone=1;
838 buffer = descr->buf1;
839 iovp = &dep->de_write_iovec;
840 iovp->iod_proc_nr = mp->DL_PROC;
841 de_get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
842 mp->DL_COUNT, iovp->iod_iovec);
843 iovp->iod_iovec_s = mp->DL_COUNT;
844 iovp->iod_grant = (cp_grant_id_t) mp->DL_GRANT;
845 iovp->iod_iovec_offset = 0;
846 totalsize = size = de_calc_iov_size(iovp);
847 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
848 panic(str_SizeErrMsg, size);
850 dep->bytes_tx += size;
851 dep->de_stat.ets_packetT++;
853 ix=0;
854 do {
855 bytes = iovp->iod_iovec[ix].iov_size;
856 if (bytes >= size)
857 bytes = size;
859 r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
860 0, (vir_bytes)buffer, bytes, D);
861 if (r != OK)
862 panic(str_CopyErrMsg, r);
863 buffer += bytes;
865 if (++ix >= IOVEC_NR) {
866 de_next_iov(iovp);
867 ix = 0;
869 } while ((size -= bytes) > 0);
871 descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
872 DES1_FS | DES1_LS | DES1_IC | totalsize;
873 descr->descr->des[DES0] = DES0_OWN;
875 dep->cur_descr[DESCR_TRAN]++;
876 if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
877 dep->cur_descr[DESCR_TRAN] = 0;
879 io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
882 dep->de_flags |= DEF_ACK_SEND;
883 if(from_int){
884 dep->de_flags &= NOT(DEF_SENDING);
885 return;
887 do_reply(dep, OK, FALSE);
888 return;
890 suspend:
891 if(from_int)
892 panic("should not happen: %d", 0);
894 dep->de_stat.ets_transDef++;
895 dep->de_flags |= DEF_SENDING;
896 dep->de_stat.ets_transDef++;
897 dep->tx_return_msg = *mp;
898 do_reply(dep, OK, FALSE);
901 PRIVATE void warning(const char *type, int err){
902 printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err);
903 return;
906 PRIVATE u32_t io_inl(u16_t port){
907 u32_t value;
908 int rc;
909 if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc);
910 return value;
913 PRIVATE void io_outl(u16_t port, u32_t value){
914 int rc;
915 if ((rc = sys_outl(port, value)) != OK) warning("outl", rc);
916 return;