vm: fix a null dereference on out-of-memory
[minix.git] / drivers / dec21140A / dec21140A.c
blobc6edcf8ce383b517f3d82e728abea8086d5eca9d
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 <minix/drivers.h>
13 #include <minix/netdriver.h>
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>
26 #include "dec21140A.h"
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 *);
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 *);
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#?";
63 static dpeth_t de_state;
64 static int de_instance;
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);
70 /*===========================================================================*
71 * main *
72 *===========================================================================*/
73 int main(int argc, char *argv[])
75 dpeth_t *dep;
76 message m;
77 int ipc_status;
78 int r;
80 /* SEF local startup. */
81 env_setargs(argc, argv);
82 sef_local_startup();
84 while (TRUE)
86 if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
87 panic("netdriver_receive failed: %d", r);
89 if(is_ipc_notify(ipc_status)) {
90 switch(_ENDPOINT_P(m.m_source)) {
91 case CLOCK:
92 do_watchdog(&m);
93 break;
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);
103 break;
104 default:
105 printf("ignoring notify from %d\n", m.m_source);
106 break;
108 continue;
111 switch (m.m_type)
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;
118 default:
119 printf("message 0x%lx; %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);
126 /*===========================================================================*
127 * sef_local_startup *
128 *===========================================================================*/
129 static void sef_local_startup()
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);
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);
140 /* Register signal callbacks. */
141 sef_setcb_signal_handler(sef_cb_signal_handler_term);
143 /* Let SEF perform startup. */
144 sef_startup();
147 /*===========================================================================*
148 * sef_cb_init_fresh *
149 *===========================================================================*/
150 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
152 /* Initialize the DEC 21140A driver. */
153 int fkeys, sfkeys;
154 long v;
156 v = 0;
157 (void) env_parse("instance", "d", 0, &v, 0, 255);
158 de_instance = (int) v;
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);
166 /* Announce we are up! */
167 netdriver_announce();
169 return OK;
172 static void do_get_stat_s(message * mp)
174 int rc;
175 dpeth_t *dep;
177 dep = &de_state;
179 if ((rc = sys_safecopyto(mp->m_source, mp->DL_GRANT, 0UL,
180 (vir_bytes)&dep->de_stat,
181 sizeof(dep->de_stat))) != OK)
182 panic(str_CopyErrMsg, rc);
184 mp->m_type = DL_STAT_REPLY;
185 rc = send(mp->m_source, mp);
186 if( rc != OK )
187 panic(str_StatErrMsg, rc);
188 return;
191 static void do_conf(const message * mp)
193 int r;
194 dpeth_t *dep;
195 message reply_mess;
197 dep = &de_state;
199 strncpy(dep->de_name, str_DevName, strlen(str_DevName));
200 dep->de_name[strlen(dep->de_name)-1] = '0' + de_instance;
202 if (dep->de_mode == DEM_DISABLED) {
203 de_update_conf(dep);
204 pci_init();
205 if (dep->de_mode == DEM_ENABLED && !de_probe(dep, de_instance)) {
206 printf("%s: warning no ethernet card found at 0x%04X\n",
207 dep->de_name, dep->de_base_port);
208 dep->de_mode = DEM_DISABLED;
212 r = OK;
214 /* 'de_mode' may change if probe routines fail, test again */
215 switch (dep->de_mode) {
217 case DEM_DISABLED:
218 r = ENXIO; /* Device is OFF or hardware probe failed */
219 break;
221 case DEM_ENABLED:
222 if (dep->de_flags == DEF_EMPTY) {
223 de_first_init(dep);
224 dep->de_flags |= DEF_ENABLED;
225 de_reset(dep);
226 de_hw_conf(dep);
227 de_setup_frame(dep);
228 de_start(dep);
231 /* TODO CHECK PROMISC AND MULTI */
232 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
233 if (mp->DL_MODE & DL_PROMISC_REQ)
234 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
235 if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI;
236 if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD;
237 break;
239 case DEM_SINK:
240 DEBUG(printf("%s running in sink mode\n", str_DevName));
241 memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
242 de_conf_addr(dep);
243 break;
245 default: break;
248 reply_mess.m_type = DL_CONF_REPLY;
249 reply_mess.DL_STAT = r;
250 if(r == OK){
251 *(ether_addr_t *) reply_mess.DL_HWADDR = dep->de_address;
254 if (send(mp->m_source, &reply_mess) != OK)
255 panic(str_SendErrMsg, mp->m_source);
257 return;
260 static void do_reply(dpeth_t * dep)
262 message reply;
263 int r, flags = DL_NOFLAGS;
265 if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND;
266 if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV;
268 reply.m_type = DL_TASK_REPLY;
269 reply.DL_FLAGS = flags;
270 reply.DL_COUNT = dep->de_read_s;
272 r = send(dep->de_client, &reply);
274 if(r < 0)
275 panic(str_SendErrMsg, r);
277 dep->de_read_s = 0;
278 dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
279 return;
282 static void do_watchdog(void *UNUSED(message))
284 /* nothing here yet */
285 return;
288 static int de_probe(dpeth_t *dep, int skip)
290 int i, r, devind;
291 u16_t vid, did, temp16;
293 DEBUG(printf("PROBING..."));
295 r= pci_first_dev(&devind, &vid, &did);
296 if (r == 0)
297 return FALSE;
299 while (skip--)
301 r= pci_next_dev(&devind, &vid, &did);
302 if (!r)
303 return FALSE;
306 pci_reserve(devind);
308 dep->de_base_port = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
309 dep->de_irq = pci_attr_r8(devind, PCI_ILR);
311 if (dep->de_base_port < DE_MIN_BASE_ADDR)
312 panic("de_probe: base address invalid: %d", dep->de_base_port);
314 DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n",
315 dep->de_name, (unsigned long)dep->de_base_port,
316 dep->de_irq));
318 dep->de_type = pci_attr_r8(devind, PCI_REV);
320 /* device validation. We support only the DEC21140A */
321 if(dep->de_type != DEC_21140A){
322 dep->de_type = DE_TYPE_UNKNOWN;
323 printf("%s: unsupported device\n", str_DevName);
324 return FALSE;
327 de_reset(dep);
329 DEBUG(printf("Reading SROM...\n"));
331 for(i=0;i<(1<<SROM_BITWIDTH)-1;i++){
332 temp16 = de_read_rom(dep, i, SROM_BITWIDTH);
333 dep->srom[i*2] = temp16 & 0xFF;
334 dep->srom[i*2+1] = temp16 >> 8;
337 /* TODO: validate SROM content */
338 /* acquire MAC addr */
339 DEBUG(printf("Using MAC addr= "));
340 for(i=0;i<6;i++){
341 dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET];
342 DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n'));
344 DEBUG(printf("probe success\n"));
345 return TRUE;
348 static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){
349 u16_t retVal = 0;
350 int i;
351 u32_t csr = 0;
352 u32_t csr2 = 0; /* csr2 is used to hold constant values that are
353 setup in the init phase, it makes this a little
354 more readable, the following macro is also just
355 to clear up the code a little.*/
357 #define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0)
359 /* init */
360 csr = 0; EMIT;
361 csr = CSR9_SR; EMIT;
362 csr = CSR9_SR | CSR9_RD; EMIT;
364 csr2 = CSR9_SR | CSR9_RD;
365 csr = 0; EMIT;
366 csr2 |= CSR9_CS;
368 csr = 0; EMIT;
369 csr = CSR9_SRC; EMIT;
370 csr = 0; EMIT;
372 /* cmd 110 - Read */
373 csr = CSR9_DI; EMIT;
374 csr = CSR9_DI | CSR9_SRC; EMIT;
375 csr = CSR9_DI; EMIT;
376 csr = CSR9_DI | CSR9_SRC; EMIT;
377 csr = CSR9_DI; EMIT;
378 csr = 0; EMIT;
379 csr = CSR9_SRC; EMIT;
380 csr = 0; EMIT;
382 /* addr to read */
383 for(i=nbAddrBits;i!=0;i--){
384 csr = (addr&(1<<(i-1))) != 0 ? CSR9_DI : 0; EMIT;
385 csr ^= CSR9_SRC; EMIT;
386 csr ^= CSR9_SRC; EMIT;
389 /* actual read */
390 retVal=0;
391 for(i=0;i<16;i++){
392 retVal <<= 1;
393 csr = CSR9_SRC; EMIT;
394 retVal |= (io_inl(CSR_ADDR(dep, CSR9)) & CSR9_DO) == 0 ? 0 : 1;
395 csr = 0; EMIT;
398 /* clean up */
399 csr = 0; EMIT;
401 #undef EMIT
402 return retVal;
405 static void de_update_conf(dpeth_t * dep)
407 static char dpc_fmt[] = "x:d:x";
408 char ec_key[16];
409 long val;
411 strlcpy(ec_key, "DEETH0", sizeof(ec_key));
412 ec_key[5] += de_instance;
414 dep->de_mode = DEM_ENABLED;
415 switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
416 case EP_OFF: dep->de_mode = DEM_DISABLED; break;
417 case EP_ON: dep->de_mode = DEM_SINK; break;
419 dep->de_base_port = 0;
421 return;
424 static void do_vread_s(const message * mp, int from_int)
426 u8_t *buffer;
427 u32_t size;
428 int r, ix = 0;
429 vir_bytes bytes;
430 dpeth_t *dep = NULL;
431 de_loc_descr_t *descr = NULL;
432 iovec_dat_s_t *iovp = NULL;
434 dep = &de_state;
436 dep->de_client = mp->m_source;
438 if (dep->de_mode == DEM_ENABLED) {
440 descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]];
442 /* check if packet is in the current descr and only there */
443 if( !( !(descr->descr->des[DES0] & DES0_OWN) &&
444 (descr->descr->des[DES0] & DES0_FS) &&
445 (descr->descr->des[DES0] & DES0_LS) ))
446 goto suspend;
449 /*TODO: multi-descr msgs...*/
450 /* We only support packets contained in a single descriptor.
451 Setting the descriptor buffer size to less then
452 ETH_MAX_PACK_SIZE will result in multi-descriptor
453 packets that we won't be able to handle
455 assert(!(descr->descr->des[DES0]&DES0_OWN));
456 assert(descr->descr->des[DES0]&DES0_FS);
457 assert(descr->descr->des[DES0]&DES0_LS);
459 /* Check for abnormal messages. We assert here
460 because this driver is for a virtualized
461 envrionment where we will not get bad packets
463 assert(!(descr->descr->des[DES0]&DES0_ES));
464 assert(!(descr->descr->des[DES0]&DES0_RE));
467 /* Setup the iovec entry to allow copying into
468 client layer
470 dep->de_read_iovec.iod_proc_nr = mp->m_source;
471 de_get_userdata_s(mp->m_source, (cp_grant_id_t) mp->DL_GRANT, 0,
472 mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
473 dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
474 dep->de_read_iovec.iod_grant = (cp_grant_id_t) mp->DL_GRANT;
475 dep->de_read_iovec.iod_iovec_offset = 0;
476 size = de_calc_iov_size(&dep->de_read_iovec);
477 if (size < ETH_MAX_PACK_SIZE)
478 panic(str_SizeErrMsg, size);
480 /* Copy buffer to user area and clear ownage */
481 size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT;
483 /*TODO: Complain to MS */
484 /*HACK: VPC2007 returns packet of invalid size. Ethernet standard
485 specify 46 bytes as the minimum for valid payload. However, this is
486 artificial in so far as for certain packet types, notably ARP, less
487 then 46 bytes are needed to contain the full information. In a non
488 virtualized environment the 46 bytes rule is enforced in order to give
489 guarantee in the collison detection scheme. Of course, this being a
490 driver for a VPC2007, we won't have collisions and I can only suppose
491 MS decided to cut packet size to true minimum, regardless of the
492 46 bytes payload standard. Note that this seems to not happen in
493 bridged mode. Note also, that the card does not return runt or
494 incomplete frames to us, so this hack is safe
496 if(size<60){
497 bzero(&descr->buf1[size], 60-size);
498 size=60;
500 /* End ugly hack */
502 iovp = &dep->de_read_iovec;
503 buffer = descr->buf1;
504 dep->bytes_rx += size;
505 dep->de_stat.ets_packetR++;
506 dep->de_read_s = size;
508 do {
509 bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */
510 if (bytes >= size)
511 bytes = size;
513 r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
514 (vir_bytes)buffer, bytes);
515 if (r != OK)
516 panic(str_CopyErrMsg, r);
517 buffer += bytes;
519 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
520 de_next_iov(iovp);
521 ix = 0;
523 } while ((size -= bytes) > 0);
525 descr->descr->des[DES0]=DES0_OWN;
526 dep->cur_descr[DESCR_RECV]++;
527 if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR)
528 dep->cur_descr[DESCR_RECV] = 0;
530 DEBUG(printf("Read returned size = %d\n", size));
532 /* Reply information */
533 dep->de_flags |= DEF_ACK_RECV;
534 dep->de_flags &= NOT(DEF_READING);
537 if(!from_int){
538 do_reply(dep);
540 return;
542 suspend:
543 if(from_int){
544 assert(dep->de_flags & DEF_READING);
545 return;
548 assert(!(dep->de_flags & DEF_READING));
549 dep->rx_return_msg = *mp;
550 dep->de_flags |= DEF_READING;
551 do_reply(dep);
552 return;
555 static void de_conf_addr(dpeth_t * dep)
557 static char ea_fmt[] = "x:x:x:x:x:x";
558 char ea_key[16];
559 int ix;
560 long val;
562 strlcpy(ea_key, "DEETH0_EA", sizeof(ea_key));
563 ea_key[5] += de_instance;
565 for (ix = 0; ix < SA_ADDR_LEN; ix++) {
566 val = dep->de_address.ea_addr[ix];
567 if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
568 break;
569 dep->de_address.ea_addr[ix] = val;
572 if (ix != 0 && ix != SA_ADDR_LEN)
573 env_parse(ea_key, "?", 0, &val, 0L, 0L);
574 return;
577 static void de_first_init(dpeth_t *dep)
579 int i,j,r;
580 vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf;
581 vir_bytes buffer_vir = (vir_bytes)dep->sendrecv_buf;
582 de_loc_descr_t *loc_descr;
583 u32_t temp;
586 for(i=0;i<2;i++){
587 loc_descr = &dep->descr[i][0];
588 for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
590 /* assign buffer space for descriptor */
591 loc_descr->descr = (void*)descr_vir;
592 descr_vir += sizeof(de_descr_t);
594 /* assign space for buffer */
595 loc_descr->buf1 = (u8_t*)buffer_vir;
596 buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
597 loc_descr->buf2 = 0;
598 loc_descr++;
602 /* Now that we have buffer space and descriptors, we need to
603 obtain their physical address to pass to the hardware
605 for(i=0;i<2;i++){
606 loc_descr = &dep->descr[i][0];
607 temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE);
608 for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){
609 /* translate buffers physical address */
610 r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp,
611 &(loc_descr->descr->des[DES_BUF1]));
612 if(r != OK) panic("umap failed: %d", r);
613 loc_descr->descr->des[DES_BUF2] = 0;
614 memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t));
615 loc_descr->descr->des[DES1] = temp;
616 if(j==( (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR)-1))
617 loc_descr->descr->des[DES1] |= DES1_ER;
618 if(i==DESCR_RECV)
619 loc_descr->descr->des[DES0] |= DES0_OWN;
620 loc_descr++;
624 /* record physical location of two first descriptor */
625 r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr,
626 sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]);
627 if(r != OK) panic(str_UmapErrMsg, r);
629 r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_TRAN][0].descr,
630 sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]);
631 if(r != OK) panic(str_UmapErrMsg, r);
633 DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n",
634 dep->sendrecv_descr_phys_addr[DESCR_TRAN],
635 dep->sendrecv_descr_phys_addr[DESCR_RECV]));
637 /* check alignment just to be extra safe */
638 for(i=0;i<2;i++){
639 loc_descr = &dep->descr[i][0];
640 for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){
641 r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr),
642 sizeof(de_descr_t), &temp);
643 if(r != OK)
644 panic(str_UmapErrMsg, r);
646 if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) ||
647 ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) ||
648 ((temp&0x3)!=0) )
649 panic(str_AlignErrMsg, temp);
651 loc_descr++;
655 /* Init default values */
656 dep->cur_descr[DESCR_TRAN]=1;
657 dep->cur_descr[DESCR_RECV]=0;
658 dep->bytes_rx = 0;
659 dep->bytes_tx = 0;
661 /* Set the interrupt handler policy. Request interrupts not to be reenabled
662 * automatically. Return the IRQ line number when an interrupt occurs.
664 dep->de_hook = dep->de_irq;
665 sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
666 sys_irqenable(&dep->de_hook);
669 static void do_interrupt(const dpeth_t *dep){
670 u32_t val;
671 val = io_inl(CSR_ADDR(dep, CSR5));
673 if(val & CSR5_AIS){
674 panic("Abnormal Int CSR5=: %d", val);
677 if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){
678 do_vread_s(&dep->rx_return_msg, TRUE);
681 if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){
682 do_vwrite_s(&dep->tx_return_msg, TRUE);
685 /* ack and reset interrupts */
686 io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF);
687 return;
690 static void de_reset(const dpeth_t *dep){
691 io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR);
694 static void de_hw_conf(const dpeth_t *dep){
695 u32_t val;
697 /* CSR0 - global host bus prop */
698 val = CSR0_BAR | CSR0_CAL_8;
699 io_outl(CSR_ADDR(dep, CSR0), val);
701 /* CSR3 - Receive list BAR */
702 val = dep->sendrecv_descr_phys_addr[DESCR_RECV];
703 io_outl(CSR_ADDR(dep, CSR3), val);
705 /* CSR4 - Transmit list BAR */
706 val = dep->sendrecv_descr_phys_addr[DESCR_TRAN];
707 io_outl(CSR_ADDR(dep, CSR4), val);
709 /* CSR7 - interrupt mask */
710 val = CSR7_TI | CSR7_RI | CSR7_AI;
711 io_outl(CSR_ADDR(dep, CSR7), val);
713 /* CSR6 - operating mode register */
714 val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD |
715 CSR6_PCS | CSR6_SCR | CSR6_TR_00;
716 io_outl(CSR_ADDR(dep, CSR6), val);
719 static void de_start(const dpeth_t *dep){
720 u32_t val;
721 val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR;
722 io_outl(CSR_ADDR(dep, CSR6), val);
725 static void de_setup_frame(const dpeth_t *dep){
726 int i;
727 u32_t val;
729 /* this is not perfect... we assume pass all multicast and only
730 filter non-multicast frames */
731 dep->descr[DESCR_TRAN][0].buf1[0] = 0xFF;
732 dep->descr[DESCR_TRAN][0].buf1[1] = 0xFF;
733 dep->descr[DESCR_TRAN][0].buf1[4] = 0xFF;
734 dep->descr[DESCR_TRAN][0].buf1[5] = 0xFF;
735 dep->descr[DESCR_TRAN][0].buf1[8] = 0xFF;
736 dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF;
737 for(i=1;i<16;i++){
738 memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12);
739 dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0];
740 dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1];
741 dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2];
742 dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3];
743 dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4];
744 dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5];
747 dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN;
748 dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET |
749 DE_SETUP_FRAME_SIZE | DES1_IC;
751 /* start transmit process to process setup frame */
752 val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST;
753 io_outl(CSR_ADDR(dep, CSR6), val);
754 io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
756 return;
759 static int de_calc_iov_size(iovec_dat_s_t * iovp){
760 int size, ix;
761 size = ix = 0;
764 size += iovp->iod_iovec[ix].iov_size;
765 if (++ix >= IOVEC_NR) {
766 de_next_iov(iovp);
767 ix = 0;
769 } while (ix < iovp->iod_iovec_s);
770 return size;
773 static void de_get_userdata_s(int user_proc, cp_grant_id_t grant,
774 vir_bytes offset, int count, void *loc_addr){
775 int rc;
776 vir_bytes len;
778 len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
779 rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len);
780 if (rc != OK)
781 panic(str_CopyErrMsg, rc);
782 return;
785 static void de_next_iov(iovec_dat_s_t * iovp){
787 iovp->iod_iovec_s -= IOVEC_NR;
788 iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
789 de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
790 iovp->iod_iovec_s, iovp->iod_iovec);
791 return;
794 static void do_vwrite_s(const message * mp, int from_int){
795 static u8_t setupDone = 0;
796 int size, r, bytes, ix, totalsize;
797 dpeth_t *dep;
798 iovec_dat_s_t *iovp = NULL;
799 de_loc_descr_t *descr = NULL;
800 u8_t *buffer = NULL;
802 dep = &de_state;
804 dep->de_client = mp->m_source;
806 if (dep->de_mode == DEM_ENABLED) {
808 if (!from_int && (dep->de_flags & DEF_SENDING))
809 panic(str_BusyErrMsg);
811 descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]];
813 if(( descr->descr->des[DES0] & DES0_OWN)!=0)
814 goto suspend;
816 if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){
817 dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0;
818 setupDone=1;
821 buffer = descr->buf1;
822 iovp = &dep->de_write_iovec;
823 iovp->iod_proc_nr = mp->m_source;
824 de_get_userdata_s(mp->m_source, mp->DL_GRANT, 0,
825 mp->DL_COUNT, iovp->iod_iovec);
826 iovp->iod_iovec_s = mp->DL_COUNT;
827 iovp->iod_grant = (cp_grant_id_t) mp->DL_GRANT;
828 iovp->iod_iovec_offset = 0;
829 totalsize = size = de_calc_iov_size(iovp);
830 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
831 panic(str_SizeErrMsg, size);
833 dep->bytes_tx += size;
834 dep->de_stat.ets_packetT++;
836 ix=0;
837 do {
838 bytes = iovp->iod_iovec[ix].iov_size;
839 if (bytes >= size)
840 bytes = size;
842 r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
843 0, (vir_bytes)buffer, bytes);
844 if (r != OK)
845 panic(str_CopyErrMsg, r);
846 buffer += bytes;
848 if (++ix >= IOVEC_NR) {
849 de_next_iov(iovp);
850 ix = 0;
852 } while ((size -= bytes) > 0);
854 descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) |
855 DES1_FS | DES1_LS | DES1_IC | totalsize;
856 descr->descr->des[DES0] = DES0_OWN;
858 dep->cur_descr[DESCR_TRAN]++;
859 if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR)
860 dep->cur_descr[DESCR_TRAN] = 0;
862 io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF);
865 dep->de_flags |= DEF_ACK_SEND;
866 if(from_int){
867 dep->de_flags &= NOT(DEF_SENDING);
868 return;
870 do_reply(dep);
871 return;
873 suspend:
874 if(from_int)
875 panic("should not happen: %d", 0);
877 dep->de_stat.ets_transDef++;
878 dep->de_flags |= DEF_SENDING;
879 dep->de_stat.ets_transDef++;
880 dep->tx_return_msg = *mp;
881 do_reply(dep);
884 static void warning(const char *type, int err){
885 printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err);
886 return;
889 static u32_t io_inl(u16_t port){
890 u32_t value;
891 int rc;
892 if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc);
893 return value;
896 static void io_outl(u16_t port, u32_t value){
897 int rc;
898 if ((rc = sys_outl(port, value)) != OK) warning("outl", rc);
899 return;