]> Zhao Yanbai Git Server - minix.git/commitdiff
Safecopy support in ethernet drivers.
authorPhilip Homburg <philip@cs.vu.nl>
Mon, 10 Jul 2006 12:43:38 +0000 (12:43 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Mon, 10 Jul 2006 12:43:38 +0000 (12:43 +0000)
15 files changed:
drivers/dp8390/Makefile
drivers/dp8390/dp8390.c
drivers/dp8390/dp8390.h
drivers/dpeth/3c509.c
drivers/dpeth/8390.c
drivers/dpeth/Makefile
drivers/dpeth/devio.c
drivers/dpeth/dp.c
drivers/dpeth/dp.h
drivers/dpeth/netbuff.c
drivers/fxp/Makefile
drivers/fxp/fxp.c
drivers/lance/lance.c
drivers/lance/lance.h
drivers/rtl8139/rtl8139.c

index b60585fb54c290821696f0a7c6d186ecbd68b87f..7228d212c45d7588b711575317fe98d99dceb38f 100644 (file)
@@ -21,7 +21,7 @@ OBJ = 3c503.o dp8390.o ne2000.o rtl8029.o wdeth.o
 all build:     $(DRIVER)
 $(DRIVER):     $(OBJ) 
        $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
-       install -S 4096 $(DRIVER)
+       install -S 32k $(DRIVER)
 
 # install with other drivers
 install:       /usr/sbin/$(DRIVER)
index dc587b3172d67e7f3f1241b4b190ef5286e80df0..fdf636fcdf0110e723b53b3002fd2eea51a8ca00 100644 (file)
@@ -6,24 +6,30 @@
  *
  * The valid messages and their parameters are:
  *
- *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
- * |------------+----------+---------+----------+---------+---------|
- * | HARDINT   |          |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READ   | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READV  | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_INIT   | port nr  | proc nr | mode     |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_GETSTAT        | port nr  | proc nr |          |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_STOP   | port_nr  |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR   DL_GRANT
+ * |------------+----------+---------+----------+---------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV_S| port nr  | proc nr | count    | mode    |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV_S        | port nr  | proc nr | count    |         |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_CONF   | port nr  | proc nr |          | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * |DL_GETSTAT_S| port nr  | proc nr |          |         |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
  *
  * The messages sent are:
  *
@@ -34,7 +40,7 @@
  *
  *   m_type       m3_i1     m3_i2       m3_ca1
  * |-------------+---------+-----------+---------------|
- * |DL_INIT_REPLY| port nr | last port | ethernet addr |
+ * |DL_CONF_REPLY| port nr | last port | ethernet addr |
  * |-------------+---------+-----------+---------------|
  *
  * Created:    before Dec 28, 1992 by Philip Homburg <philip@f-mnx.phicoh.com>
@@ -53,6 +59,7 @@
 #include <net/hton.h>
 #include <net/gen/ether.h>
 #include <net/gen/eth_io.h>
+#include <sys/vm.h>
 #include "assert.h"
 
 #include "local.h"
@@ -108,10 +115,13 @@ _PROTOTYPE( static void pci_conf, (void)                          );
 #endif
 _PROTOTYPE( static void do_vwrite, (message *mp, int from_int,
                                                        int vectored)   );
+_PROTOTYPE( static void do_vwrite_s, (message *mp, int from_int)       );
 _PROTOTYPE( static void do_vread, (message *mp, int vectored)          );
+_PROTOTYPE( static void do_vread_s, (message *mp)                      );
 _PROTOTYPE( static void do_init, (message *mp)                         );
 _PROTOTYPE( static void do_int, (dpeth_t *dep)                         );
 _PROTOTYPE( static void do_getstat, (message *mp)                      );
+_PROTOTYPE( static void do_getstat_s, (message *mp)                    );
 _PROTOTYPE( static void do_getname, (message *mp)                      );
 _PROTOTYPE( static void do_stop, (message *mp)                         );
 _PROTOTYPE( static void dp_init, (dpeth_t *dep)                                );
@@ -130,30 +140,54 @@ _PROTOTYPE( static void dp_pio16_getblock, (dpeth_t *dep, int page,
                                size_t offset, size_t size, void *dst)  );
 _PROTOTYPE( static int dp_pkt2user, (dpeth_t *dep, int page,
                                                        int length)     );
+_PROTOTYPE( static int dp_pkt2user_s, (dpeth_t *dep, int page,
+                                                       int length)     );
 _PROTOTYPE( static void dp_user2nic, (dpeth_t *dep, iovec_dat_t *iovp, 
                vir_bytes offset, int nic_addr, vir_bytes count)        );
+_PROTOTYPE( static void dp_user2nic_s, (dpeth_t *dep, iovec_dat_s_t *iovp, 
+               vir_bytes offset, int nic_addr, vir_bytes count)        );
 _PROTOTYPE( static void dp_pio8_user2nic, (dpeth_t *dep,
                                iovec_dat_t *iovp, vir_bytes offset,
                                int nic_addr, vir_bytes count)          );
+_PROTOTYPE( static void dp_pio8_user2nic_s, (dpeth_t *dep,
+                               iovec_dat_s_t *iovp, vir_bytes offset,
+                               int nic_addr, vir_bytes count)          );
 _PROTOTYPE( static void dp_pio16_user2nic, (dpeth_t *dep,
                                iovec_dat_t *iovp, vir_bytes offset,
                                int nic_addr, vir_bytes count)          );
+_PROTOTYPE( static void dp_pio16_user2nic_s, (dpeth_t *dep,
+                               iovec_dat_s_t *iovp, vir_bytes offset,
+                               int nic_addr, vir_bytes count)          );
 _PROTOTYPE( static void dp_nic2user, (dpeth_t *dep, int nic_addr, 
                iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)   );
+_PROTOTYPE( static void dp_nic2user_s, (dpeth_t *dep, int nic_addr, 
+               iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count) );
 _PROTOTYPE( static void dp_pio8_nic2user, (dpeth_t *dep, int nic_addr, 
                iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)   );
+_PROTOTYPE( static void dp_pio8_nic2user_s, (dpeth_t *dep, int nic_addr, 
+               iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count) );
 _PROTOTYPE( static void dp_pio16_nic2user, (dpeth_t *dep, int nic_addr, 
                iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)   );
+_PROTOTYPE( static void dp_pio16_nic2user_s, (dpeth_t *dep, int nic_addr, 
+               iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count) );
 _PROTOTYPE( static void dp_next_iovec, (iovec_dat_t *iovp)             );
+_PROTOTYPE( static void dp_next_iovec_s, (iovec_dat_s_t *iovp)         );
 _PROTOTYPE( static void conf_hw, (dpeth_t *dep)                                );
 _PROTOTYPE( static void update_conf, (dpeth_t *dep, dp_conf_t *dcp)    );
+_PROTOTYPE( static void map_hw_buffer, (dpeth_t *dep)                  );
 _PROTOTYPE( static int calc_iovec_size, (iovec_dat_t *iovp)            );
+_PROTOTYPE( static int calc_iovec_size_s, (iovec_dat_s_t *iovp)                );
 _PROTOTYPE( static void reply, (dpeth_t *dep, int err, int may_block)  );
 _PROTOTYPE( static void mess_reply, (message *req, message *reply)     );
 _PROTOTYPE( static void get_userdata, (int user_proc,
                vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
+_PROTOTYPE( static void get_userdata_s, (int user_proc,
+               cp_grant_id_t grant, vir_bytes offset, vir_bytes count,
+               void *loc_addr) );
 _PROTOTYPE( static void put_userdata, (int user_proc,
                vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
+_PROTOTYPE( static void put_userdata_s, (int user_proc,
+               cp_grant_id_t grant, size_t count, void *loc_addr)      );
 _PROTOTYPE( static void insb, (port_t port, void *buf, size_t size)                            );
 _PROTOTYPE( static void insw, (port_t port, void *buf, size_t size)                            );
 _PROTOTYPE( static void do_vir_insb, (port_t port, int proc,
@@ -209,10 +243,13 @@ int main(int argc, char *argv[])
                case DEV_PING:  notify(m.m_source);             continue;
                case DL_WRITE:  do_vwrite(&m, FALSE, FALSE);    break;
                case DL_WRITEV: do_vwrite(&m, FALSE, TRUE);     break;
+               case DL_WRITEV_S: do_vwrite_s(&m, FALSE);       break;
                case DL_READ:   do_vread(&m, FALSE);            break;
                case DL_READV:  do_vread(&m, TRUE);             break;
-               case DL_INIT:   do_init(&m);                    break;
+               case DL_READV_S: do_vread_s(&m);                break;
+               case DL_CONF:   do_init(&m);                    break;
                case DL_GETSTAT: do_getstat(&m);                break;
+               case DL_GETSTAT_S: do_getstat_s(&m);            break;
                case DL_GETNAME: do_getname(&m);                break;
                case DL_STOP:   do_stop(&m);                    break;
                case HARD_INT:
@@ -476,6 +513,96 @@ int vectored;
        assert(dep->de_flags & DEF_ENABLED);
 }
 
+/*===========================================================================*
+ *                             do_vwrite_s                                  *
+ *===========================================================================*/
+static void do_vwrite_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       int port, count, size;
+       int sendq_head;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       dep->de_client= mp->DL_PROC;
+
+       if (dep->de_mode == DEM_SINK)
+       {
+               assert(!from_int);
+               dep->de_flags |= DEF_PACK_SEND;
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+       if (dep->de_flags & DEF_SEND_AVAIL)
+               panic("", "dp8390: send already in progress", NO_NUM);
+
+       sendq_head= dep->de_sendq_head;
+       if (dep->de_sendq[sendq_head].sq_filled)
+       {
+               if (from_int)
+                       panic("", "dp8390: should not be sending\n", NO_NUM);
+               dep->de_sendmsg= *mp;
+               dep->de_flags |= DEF_SEND_AVAIL;
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(!(dep->de_flags & DEF_PACK_SEND));
+
+       get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
+               (count > IOVEC_NR ? IOVEC_NR : count) *
+               sizeof(dep->de_write_iovec_s.iod_iovec[0]),
+               dep->de_write_iovec_s.iod_iovec);
+       dep->de_write_iovec_s.iod_iovec_s = count;
+       dep->de_write_iovec_s.iod_proc_nr = mp->DL_PROC;
+       dep->de_write_iovec_s.iod_grant = mp->DL_GRANT;
+       dep->de_write_iovec_s.iod_iovec_offset = 0;
+
+       dep->de_tmp_iovec_s = dep->de_write_iovec_s;
+       size = calc_iovec_size_s(&dep->de_tmp_iovec_s);
+
+       if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
+       {
+               panic("", "dp8390: invalid packet size", size);
+       }
+       (dep->de_user2nicf_s)(dep, &dep->de_write_iovec_s, 0,
+               dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE,
+               size);
+       dep->de_sendq[sendq_head].sq_filled= TRUE;
+       if (dep->de_sendq_tail == sendq_head)
+       {
+               outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
+               outb_reg0(dep, DP_TBCR1, size >> 8);
+               outb_reg0(dep, DP_TBCR0, size & 0xff);
+               outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);/* there it goes.. */
+       }
+       else
+               dep->de_sendq[sendq_head].sq_size= size;
+       
+       if (++sendq_head == dep->de_sendq_nr)
+               sendq_head= 0;
+       assert(sendq_head < SENDQ_NR);
+       dep->de_sendq_head= sendq_head;
+
+       dep->de_flags |= DEF_PACK_SEND;
+
+       /* If the interrupt handler called, don't send a reply. The reply
+        * will be sent after all interrupts are handled. 
+        */
+       if (from_int)
+               return;
+       reply(dep, OK, FALSE);
+
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+}
+
 /*===========================================================================*
  *                             do_vread                                     *
  *===========================================================================*/
@@ -504,6 +631,8 @@ int vectored;
        if(dep->de_flags & DEF_READING)
                panic("", "dp8390: read already in progress", NO_NUM);
 
+       dep->de_safecopy_read= 0;
+
        if (vectored)
        {
                get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
@@ -544,6 +673,64 @@ int vectored;
        reply(dep, OK, FALSE);
 }
 
+/*===========================================================================*
+ *                             do_vread_s                                   *
+ *===========================================================================*/
+static void do_vread_s(mp)
+message *mp;
+{
+       int port, count;
+       int size;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       dep->de_client= mp->DL_PROC;
+       if (dep->de_mode == DEM_SINK)
+       {
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+
+       dep->de_safecopy_read= 1;
+
+       if(dep->de_flags & DEF_READING)
+               panic("", "dp8390: read already in progress", NO_NUM);
+
+       get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
+               (count > IOVEC_NR ? IOVEC_NR : count) *
+               sizeof(dep->de_read_iovec_s.iod_iovec[0]),
+               dep->de_read_iovec_s.iod_iovec);
+       dep->de_read_iovec_s.iod_iovec_s = count;
+       dep->de_read_iovec_s.iod_proc_nr = mp->DL_PROC;
+       dep->de_read_iovec_s.iod_grant = mp->DL_GRANT;
+       dep->de_read_iovec_s.iod_iovec_offset = 0;
+
+       dep->de_tmp_iovec_s = dep->de_read_iovec_s;
+       size= calc_iovec_size_s(&dep->de_tmp_iovec_s);
+
+       if (size < ETH_MAX_PACK_SIZE_TAGGED)
+               panic("", "dp8390: wrong packet size", size);
+       dep->de_flags |= DEF_READING;
+
+       dp_recv(dep);
+
+       if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) ==
+               (DEF_READING|DEF_STOPPED))
+       {
+               /* The chip is stopped, and all arrived packets are 
+                * delivered.
+                */
+               dp_reset(dep);
+       }
+       reply(dep, OK, FALSE);
+}
+
 /*===========================================================================*
  *                             do_init                                      *
  *===========================================================================*/
@@ -561,7 +748,7 @@ message *mp;
        port = mp->DL_PORT;
        if (port < 0 || port >= DE_PORT_NR)
        {
-               reply_mess.m_type= DL_INIT_REPLY;
+               reply_mess.m_type= DL_CONF_REPLY;
                reply_mess.m3_i1= ENXIO;
                mess_reply(mp, &reply_mess);
                return;
@@ -574,7 +761,7 @@ message *mp;
                if (dep->de_mode == DEM_DISABLED)
                {
                        /* Probe failed, or the device is configured off. */
-                       reply_mess.m_type= DL_INIT_REPLY;
+                       reply_mess.m_type= DL_CONF_REPLY;
                        reply_mess.m3_i1= ENXIO;
                        mess_reply(mp, &reply_mess);
                        return;
@@ -588,7 +775,7 @@ message *mp;
                strncpy((char *) dep->de_address.ea_addr, "ZDP", 6);
                dep->de_address.ea_addr[5] = port;
                dp_confaddr(dep);
-               reply_mess.m_type = DL_INIT_REPLY;
+               reply_mess.m_type = DL_CONF_REPLY;
                reply_mess.m3_i1 = mp->DL_PORT;
                reply_mess.m3_i2 = DE_PORT_NR;
                *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
@@ -610,7 +797,7 @@ message *mp;
        dep->de_client = mp->m_source;
        dp_reinit(dep);
 
-       reply_mess.m_type = DL_INIT_REPLY;
+       reply_mess.m_type = DL_CONF_REPLY;
        reply_mess.m3_i1 = mp->DL_PORT;
        reply_mess.m3_i2 = DE_PORT_NR;
        *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
@@ -661,6 +848,39 @@ message *mp;
        reply(dep, OK, FALSE);
 }
 
+/*===========================================================================*
+ *                             do_getstat_s                                 *
+ *===========================================================================*/
+static void do_getstat_s(mp)
+message *mp;
+{
+       int port;
+       dpeth_t *dep;
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= DE_PORT_NR)
+               panic("", "dp8390: illegal port", port);
+       dep= &de_table[port];
+       dep->de_client= mp->DL_PROC;
+       if (dep->de_mode == DEM_SINK)
+       {
+               put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
+                       (vir_bytes) sizeof(dep->de_stat), &dep->de_stat);
+               reply(dep, OK, FALSE);
+               return;
+       }
+       assert(dep->de_mode == DEM_ENABLED);
+       assert(dep->de_flags & DEF_ENABLED);
+
+       dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
+       dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1);
+       dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2);
+
+       put_userdata_s(mp->DL_PROC, mp->DL_GRANT,
+               sizeof(dep->de_stat), &dep->de_stat);
+       reply(dep, OK, FALSE);
+}
+
 /*===========================================================================*
  *                             do_getname                                   *
  *===========================================================================*/
@@ -727,6 +947,9 @@ dpeth_t *dep;
                                                        i < 5 ? ':' : '\n');
        }
 
+       /* Map buffer */
+       map_hw_buffer(dep);
+
        /* Initialization of the dp8390 following the mandatory procedure
         * in reference manual ("DP8390D/NS32490D NIC Network Interface
         * Controller", National Semiconductor, July 1995, Page 29).
@@ -799,19 +1022,25 @@ dpeth_t *dep;
        if (!dep->de_prog_IO)
        {
                dep->de_user2nicf= dp_user2nic;
+               dep->de_user2nicf_s= dp_user2nic_s;
                dep->de_nic2userf= dp_nic2user;
+               dep->de_nic2userf_s= dp_nic2user_s;
                dep->de_getblockf= dp_getblock;
        }
        else if (dep->de_16bit)
        {
                dep->de_user2nicf= dp_pio16_user2nic;
+               dep->de_user2nicf_s= dp_pio16_user2nic_s;
                dep->de_nic2userf= dp_pio16_nic2user;
+               dep->de_nic2userf_s= dp_pio16_nic2user_s;
                dep->de_getblockf= dp_pio16_getblock;
        }
        else
        {
                dep->de_user2nicf= dp_pio8_user2nic;
+               dep->de_user2nicf_s= dp_pio8_user2nic_s;
                dep->de_nic2userf= dp_pio8_nic2user;
+               dep->de_nic2userf_s= dp_pio8_nic2user_s;
                dep->de_getblockf= dp_pio8_getblock;
        }
 
@@ -1130,7 +1359,10 @@ dpeth_t *dep;
                else if ((header.dr_status & RSR_PRX) &&
                                           (dep->de_flags & DEF_ENABLED))
                {
-                       r = dp_pkt2user(dep, pageno, length);
+                       if (dep->de_safecopy_read)
+                               r = dp_pkt2user_s(dep, pageno, length);
+                       else
+                               r = dp_pkt2user(dep, pageno, length);
                        if (r != OK)
                                return;
 
@@ -1161,8 +1393,9 @@ dpeth_t *dep;
        {
        case DL_WRITE:  do_vwrite(&dep->de_sendmsg, TRUE, FALSE);       break;
        case DL_WRITEV: do_vwrite(&dep->de_sendmsg, TRUE, TRUE);        break;
+       case DL_WRITEV_S: do_vwrite_s(&dep->de_sendmsg, TRUE);  break;
        default:
-               panic("", "dp8390: wrong type:", dep->de_sendmsg.m_type);
+               panic("", "dp8390: wrong type", dep->de_sendmsg.m_type);
                break;
        }
 }
@@ -1181,11 +1414,7 @@ void *dst;
 
        offset = page * DP_PAGESIZE + offset;
 
-       r = sys_vircopy(SELF, BIOS_SEG, dep->de_linmem + offset,
-               SELF, D, (vir_bytes)dst, size);
-
-       if (r != OK)
-               panic("DP8390", "dp_getblock: sys_vircopy failed", r);
+       memcpy(dst, dep->de_locmem + offset, size);
 }
 
 /*===========================================================================*
@@ -1267,6 +1496,44 @@ int page, length;
        return OK;
 }
 
+/*===========================================================================*
+ *                             dp_pkt2user_s                                *
+ *===========================================================================*/
+static int dp_pkt2user_s(dep, page, length)
+dpeth_t *dep;
+int page, length;
+{
+       int last, count;
+
+       if (!(dep->de_flags & DEF_READING))
+               return EGENERIC;
+
+       last = page + (length - 1) / DP_PAGESIZE;
+       if (last >= dep->de_stoppage)
+       {
+               count = (dep->de_stoppage - page) * DP_PAGESIZE -
+                       sizeof(dp_rcvhdr_t);
+
+               /* Save read_iovec since we need it twice. */
+               dep->de_tmp_iovec_s = dep->de_read_iovec_s;
+               (dep->de_nic2userf_s)(dep, page * DP_PAGESIZE +
+                       sizeof(dp_rcvhdr_t), &dep->de_tmp_iovec_s, 0, count);
+               (dep->de_nic2userf_s)(dep, dep->de_startpage * DP_PAGESIZE, 
+                               &dep->de_read_iovec_s, count, length - count);
+       }
+       else
+       {
+               (dep->de_nic2userf_s)(dep, page * DP_PAGESIZE +
+                       sizeof(dp_rcvhdr_t), &dep->de_read_iovec_s, 0, length);
+       }
+
+       dep->de_read_s = length;
+       dep->de_flags |= DEF_PACK_RECV;
+       dep->de_flags &= ~DEF_READING;
+
+       return OK;
+}
+
 /*===========================================================================*
  *                             dp_user2nic                                  *
  *===========================================================================*/
@@ -1280,7 +1547,7 @@ vir_bytes count;
        vir_bytes vir_hw, vir_user;
        int bytes, i, r;
 
-       vir_hw = dep->de_linmem + nic_addr;
+       vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
 
        i= 0;
        while (count > 0)
@@ -1304,7 +1571,7 @@ vir_bytes count;
 
                r= sys_vircopy(iovp->iod_proc_nr, D,
                        iovp->iod_iovec[i].iov_addr + offset,
-                       SELF, BIOS_SEG, vir_hw, bytes);
+                       SELF, D, vir_hw, bytes);
                if (r != OK)
                        panic("DP8390", "dp_user2nic: sys_vircopy failed", r);
 
@@ -1315,6 +1582,57 @@ vir_bytes count;
        assert(count == 0);
 }
 
+/*===========================================================================*
+ *                             dp_user2nic_s                                *
+ *===========================================================================*/
+static void dp_user2nic_s(dep, iovp, offset, nic_addr, count)
+dpeth_t *dep;
+iovec_dat_s_t *iovp;
+vir_bytes offset;
+int nic_addr;
+vir_bytes count;
+{
+       vir_bytes vir_hw, vir_user;
+       int bytes, i, r;
+
+       vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec_s(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               r= sys_safecopyfrom(iovp->iod_proc_nr,
+                       iovp->iod_iovec[i].iov_grant, offset,
+                       vir_hw, bytes, D);
+               if (r != OK)
+               {
+                       panic("DP8390",
+                               "dp_user2nic_s: sys_safecopyfrom failed", r);
+               }
+
+               count -= bytes;
+               vir_hw += bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+}
+
 /*===========================================================================*
  *                             dp_pio8_user2nic                             *
  *===========================================================================*/
@@ -1375,27 +1693,22 @@ vir_bytes count;
 }
 
 /*===========================================================================*
- *                             dp_pio16_user2nic                            *
+ *                             dp_pio8_user2nic_s                           *
  *===========================================================================*/
-static void dp_pio16_user2nic(dep, iovp, offset, nic_addr, count)
+static void dp_pio8_user2nic_s(dep, iovp, offset, nic_addr, count)
 dpeth_t *dep;
-iovec_dat_t *iovp;
+iovec_dat_s_t *iovp;
 vir_bytes offset;
 int nic_addr;
 vir_bytes count;
 {
-       vir_bytes vir_user;
-       vir_bytes ecount;
-       int i, r, bytes, user_proc;
-       u8_t two_bytes[2];
-       int odd_byte;
-
-       ecount= (count+1) & ~1;
-       odd_byte= 0;
+       phys_bytes phys_user;
+       int bytes, i, r;
 
        outb_reg0(dep, DP_ISR, ISR_RDC);
-       outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
-       outb_reg0(dep, DP_RBCR1, ecount >> 8);
+
+       outb_reg0(dep, DP_RBCR0, count & 0xFF);
+       outb_reg0(dep, DP_RBCR1, count >> 8);
        outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
        outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
        outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
@@ -1405,7 +1718,7 @@ vir_bytes count;
        {
                if (i >= IOVEC_NR)
                {
-                       dp_next_iovec(iovp);
+                       dp_next_iovec_s(iovp);
                        i= 0;
                        continue;
                }
@@ -1420,13 +1733,83 @@ vir_bytes count;
                if (bytes > count)
                        bytes = count;
 
-               user_proc= iovp->iod_proc_nr;
-               vir_user= iovp->iod_iovec[i].iov_addr + offset;
-               if (odd_byte)
+               r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
+                       iovp->iod_iovec[i].iov_grant, offset, bytes);
+               if (r != OK)
                {
-                       r= sys_vircopy(user_proc, D, vir_user, 
-                               SELF, D, (vir_bytes)&two_bytes[1], 1);
-                       if (r != OK)
+                       panic(__FILE__,
+                               "dp_pio8_user2nic_s: sys_safe_outsb failed",
+                               r);
+               }
+               count -= bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+
+       for (i= 0; i<100; i++)
+       {
+               if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+                       break;
+       }
+       if (i == 100)
+       {
+               panic("", "dp8390: remote dma failed to complete", NO_NUM);
+       }
+}
+
+/*===========================================================================*
+ *                             dp_pio16_user2nic                            *
+ *===========================================================================*/
+static void dp_pio16_user2nic(dep, iovp, offset, nic_addr, count)
+dpeth_t *dep;
+iovec_dat_t *iovp;
+vir_bytes offset;
+int nic_addr;
+vir_bytes count;
+{
+       vir_bytes vir_user;
+       vir_bytes ecount;
+       int i, r, bytes, user_proc;
+       u8_t two_bytes[2];
+       int odd_byte;
+
+       ecount= (count+1) & ~1;
+       odd_byte= 0;
+
+       outb_reg0(dep, DP_ISR, ISR_RDC);
+       outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
+       outb_reg0(dep, DP_RBCR1, ecount >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               user_proc= iovp->iod_proc_nr;
+               vir_user= iovp->iod_iovec[i].iov_addr + offset;
+               if (odd_byte)
+               {
+                       r= sys_vircopy(user_proc, D, vir_user, 
+                               SELF, D, (vir_bytes)&two_bytes[1], 1);
+                       if (r != OK)
                        {
                                panic("DP8390",
                                        "dp_pio16_user2nic: sys_vircopy failed",
@@ -1485,6 +1868,120 @@ vir_bytes count;
        }
 }
 
+/*===========================================================================*
+ *                             dp_pio16_user2nic_s                          *
+ *===========================================================================*/
+static void dp_pio16_user2nic_s(dep, iovp, offset, nic_addr, count)
+dpeth_t *dep;
+iovec_dat_s_t *iovp;
+vir_bytes offset;
+int nic_addr;
+vir_bytes count;
+{
+       vir_bytes ecount;
+       cp_grant_id_t gid;
+       int i, r, bytes, user_proc;
+       u8_t two_bytes[2];
+       int odd_byte;
+
+       ecount= (count+1) & ~1;
+       odd_byte= 0;
+
+       outb_reg0(dep, DP_ISR, ISR_RDC);
+       outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
+       outb_reg0(dep, DP_RBCR1, ecount >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec_s(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               user_proc= iovp->iod_proc_nr;
+               gid= iovp->iod_iovec[i].iov_grant;
+               if (odd_byte)
+               {
+                       r= sys_safecopyfrom(user_proc, gid, offset, 
+                               (vir_bytes)&two_bytes[1], 1, D);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                               "dp_pio16_user2nic: sys_safecopyfrom failed",
+                                       r);
+                       }
+                       outw(dep->de_data_port, *(u16_t *)two_bytes);
+                       count--;
+                       offset++;
+                       bytes--;
+                       odd_byte= 0;
+                       if (!bytes)
+                               continue;
+               }
+               ecount= bytes & ~1;
+               if (ecount != 0)
+               {
+                       r= sys_safe_outsw(dep->de_data_port, user_proc,
+                               gid, offset, ecount);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                               "dp_pio16_user2nic: sys_safe_outsw failed",
+                                       r);
+                       }
+                       count -= ecount;
+                       offset += ecount;
+                       bytes -= ecount;
+               }
+               if (bytes)
+               {
+                       assert(bytes == 1);
+                       r= sys_safecopyfrom(user_proc, gid, offset,
+                               (vir_bytes)&two_bytes[0], 1, D);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                               "dp_pio16_user2nic: sys_safecopyfrom failed",
+                                       r);
+                       }
+                       count--;
+                       offset++;
+                       bytes--;
+                       odd_byte= 1;
+               }
+       }
+       assert(count == 0);
+
+       if (odd_byte)
+               outw(dep->de_data_port, *(u16_t *)two_bytes);
+
+       for (i= 0; i<100; i++)
+       {
+               if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+                       break;
+       }
+       if (i == 100)
+       {
+               panic("", "dp8390: remote dma failed to complete", NO_NUM);
+       }
+}
+
 /*===========================================================================*
  *                             dp_nic2user                                  *
  *===========================================================================*/
@@ -1498,7 +1995,7 @@ vir_bytes count;
        vir_bytes vir_hw, vir_user;
        int bytes, i, r;
 
-       vir_hw = dep->de_linmem + nic_addr;
+       vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
 
        i= 0;
        while (count > 0)
@@ -1520,7 +2017,7 @@ vir_bytes count;
                if (bytes > count)
                        bytes = count;
 
-               r= sys_vircopy(SELF, BIOS_SEG, vir_hw,
+               r= sys_vircopy(SELF, D, vir_hw,
                        iovp->iod_proc_nr, D,
                        iovp->iod_iovec[i].iov_addr + offset, bytes);
                if (r != OK)
@@ -1533,6 +2030,55 @@ vir_bytes count;
        assert(count == 0);
 }
 
+/*===========================================================================*
+ *                             dp_nic2user_s                                *
+ *===========================================================================*/
+static void dp_nic2user_s(dep, nic_addr, iovp, offset, count)
+dpeth_t *dep;
+int nic_addr;
+iovec_dat_s_t *iovp;
+vir_bytes offset;
+vir_bytes count;
+{
+       vir_bytes vir_hw, vir_user;
+       int bytes, i, r;
+
+       vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec_s(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               r= sys_safecopyto(iovp->iod_proc_nr,
+                       iovp->iod_iovec[i].iov_grant, offset,
+                       vir_hw, bytes, D);
+               if (r != OK)
+                       panic("DP8390",
+                               "dp_nic2user_s: sys_safecopyto failed", r);
+
+               count -= bytes;
+               vir_hw += bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+}
+
 /*===========================================================================*
  *                             dp_pio8_nic2user                             *
  *===========================================================================*/
@@ -1580,6 +2126,58 @@ vir_bytes count;
        assert(count == 0);
 }
 
+/*===========================================================================*
+ *                             dp_pio8_nic2user_s                           *
+ *===========================================================================*/
+static void dp_pio8_nic2user_s(dep, nic_addr, iovp, offset, count)
+dpeth_t *dep;
+int nic_addr;
+iovec_dat_s_t *iovp;
+vir_bytes offset;
+vir_bytes count;
+{
+       phys_bytes phys_user;
+       int bytes, i, r;
+
+       outb_reg0(dep, DP_RBCR0, count & 0xFF);
+       outb_reg0(dep, DP_RBCR1, count >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec_s(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
+                       iovp->iod_iovec[i].iov_grant, offset, bytes);
+               if (r != OK)
+               {
+                       panic(__FILE__,
+                               "dp_pio8_nic2user_s: sys_safe_insb failed", r);
+               }
+               count -= bytes;
+               offset += bytes;
+       }
+       assert(count == 0);
+}
+
 /*===========================================================================*
  *                             dp_pio16_nic2user                            *
  *===========================================================================*/
@@ -1678,7 +2276,107 @@ vir_bytes count;
 }
 
 /*===========================================================================*
- *                             dp_next_iovec                                        *
+ *                             dp_pio16_nic2user_s                          *
+ *===========================================================================*/
+static void dp_pio16_nic2user_s(dep, nic_addr, iovp, offset, count)
+dpeth_t *dep;
+int nic_addr;
+iovec_dat_s_t *iovp;
+vir_bytes offset;
+vir_bytes count;
+{
+       vir_bytes ecount;
+       cp_grant_id_t gid;
+       int i, r, bytes, user_proc;
+       u8_t two_bytes[2];
+       int odd_byte;
+
+       ecount= (count+1) & ~1;
+       odd_byte= 0;
+
+       outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
+       outb_reg0(dep, DP_RBCR1, ecount >> 8);
+       outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
+       outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+       outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+
+       i= 0;
+       while (count > 0)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec_s(iovp);
+                       i= 0;
+                       continue;
+               }
+               assert(i < iovp->iod_iovec_s);
+               if (offset >= iovp->iod_iovec[i].iov_size)
+               {
+                       offset -= iovp->iod_iovec[i].iov_size;
+                       i++;
+                       continue;
+               }
+               bytes = iovp->iod_iovec[i].iov_size - offset;
+               if (bytes > count)
+                       bytes = count;
+
+               user_proc= iovp->iod_proc_nr;
+               gid= iovp->iod_iovec[i].iov_grant;
+               if (odd_byte)
+               {
+                       r= sys_safecopyto(user_proc, gid, offset,
+                               (vir_bytes)&two_bytes[1], 1, D);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                               "dp_pio16_nic2user: sys_safecopyto failed",
+                                       r);
+                       }
+                       count--;
+                       offset++;
+                       bytes--;
+                       odd_byte= 0;
+                       if (!bytes)
+                               continue;
+               }
+               ecount= bytes & ~1;
+               if (ecount != 0)
+               {
+                       r= sys_safe_insw(dep->de_data_port, user_proc, gid,
+                               offset, ecount);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                               "dp_pio16_nic2user: sys_safe_insw failed",
+                                       r);
+                       }
+                       count -= ecount;
+                       offset += ecount;
+                       bytes -= ecount;
+               }
+               if (bytes)
+               {
+                       assert(bytes == 1);
+                       *(u16_t *)two_bytes= inw(dep->de_data_port);
+                       r= sys_safecopyto(user_proc, gid, offset,
+                               (vir_bytes)&two_bytes[0], 1, D);
+                       if (r != OK)
+                       {
+                               panic("DP8390",
+                               "dp_pio16_nic2user: sys_safecopyto failed",
+                                       r);
+                       }
+                       count--;
+                       offset++;
+                       bytes--;
+                       odd_byte= 1;
+               }
+       }
+       assert(count == 0);
+}
+
+/*===========================================================================*
+ *                             dp_next_iovec                                *
  *===========================================================================*/
 static void dp_next_iovec(iovp)
 iovec_dat_t *iovp;
@@ -1694,6 +2392,24 @@ iovec_dat_t *iovp;
                sizeof(iovec_t), iovp->iod_iovec); 
 }
 
+/*===========================================================================*
+ *                             dp_next_iovec_s                              *
+ *===========================================================================*/
+static void dp_next_iovec_s(iovp)
+iovec_dat_s_t *iovp;
+{
+       assert(iovp->iod_iovec_s > IOVEC_NR);
+
+       iovp->iod_iovec_s -= IOVEC_NR;
+
+       iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
+
+       get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant,
+               iovp->iod_iovec_offset, 
+               (iovp->iod_iovec_s > IOVEC_NR ? IOVEC_NR : iovp->iod_iovec_s) *
+               sizeof(iovp->iod_iovec[0]), iovp->iod_iovec); 
+}
+
 /*===========================================================================*
  *                             conf_hw                                      *
  *===========================================================================*/
@@ -1777,6 +2493,43 @@ dp_conf_t *dcp;
        dep->de_ramsize= v;
 }
 
+/*===========================================================================*
+ *                             map_hw_buffer                                *
+ *===========================================================================*/
+static void map_hw_buffer(dep)
+dpeth_t *dep;
+{
+       int r;
+       size_t o, size;
+       char *buf, *abuf;
+
+       if (dep->de_prog_IO)
+       {
+#if 0
+               printf(
+               "map_hw_buffer: programmed I/O, no need to map buffer\n");
+#endif
+               dep->de_locmem = (char *)-dep->de_ramsize; /* trap errors */
+               return;
+       }
+
+       size = dep->de_ramsize + PAGE_SIZE;     /* Add PAGE_SIZE for
+                                                * alignment
+                                                */
+       buf= malloc(size);
+       if (buf == NULL)
+               panic(__FILE__, "map_hw_buffer: cannot malloc size", size);
+       o= PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE);
+       abuf= buf + o;
+       printf("buf at 0x%x, abuf at 0x%x\n", buf, abuf);
+
+       r= sys_vm_map(SELF, 1 /* map */, (vir_bytes)abuf,
+                       dep->de_ramsize, (phys_bytes)dep->de_linmem);
+       if (r != OK)
+               panic(__FILE__, "map_hw_buffer: sys_vm_map failed", r);
+       dep->de_locmem = abuf;
+}
+
 /*===========================================================================*
  *                             calc_iovec_size                              *
  *===========================================================================*/
@@ -1805,6 +2558,34 @@ iovec_dat_t *iovp;
        return size;
 }
 
+/*===========================================================================*
+ *                             calc_iovec_size_s                            *
+ *===========================================================================*/
+static int calc_iovec_size_s(iovp)
+iovec_dat_s_t *iovp;
+{
+       /* Calculate the size of a request. Note that the iovec_dat
+        * structure will be unusable after calc_iovec_size_s.
+        */
+       int size;
+       int i;
+
+       size= 0;
+       i= 0;
+       while (i < iovp->iod_iovec_s)
+       {
+               if (i >= IOVEC_NR)
+               {
+                       dp_next_iovec_s(iovp);
+                       i= 0;
+                       continue;
+               }
+               size += iovp->iod_iovec[i].iov_size;
+               i++;
+       }
+       return size;
+}
+
 /*===========================================================================*
  *                             reply                                        *
  *===========================================================================*/
@@ -1874,6 +2655,24 @@ void *loc_addr;
                panic("DP8390", "get_userdata: sys_vircopy failed", r);
 }
 
+/*===========================================================================*
+ *                             get_userdata_s                               *
+ *===========================================================================*/
+static void get_userdata_s(user_proc, grant, offset, count, loc_addr)
+int user_proc;
+cp_grant_id_t grant;
+vir_bytes offset;
+vir_bytes count;
+void *loc_addr;
+{
+       int r;
+
+       r= sys_safecopyfrom(user_proc, grant, offset,
+               (vir_bytes)loc_addr, count, D);
+       if (r != OK)
+               panic("DP8390", "get_userdata: sys_safecopyfrom failed", r);
+}
+
 /*===========================================================================*
  *                             put_userdata                                 *
  *===========================================================================*/
@@ -1891,6 +2690,23 @@ void *loc_addr;
                panic("DP8390", "put_userdata: sys_vircopy failed", r);
 }
 
+/*===========================================================================*
+ *                             put_userdata_s                               *
+ *===========================================================================*/
+static void put_userdata_s(user_proc, grant, count, loc_addr)
+int user_proc;
+cp_grant_id_t grant;
+size_t count;
+void *loc_addr;
+{
+       int r;
+
+       r= sys_safecopyto(user_proc, grant, 0, (vir_bytes)loc_addr, 
+               count, D);
+       if (r != OK)
+               panic("DP8390", "put_userdata: sys_safecopyto failed", r);
+}
+
 u8_t inb(port_t port)
 {
        int r;
index be889dbf40b1cb5b7c1e42acbda32ebffdad1031..083ddf6305957c6b8018587e86272aff87ee5bed 100644 (file)
@@ -172,14 +172,21 @@ typedef struct dp_rcvhdr
 
 struct dpeth;
 struct iovec_dat;
+struct iovec_dat_s;
 _PROTOTYPE( typedef void (*dp_initf_t), (struct dpeth *dep)            );
 _PROTOTYPE( typedef void (*dp_stopf_t), (struct dpeth *dep)            );
 _PROTOTYPE( typedef void (*dp_user2nicf_t), (struct dpeth *dep,
                        struct iovec_dat *iovp, vir_bytes offset,
                        int nic_addr, vir_bytes count)                  );
+_PROTOTYPE( typedef void (*dp_user2nicf_s_t), (struct dpeth *dep,
+                       struct iovec_dat_s *iovp, vir_bytes offset,
+                       int nic_addr, vir_bytes count)                  );
 _PROTOTYPE( typedef void (*dp_nic2userf_t), (struct dpeth *dep,
                        int nic_addr, struct iovec_dat *iovp,
                        vir_bytes offset, vir_bytes count)              );
+_PROTOTYPE( typedef void (*dp_nic2userf_s_t), (struct dpeth *dep,
+                       int nic_addr, struct iovec_dat_s *iovp,
+                       vir_bytes offset, vir_bytes count)              );
 #if 0
 _PROTOTYPE( typedef void (*dp_getheaderf_t), (struct dpeth *dep,
                        int page, struct dp_rcvhdr *h, u16_t *eth_type) );
@@ -200,6 +207,15 @@ typedef struct iovec_dat
   vir_bytes iod_iovec_addr;
 } iovec_dat_t;
 
+typedef struct iovec_dat_s
+{
+  iovec_s_t iod_iovec[IOVEC_NR];
+  int iod_iovec_s;
+  int iod_proc_nr;
+  cp_grant_id_t iod_grant;
+  vir_bytes iod_iovec_offset;
+} iovec_dat_s_t;
+
 #define SENDQ_NR       2       /* Maximum size of the send queue */
 #define SENDQ_PAGES    6       /* 6 * DP_PAGESIZE >= 1514 bytes */
 
@@ -215,6 +231,7 @@ typedef struct dpeth
         */
        port_t de_base_port;
        phys_bytes de_linmem;
+       char *de_locmem;
        int de_irq;
        int de_int_pending;
        irq_hook_t de_hook;
@@ -261,13 +278,19 @@ typedef struct dpeth
        int de_mode;
        eth_stat_t de_stat;
        iovec_dat_t de_read_iovec;
+       iovec_dat_s_t de_read_iovec_s;
+       int de_safecopy_read;
        iovec_dat_t de_write_iovec;
+       iovec_dat_s_t de_write_iovec_s;
        iovec_dat_t de_tmp_iovec;
+       iovec_dat_s_t de_tmp_iovec_s;
        vir_bytes de_read_s;
        int de_client;
        message de_sendmsg;
        dp_user2nicf_t de_user2nicf; 
+       dp_user2nicf_s_t de_user2nicf_s; 
        dp_nic2userf_t de_nic2userf; 
+       dp_nic2userf_s_t de_nic2userf_s; 
        dp_getblock_t de_getblockf; 
 } dpeth_t;
 
index 2510a51d0a8efbd4124dc4924a5e30e345c76d45..14c89a526f17ef074e57ccf9e6b3ee7c579e4aa1 100644 (file)
@@ -122,16 +122,19 @@ static void el3_write_fifo(dpeth_t * dep, int pktsize)
 {
   phys_bytes phys_user;
   int bytes, ix = 0;
-  iovec_dat_t *iovp = &dep->de_write_iovec;
-  int padding = pktsize;
+  iovec_dat_s_t *iovp = &dep->de_write_iovec;
+  int r, padding = pktsize;
 
   do {                         /* Writes chuncks of packet from user buffers */
 
        bytes = iovp->iod_iovec[ix].iov_size;   /* Size of buffer */
        if (bytes > pktsize) bytes = pktsize;
        /* Writes from user buffer to Tx FIFO */
-        outsb(dep->de_data_port, iovp->iod_proc_nr,
-              (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
+       r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
+               iovp->iod_iovec[ix].iov_grant, 0, bytes);
+       if (r != OK)
+               panic(__FILE__, "el3_write_fifo: sys_safe_insb failed", r);
+               
        if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
                dp_next_iovec(iovp);
                ix = 0;
index c435e3945fa5a98dd6f785babf9b672bd796f179..9116d2feac9a985f9ad3022ac15c26e96e454e39 100644 (file)
@@ -1,3 +1,4 @@
+#include <assert.h>
 /*
 **  File:      8390.c          May  02, 2000
 **
 
 #include "8390.h"
 
+#if 0
 #define        sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
        sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
                    (dstProc),D,(vir_bytes)(dstOffs),length)
-#define        sys_user2nic(srcProc,srcOffs,dstOffs,length) \
-       sys_vircopy((srcProc),D,(vir_bytes)(srcOffs),\
-                   SELF,dep->de_memsegm,(vir_bytes)(dstOffs),length)
+#endif
+#if 0
+#define        sys_user2nic_s(srcProc,grant,dstOffs,length) \
+       sys_safecopyfrom((srcProc),(grant),0, \
+                   (vir_bytes)(dstOffs),length,dep->de_memsegm)
+#endif
 
-static const char RdmaErrMsg[] = "remote dma failed to complete";
+static char RdmaErrMsg[] = "remote dma failed to complete";
 
 /*
 **  Name:      void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
@@ -72,9 +77,11 @@ static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
 */
 static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
 {
-
+  panic(__FILE__, "mem_getblock: not converted to safecopies", NO_NUM);
+#if 0
   sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
   return;
+#endif
 }
 
 /*
@@ -84,9 +91,12 @@ static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
 static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
 {
   phys_bytes offset, phys_user;
-  iovec_dat_t *iovp = &dep->de_read_iovec;
+  iovec_dat_s_t *iovp = &dep->de_read_iovec;
   int bytes, ix = 0;
 
+  panic(__FILE__, "mem_nic2user: not converted to safecopies", NO_NUM);
+#if 0
+
   /* Computes shared memory address (skipping receive header) */
   offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
 
@@ -100,16 +110,16 @@ static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
 
                /* Circular buffer wrap-around */
                bytes = dep->de_stoppage * DP_PAGESIZE - offset;
-               sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
-                           iovp->iod_iovec[ix].iov_addr, bytes);
+               sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
+                           iovp->iod_iovec[ix].iov_grant, bytes);
                pktsize -= bytes;
                phys_user += bytes;
                bytes = iovp->iod_iovec[ix].iov_size - bytes;
                if (bytes > pktsize) bytes = pktsize;
                offset = dep->de_startpage * DP_PAGESIZE;
        }
-       sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
-                   iovp->iod_iovec[ix].iov_addr, bytes);
+       sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
+                   iovp->iod_iovec[ix].iov_grant, bytes);
        offset += bytes;
 
        if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
@@ -119,6 +129,7 @@ static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
        /* Till packet done */
   } while ((pktsize -= bytes) > 0);
   return;
+#endif
 }
 
 /*
@@ -128,9 +139,12 @@ static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
 static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
 {
   phys_bytes offset, phys_user;
-  iovec_dat_t *iovp = &dep->de_write_iovec;
+  iovec_dat_s_t *iovp = &dep->de_write_iovec;
   int bytes, ix = 0;
 
+  panic(__FILE__, "mem_user2nic: not converted to safecopies", NO_NUM);
+#if 0
+
   /* Computes shared memory address */
   offset = pageno * DP_PAGESIZE;
 
@@ -140,7 +154,7 @@ static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
        if (bytes > pktsize) bytes = pktsize;
 
        /* Reads from user area to board (shared memory) */
-       sys_user2nic(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr
+       sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant
                     dep->de_linmem + offset, bytes);
        offset += bytes;
 
@@ -151,6 +165,7 @@ static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
        /* Till packet done */
   } while ((pktsize -= bytes) > 0);
   return;
+#endif
 }
 
 /*
@@ -183,8 +198,8 @@ static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
 static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
 {
   phys_bytes phys_user;
-  iovec_dat_t *iovp = &dep->de_read_iovec;
-  unsigned offset; int bytes, ix = 0;
+  iovec_dat_s_t *iovp = &dep->de_read_iovec;
+  unsigned offset, iov_offset; int r, bytes, ix = 0;
 
   /* Computes memory address (skipping receive header) */
   offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
@@ -192,6 +207,7 @@ static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
   ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
        (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
 
+  iov_offset= 0;
   do {                         /* Reads chuncks of packet into user area */
 
        bytes = iovp->iod_iovec[ix].iov_size;   /* Size of a chunck */
@@ -201,21 +217,31 @@ static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
 
                /* Circular buffer wrap-around */
                bytes = dep->de_stoppage * DP_PAGESIZE - offset;
-               insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
+               r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr, 
+                       iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
+               if (r != OK)
+               {
+                       panic(__FILE__, "pio_nic2user: sys_safe_insb failed",
+                               r);
+               }
                pktsize -= bytes;
-               iovp->iod_iovec[ix].iov_addr += bytes;
+               iov_offset += bytes;
                bytes = iovp->iod_iovec[ix].iov_size - bytes;
                if (bytes > pktsize) bytes = pktsize;
                offset = dep->de_startpage * DP_PAGESIZE;
                ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
        }
-       insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
+       r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
+               iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
+       if (r != OK)
+               panic(__FILE__, "pio_nic2user: sys_safe_insb failed", r);
        offset += bytes;
 
        if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
                dp_next_iovec(iovp);
                ix = 0;
        }
+       iov_offset= 0;
        /* Till packet done */
   } while ((pktsize -= bytes) > 0);
   return;
@@ -228,8 +254,8 @@ static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
 static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
 {
   phys_bytes phys_user;
-  iovec_dat_t *iovp = &dep->de_write_iovec;
-  int bytes, ix = 0;
+  iovec_dat_s_t *iovp = &dep->de_write_iovec;
+  int r, bytes, ix = 0;
 
   /* Sets up board for writing */
   ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
@@ -238,8 +264,10 @@ static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
 
        bytes = iovp->iod_iovec[ix].iov_size;   /* Size of chunck */
        if (bytes > pktsize) bytes = pktsize;
-       outsb(dep->de_data_port, iovp->iod_proc_nr,
-             (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
+       r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
+             iovp->iod_iovec[ix].iov_grant, 0, bytes);
+       if (r != OK)
+               panic(__FILE__, "pio_user2nic: sys_safe_outsb failed", r);
 
        if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
                dp_next_iovec(iovp);
index 8bc1107c7fe007ba4420250f8b9705b37e228132..49749a8633db83b02061ba6070c5f3eac5a79e31 100644 (file)
@@ -2,6 +2,9 @@
 ##  Makefile for ISA ethernet drivers  May  02, 2000
 ##
 ##  $Log$
+##  Revision 1.4  2006/07/10 12:43:38  philip
+##  Safecopy support in ethernet drivers.
+##
 ##  Revision 1.3  2005/07/19 13:21:48  jnherder
 ##  Renamed src/lib/utils to src/lib/sysutil --- because of new src/lib/util
 ##
@@ -26,7 +29,7 @@ debug = 0
 CC     = exec cc
 LD     = $(CC)
 CPPFLAGS= -I.. -I/usr/include -Ddebug=$(debug)
-CFLAGS = -ws $(CPPFLAGS)
+CFLAGS = $(CPPFLAGS)
 LDFLAGS        = -i -o $@
 
 SRCS   = 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c
index 832270c62ad36a55efa5418ad4788a6f1dc8f38e..b4c1ff5a5d52d89e10bbc359f8c5692f9c073068 100644 (file)
@@ -29,7 +29,7 @@ static void warning(const char *type, int err)
 */
 PUBLIC unsigned int inb(unsigned short port)
 {
-  unsigned int value;
+  unsigned long value;
   int rc;
 
   if ((rc = sys_inb(port, &value)) != OK) warning("inb", rc);
@@ -42,7 +42,7 @@ PUBLIC unsigned int inb(unsigned short port)
 */
 PUBLIC unsigned int inw(unsigned short port)
 {
-  unsigned int value;
+  unsigned long value;
   int rc;
 
   if ((rc = sys_inw(port, &value)) != OK) warning("inw", rc);
index 8894b1396b5bdc46cd0770c95674a7b67ba18eda..73f6fa9a667d31701f24069e9320f532a6acb201 100644 (file)
@@ -1,3 +1,4 @@
+#include <assert.h>
 /*
 **  File:      eth.c   Version 1.00,   Jan. 14, 1997
 **
@@ -29,7 +30,7 @@
 **  +------------+---------+---------+--------+-------+---------+
 **  | DL_READV   | port nr | proc nr | count  |       | address | (6)
 **  +------------+---------+---------+--------+-------+---------+
-**  | DL_INIT    | port nr | proc nr |        | mode  | address | (7)
+**  | DL_CONF    | port nr | proc nr |        | mode  | address | (7)
 **  +------------+---------+---------+--------+-------+---------+
 **  | DL_STOP    | port_nr |         |        |       |         | (8)
 **  +------------+---------+---------+--------+-------+---------+
@@ -45,7 +46,7 @@
 **
 **    m_type       m3_i1     m3_i2      m3_ca1
 **  +------------+---------+---------+---------------+
-**  |DL_INIT_REPL| port nr |last port| ethernet addr | (20)
+**  |DL_CONF_REPL| port nr |last port| ethernet addr | (20)
 **  +------------+---------+---------+---------------+
 **
 **  $Id$
@@ -80,13 +81,13 @@ static dp_conf_t dp_conf[DE_PORT_NR] = {
   {     0x280,  10,   0xCC000, "DPETH1", },
 };
 
-static const char CopyErrMsg[] = "unable to read/write user data";
-static const char PortErrMsg[] = "illegal port";
-static const char RecvErrMsg[] = "receive failed";
-static const char SendErrMsg[] = "send failed";
-static const char SizeErrMsg[] = "illegal packet size";
-static const char TypeErrMsg[] = "illegal message type";
-static const char DevName[] = "eth#?";
+static char CopyErrMsg[] = "unable to read/write user data";
+static char PortErrMsg[] = "illegal port";
+static char RecvErrMsg[] = "receive failed";
+static char SendErrMsg[] = "send failed";
+static char SizeErrMsg[] = "illegal packet size";
+static char TypeErrMsg[] = "illegal message type";
+static char DevName[] = "eth#?";
 
 static void do_getname(message *mp);
 
@@ -223,16 +224,17 @@ static void do_dump(message *mp)
 }
 
 /*
-**  Name:      void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
+**  Name:      void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
 **  Function:  Copies data from user area.
 */
-static void get_userdata(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
+static void get_userdata_s(int user_proc, cp_grant_id_t grant,
+       vir_bytes offset, int count, void *loc_addr)
 {
   int rc;
   vir_bytes len;
 
   len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
-  if ((rc = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes)loc_addr, len)) != OK)
+  if ((rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len, D)) != OK)
        panic(DevName, CopyErrMsg, rc);
   return;
 }
@@ -339,7 +341,7 @@ static void do_init(message * mp)
   } else                       /* Port number is out of range */
        port = ENXIO;
 
-  reply_mess.m_type = DL_INIT_REPLY;
+  reply_mess.m_type = DL_CONF_REPLY;
   reply_mess.m3_i1 = port;
   reply_mess.m3_i2 = DE_PORT_NR;
   DEBUG(printf("\t reply %d\n", reply_mess.m_type));
@@ -353,12 +355,12 @@ static void do_init(message * mp)
 **  Name:      void dp_next_iovec(iovec_dat_t *iovp)
 **  Function:  Retrieves data from next iovec element.
 */
-PUBLIC void dp_next_iovec(iovec_dat_t * iovp)
+PUBLIC void dp_next_iovec(iovec_dat_s_t * iovp)
 {
 
   iovp->iod_iovec_s -= IOVEC_NR;
-  iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
-  get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr,
+  iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
+  get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
             iovp->iod_iovec_s, iovp->iod_iovec);
   return;
 }
@@ -367,7 +369,7 @@ PUBLIC void dp_next_iovec(iovec_dat_t * iovp)
 **  Name:      int calc_iovec_size(iovec_dat_t *iovp)
 **  Function:  Compute the size of a request.
 */
-static int calc_iovec_size(iovec_dat_t * iovp)
+static int calc_iovec_size(iovec_dat_s_t * iovp)
 {
   int size, ix;
 
@@ -385,10 +387,10 @@ static int calc_iovec_size(iovec_dat_t * iovp)
 }
 
 /*
-**  Name:      void do_vwrite(message *mp, int vectored)
+**  Name:      void do_vwrite_s(message *mp, int vectored)
 **  Function:
 */
-static void do_vwrite(message * mp, int vectored)
+static void do_vwrite_s(message * mp)
 {
   int port, size;
   dpeth_t *dep;
@@ -406,18 +408,12 @@ static void do_vwrite(message * mp, int vectored)
                panic(dep->de_name, "send already in progress ", NO_NUM);
 
        dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
-       if (vectored) {
-               get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-                      mp->DL_COUNT, dep->de_write_iovec.iod_iovec);
-               dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT;
-               dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
-               size = calc_iovec_size(&dep->de_write_iovec);
-       } else {
-               dep->de_write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
-               dep->de_write_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT;
-               dep->de_write_iovec.iod_iovec_s = 1;
-               dep->de_write_iovec.iod_iovec_addr = 0;
-       }
+       get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
+              mp->DL_COUNT, dep->de_write_iovec.iod_iovec);
+       dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT;
+       dep->de_write_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
+       dep->de_write_iovec.iod_iovec_offset = 0;
+       size = calc_iovec_size(&dep->de_write_iovec);
        if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
                panic(dep->de_name, SizeErrMsg, size);
 
@@ -432,10 +428,10 @@ static void do_vwrite(message * mp, int vectored)
 }
 
 /*
-**  Name:      void do_vread(message *mp, int vectored)
+**  Name:      void do_vread_s(message *mp, int vectored)
 **  Function:
 */
-static void do_vread(message * mp, int vectored)
+static void do_vread_s(message * mp)
 {
   int port, size;
   dpeth_t *dep;
@@ -453,18 +449,12 @@ static void do_vread(message * mp, int vectored)
                panic(dep->de_name, "read already in progress", NO_NUM);
 
        dep->de_read_iovec.iod_proc_nr = mp->DL_PROC;
-       if (vectored) {
-               get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-                       mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
-               dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
-               dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
-               size = calc_iovec_size(&dep->de_read_iovec);
-       } else {
-               dep->de_read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
-               dep->de_read_iovec.iod_iovec[0].iov_size = size = mp->DL_COUNT;
-               dep->de_read_iovec.iod_iovec_s = 1;
-               dep->de_read_iovec.iod_iovec_addr = 0;
-       }
+       get_userdata_s(mp->DL_PROC, (vir_bytes) mp->DL_GRANT, 0,
+               mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
+       dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
+       dep->de_read_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
+       dep->de_read_iovec.iod_iovec_offset = 0;
+       size = calc_iovec_size(&dep->de_read_iovec);
        if (size < ETH_MAX_PACK_SIZE) panic(dep->de_name, SizeErrMsg, size);
 
        dep->de_flags |= DEF_READING;
@@ -481,10 +471,10 @@ static void do_vread(message * mp, int vectored)
 }
 
 /*
-**  Name:      void do_getstat(message *mp)
+**  Name:      void do_getstat_s(message *mp)
 **  Function:  Reports device statistics.
 */
-static void do_getstat(message * mp)
+static void do_getstat_s(message * mp)
 {
   int port, rc;
   dpeth_t *dep;
@@ -497,9 +487,9 @@ static void do_getstat(message * mp)
   dep->de_client = mp->DL_PROC;
 
   if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep);
-  if ((rc = sys_datacopy(SELF, (vir_bytes)&dep->de_stat,
-                        mp->DL_PROC, (vir_bytes)mp->DL_ADDR,
-                        (vir_bytes) sizeof(dep->de_stat))) != OK)
+  if ((rc = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
+                       (vir_bytes)&dep->de_stat,
+                       (vir_bytes) sizeof(dep->de_stat), 0)) != OK)
         panic(DevName, CopyErrMsg, rc);
   reply(dep, OK);
   return;
@@ -592,23 +582,17 @@ PUBLIC int main(int argc, char **argv)
            case DEV_PING:      /* Status request from RS */
                notify(m.m_source);
                continue;
-           case DL_WRITE:      /* Write message to device */
-               do_vwrite(&m, FALSE);
-               break;
-           case DL_WRITEV:     /* Write message to device */
-               do_vwrite(&m, TRUE);
-               break;
-           case DL_READ:       /* Read message from device */
-               do_vread(&m, FALSE);
+           case DL_WRITEV_S:   /* Write message to device */
+               do_vwrite_s(&m);
                break;
-           case DL_READV:      /* Read message from device */
-               do_vread(&m, TRUE);
+           case DL_READV_S:    /* Read message from device */
+               do_vread_s(&m);
                break;
-           case DL_INIT:       /* Initialize device */
+           case DL_CONF:       /* Initialize device */
                do_init(&m);
                break;
-           case DL_GETSTAT:    /* Get device statistics */
-               do_getstat(&m);
+           case DL_GETSTAT_S:  /* Get device statistics */
+               do_getstat_s(&m);
                break;
            case DL_GETNAME:
                do_getname(&m);
index d88cf674d89a3b72f03efaf4dfa76a275ba2f2f3..a18f9240c721a7d1bbd18a5c96133aeb8a6fb016 100644 (file)
@@ -6,6 +6,9 @@
 **  Interface description for ethernet device driver
 **
 **  $Log$
+**  Revision 1.5  2006/07/10 12:43:38  philip
+**  Safecopy support in ethernet drivers.
+**
 **  Revision 1.4  2005/09/04 18:52:16  beng
 **  Giovanni's fixes to dpeth:
 **  Date: Sat, 03 Sep 2005 11:05:22 +0200
@@ -83,12 +86,13 @@ typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *);
 #define SENDQ_NR       2       /* Size of the send queue        */
 #define IOVEC_NR       16      /* Number of IOVEC entries at a time */
 
-typedef struct iovec_dat {
-  iovec_t iod_iovec[IOVEC_NR];
+typedef struct iovec_dat_s {
+  iovec_s_t iod_iovec[IOVEC_NR];
   int iod_iovec_s;
   int iod_proc_nr;
-  vir_bytes iod_iovec_addr;
-} iovec_dat_t;
+  cp_grant_id_t iod_grant;
+  vir_bytes iod_iovec_offset;
+} iovec_dat_s_t;
 
 typedef struct dpeth {
   /* The de_base_port field is the starting point of the probe. The
@@ -161,8 +165,8 @@ typedef struct dpeth {
 #define DEM_ENABLED    0x0002
 
   /* Temporary storage for RECV/SEND requests */
-  iovec_dat_t de_read_iovec;
-  iovec_dat_t de_write_iovec;
+  iovec_dat_s_t de_read_iovec;
+  iovec_dat_s_t de_write_iovec;
   vir_bytes de_read_s;
   vir_bytes de_send_s;
   int de_client;
@@ -216,7 +220,7 @@ typedef struct dpeth {
  */
 
 /* dp.c */
-void dp_next_iovec(iovec_dat_t * iovp);
+void dp_next_iovec(iovec_dat_s_t * iovp);
 
 /* devio.c */
 #if defined USE_IOPL
index 8b1d97d5ac2bd6a7e9574bf6a4be67025b8ef64a..91cf20f2caa9361946a86da3fde2c5922cb02437 100644 (file)
@@ -111,8 +111,8 @@ PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff)
 {
   phys_bytes phys_user;
   int bytes, ix = 0;
-  iovec_dat_t *iovp = &dep->de_read_iovec;
-  int pktsize = rxbuff->size;
+  iovec_dat_s_t *iovp = &dep->de_read_iovec;
+  int r, pktsize = rxbuff->size;
   char *buffer = rxbuff->buffer;
 
   do {                         /* Reads chuncks of packet into user buffers */
@@ -121,8 +121,10 @@ PUBLIC void mem2user(dpeth_t *dep, buff_t *rxbuff)
        if (bytes > pktsize) bytes = pktsize;
 
        /* Reads from Rx buffer to user area */
-       sys_datacopy(SELF, (vir_bytes)buffer, iovp->iod_proc_nr,
-                    iovp->iod_iovec[ix].iov_addr, bytes);
+       r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0,
+               (vir_bytes)buffer, bytes, D);
+       if (r != OK)
+               panic(__FILE__, "mem2user: sys_safecopyto failed", r);
        buffer += bytes;
 
        if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
@@ -142,16 +144,18 @@ PUBLIC void user2mem(dpeth_t *dep, buff_t *txbuff)
 {
   phys_bytes phys_user;
   int bytes, ix = 0;
-  iovec_dat_t *iovp = &dep->de_write_iovec;
-  int pktsize = txbuff->size;
+  iovec_dat_s_t *iovp = &dep->de_write_iovec;
+  int r, pktsize = txbuff->size;
   char *buffer = txbuff->buffer;
 
   do {                         /* Reads chuncks of packet from user buffers */
 
        bytes = iovp->iod_iovec[ix].iov_size;   /* Size of buffer */
        if (bytes > pktsize) bytes = pktsize;
-       sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr,
-                    SELF, (vir_bytes)buffer, bytes);
+       r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
+               0, (vir_bytes)buffer, bytes, D);
+       if (r != OK)
+               panic(__FILE__, "user2mem: sys_safecopyfrom failed", r);
        buffer += bytes;
 
        if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
index 827da511fd2a44f4531c771ace704cc171a67574..e72c71fddb2ac04a6794f2a772e452c1c2c2b115 100644 (file)
@@ -21,7 +21,7 @@ OBJ = fxp.o mii.o
 all build:     $(DRIVER)
 $(DRIVER):     $(OBJ) 
        $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
-       install -S 4096 $(DRIVER)
+       install -S 8k $(DRIVER)
 
 # install with other drivers
 install:       /usr/sbin/$(DRIVER)
index 223cb81b630006e5f343c1c11fdb11c7cb5230ef..cb7f152afad87e01ccd748e31c4e77591b149a5e 100644 (file)
@@ -6,24 +6,30 @@
  *
  * The valid messages and their parameters are:
  *
- *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
- * |------------+----------+---------+----------+---------+---------|
- * | HARDINT   |          |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READ   | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READV  | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_INIT   | port nr  | proc nr | mode     |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_GETSTAT        | port nr  | proc nr |          |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_STOP   | port_nr  |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR   DL_GRANT
+ * |------------+----------+---------+----------+---------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV_S| port nr  | proc nr | count    | mode    |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV_S        | port nr  | proc nr | count    |         |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_CONF   | port nr  | proc nr |          | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * |DL_GETSTAT_S| port nr  | proc nr |          |         |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
  *
  * The messages sent are:
  *
@@ -34,7 +40,7 @@
  *
  *   m_type       m3_i1     m3_i2       m3_ca1
  * |-------------+---------+-----------+---------------|
- * |DL_INIT_REPLY| port nr | last port | ethernet addr |
+ * |DL_CONF_REPLY| port nr | last port | ethernet addr |
  * |-------------+---------+-----------+---------------|
  *
  * Created:    Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
@@ -169,6 +175,7 @@ typedef struct fxp
        u8_t fxp_conf_bytes[CC_BYTES_NR];
        char fxp_name[sizeof("fxp#n")];
        iovec_t fxp_iovec[IOVEC_NR];
+       iovec_s_t fxp_iovec_s[IOVEC_NR];
 }
 fxp_t;
 
@@ -223,8 +230,10 @@ _PROTOTYPE( static void fxp_confaddr, (fxp_t *fp)                  );
 _PROTOTYPE( static void fxp_rec_mode, (fxp_t *fp)                      );
 _PROTOTYPE( static void fxp_writev, (message *mp, int from_int,
                                                        int vectored)   );
+_PROTOTYPE( static void fxp_writev_s, (message *mp, int from_int)      );
 _PROTOTYPE( static void fxp_readv, (message *mp, int from_int, 
                                                        int vectored)   );
+_PROTOTYPE( static void fxp_readv_s, (message *mp, int from_int)       );
 _PROTOTYPE( static void fxp_do_conf, (fxp_t *fp)                       );
 _PROTOTYPE( static void fxp_cu_ptr_cmd, (fxp_t *fp, int cmd,
                                phys_bytes bus_addr, int check_idle)    );
@@ -232,6 +241,7 @@ _PROTOTYPE( static void fxp_ru_ptr_cmd, (fxp_t *fp, int cmd,
                                phys_bytes bus_addr, int check_idle)    );
 _PROTOTYPE( static void fxp_restart_ru, (fxp_t *fp)                    );
 _PROTOTYPE( static void fxp_getstat, (message *mp)                     );
+_PROTOTYPE( static void fxp_getstat_s, (message *mp)                   );
 _PROTOTYPE( static void fxp_getname, (message *mp)                     );
 _PROTOTYPE( static int fxp_handler, (fxp_t *fp)                                );
 _PROTOTYPE( static void fxp_check_ints, (fxp_t *fp)                    );
@@ -241,8 +251,6 @@ _PROTOTYPE( static void fxp_report_link, (fxp_t *fp)                        );
 _PROTOTYPE( static void fxp_stop, (void));
 _PROTOTYPE( static void reply, (fxp_t *fp, int err, int may_block)     );
 _PROTOTYPE( static void mess_reply, (message *req, message *reply)     );
-_PROTOTYPE( static void put_userdata, (int user_proc,
-               vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
 _PROTOTYPE( static u16_t eeprom_read, (fxp_t *fp, int reg)             );
 _PROTOTYPE( static void eeprom_addrsize, (fxp_t *fp)                   );
 _PROTOTYPE( static u16_t mii_read, (fxp_t *fp, int reg)                        );
@@ -298,12 +306,13 @@ int main(int argc, char *argv[])
                case DEV_PING:  notify(m.m_source);             continue;
                case DL_WRITEV: fxp_writev(&m, FALSE, TRUE);    break;
                case DL_WRITE:  fxp_writev(&m, FALSE, FALSE);   break;
-#if 0
-               case DL_READ:   fxp_vread(&m, FALSE);           break;
-#endif
+               case DL_WRITEV_S: fxp_writev_s(&m, FALSE);      break;
+               case DL_READ:   fxp_readv(&m, FALSE, FALSE);    break;
                case DL_READV:  fxp_readv(&m, FALSE, TRUE);     break;
-               case DL_INIT:   fxp_init(&m);                   break;
+               case DL_READV_S: fxp_readv_s(&m, FALSE);        break;
+               case DL_CONF:   fxp_init(&m);                   break;
                case DL_GETSTAT: fxp_getstat(&m);               break;
+               case DL_GETSTAT_S: fxp_getstat_s(&m);           break;
                case DL_GETNAME: fxp_getname(&m);               break;
                case HARD_INT:
                        for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
@@ -361,7 +370,7 @@ message *mp;
        port = mp->DL_PORT;
        if (port < 0 || port >= FXP_PORT_NR)
        {
-               reply_mess.m_type= DL_INIT_REPLY;
+               reply_mess.m_type= DL_CONF_REPLY;
                reply_mess.m3_i1= ENXIO;
                mess_reply(mp, &reply_mess);
                return;
@@ -374,7 +383,7 @@ message *mp;
                if (fp->fxp_mode == FM_DISABLED)
                {
                        /* Probe failed, or the device is configured off. */
-                       reply_mess.m_type= DL_INIT_REPLY;
+                       reply_mess.m_type= DL_CONF_REPLY;
                        reply_mess.m3_i1= ENXIO;
                        mess_reply(mp, &reply_mess);
                        return;
@@ -399,7 +408,7 @@ message *mp;
        fp->fxp_client = mp->m_source;
        fxp_rec_mode(fp);
 
-       reply_mess.m_type = DL_INIT_REPLY;
+       reply_mess.m_type = DL_CONF_REPLY;
        reply_mess.m3_i1 = mp->DL_PORT;
        reply_mess.m3_i2 = FXP_PORT_NR;
        *(ether_addr_t *) reply_mess.m3_ca1 = fp->fxp_address;
@@ -1194,6 +1203,152 @@ suspend:
        reply(fp, OK, FALSE);
 }
 
+/*===========================================================================*
+ *                             fxp_writev_s                                 *
+ *===========================================================================*/
+static void fxp_writev_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       cp_grant_id_t iov_grant;
+       vir_bytes iov_offset;
+       int i, j, n, o, r, s, dl_port, count, size, prev_head;
+       int fxp_client, fxp_tx_nbuf, fxp_tx_head;
+       u16_t tx_command;
+       fxp_t *fp;
+       iovec_s_t *iovp;
+       struct tx *txp, *prev_txp;
+
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= FXP_PORT_NR)
+               panic("FXP","fxp_writev: illegal port", dl_port);
+       fp= &fxp_table[dl_port];
+       fxp_client= mp->DL_PROC;
+       fp->fxp_client= fxp_client;
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       if (from_int)
+       {
+               assert(fp->fxp_flags & FF_SEND_AVAIL);
+               fp->fxp_flags &= ~FF_SEND_AVAIL;
+               fp->fxp_tx_alive= TRUE;
+       }
+
+       if (fp->fxp_tx_idle)
+       {
+               txp= fp->fxp_tx_buf;
+               fxp_tx_head= 0; /* lint */
+               prev_txp= NULL; /* lint */
+       }
+       else
+       {       
+               fxp_tx_nbuf= fp->fxp_tx_nbuf;
+               prev_head= fp->fxp_tx_head;
+               fxp_tx_head= prev_head+1;
+               if (fxp_tx_head == fxp_tx_nbuf)
+                       fxp_tx_head= 0;
+               assert(fxp_tx_head < fxp_tx_nbuf);
+
+               if (fxp_tx_head == fp->fxp_tx_tail)
+               {
+                       /* Send queue is full */
+                       assert(!(fp->fxp_flags & FF_SEND_AVAIL));
+                       fp->fxp_flags |= FF_SEND_AVAIL;
+                       goto suspend;
+               }
+
+               prev_txp= &fp->fxp_tx_buf[prev_head];
+               txp= &fp->fxp_tx_buf[fxp_tx_head];
+       }
+
+       assert(!(fp->fxp_flags & FF_SEND_AVAIL));
+       assert(!(fp->fxp_flags & FF_PACK_SENT));
+
+       iov_grant= mp->DL_GRANT;
+
+       size= 0;
+       o= 0;
+       iov_offset= 0;
+       for (i= 0; i<count; i += IOVEC_NR,
+               iov_offset += IOVEC_NR * sizeof(fp->fxp_iovec_s[0]))
+       {
+               n= IOVEC_NR;
+               if (i+n > count)
+                       n= count-i;
+               r= sys_safecopyfrom(fxp_client, iov_grant, iov_offset,
+                       (vir_bytes)fp->fxp_iovec_s,
+                       n * sizeof(fp->fxp_iovec_s[0]), D);
+               if (r != OK)
+                       panic("FXP","fxp_writev: sys_safecopyfrom failed", r);
+
+               for (j= 0, iovp= fp->fxp_iovec_s; j<n; j++, iovp++)
+               {
+                       s= iovp->iov_size;
+                       if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
+                       {
+                               panic("FXP","fxp_writev: invalid packet size",
+                                       size + s);
+                       }
+
+                       r= sys_safecopyfrom(fxp_client, iovp->iov_grant,
+                               0, (vir_bytes)(txp->tx_buf+o), s, D);
+                       if (r != OK)
+                       {
+                               panic("FXP",
+                               "fxp_writev_s: sys_safecopyfrom failed",
+                                       r);
+                       }
+                       size += s;
+                       o += s;
+               }
+       }
+       if (size < ETH_MIN_PACK_SIZE)
+               panic("FXP","fxp_writev: invalid packet size", size);
+
+       txp->tx_status= 0;
+       txp->tx_command= TXC_EL | CBL_XMIT;
+       txp->tx_tbda= TX_TBDA_NIL;
+       txp->tx_size= TXSZ_EOF | size;
+       txp->tx_tthresh= fp->fxp_tx_threshold;
+       txp->tx_ntbd= 0;
+       if (fp->fxp_tx_idle)
+       {
+               fp->fxp_tx_idle= 0;
+               fp->fxp_tx_head= fp->fxp_tx_tail= 0;
+
+               fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr,
+                       TRUE /* check idle */);
+       }
+       else
+       {
+               /* Link new request in transmit list */
+               tx_command= prev_txp->tx_command;
+               assert(tx_command == (TXC_EL | CBL_XMIT));
+               prev_txp->tx_command= CBL_XMIT;
+               fp->fxp_tx_head= fxp_tx_head;
+       }
+
+       fp->fxp_flags |= FF_PACK_SENT;
+
+       /* If the interrupt handler called, don't send a reply. The reply
+        * will be sent after all interrupts are handled. 
+        */
+       if (from_int)
+               return;
+       reply(fp, OK, FALSE);
+       return;
+
+suspend:
+       if (from_int)
+               panic("FXP","fxp: should not be sending\n", NO_NUM);
+
+       fp->fxp_tx_mess= *mp;
+       reply(fp, OK, FALSE);
+}
+
 /*===========================================================================*
  *                             fxp_readv                                    *
  *===========================================================================*/
@@ -1374,6 +1529,179 @@ suspend:
        reply(fp, OK, FALSE);
 }
 
+/*===========================================================================*
+ *                             fxp_readv_s                                  *
+ *===========================================================================*/
+static void fxp_readv_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       int i, j, n, o, r, s, dl_port, fxp_client, count, size,
+               fxp_rx_head, fxp_rx_nbuf;
+       cp_grant_id_t iov_grant;
+       port_t port;
+       unsigned packlen;
+       vir_bytes iov_offset;
+       u16_t rfd_status;
+       u16_t rfd_res;
+       u8_t scb_status;
+       fxp_t *fp;
+       iovec_s_t *iovp;
+       struct rfd *rfdp, *prev_rfdp;
+
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= FXP_PORT_NR)
+               panic("FXP","fxp_readv: illegal port", dl_port);
+       fp= &fxp_table[dl_port];
+       fxp_client= mp->DL_PROC;
+       fp->fxp_client= fxp_client;
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       port= fp->fxp_base_port;
+
+       fxp_rx_head= fp->fxp_rx_head;
+       rfdp= &fp->fxp_rx_buf[fxp_rx_head];
+
+       rfd_status= rfdp->rfd_status;
+       if (!(rfd_status & RFDS_C))
+       {
+               /* Receive buffer is empty, suspend */
+               goto suspend;
+       }
+
+       if (!rfd_status & RFDS_OK)
+       {
+               /* Not OK? What happened? */
+               assert(0);
+       }
+       else
+       {
+               assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR |
+                       RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | 
+                       RFDS_RXERR)));
+       }
+       rfd_res= rfdp->rfd_res;
+       assert(rfd_res & RFDR_EOF);
+       assert(rfd_res & RFDR_F);
+
+       packlen= rfd_res & RFDSZ_SIZE;
+
+       iov_grant = mp->DL_GRANT;
+
+       size= 0;
+       o= 0;
+       iov_offset= 0;
+       for (i= 0; i<count; i += IOVEC_NR,
+               iov_offset += IOVEC_NR * sizeof(fp->fxp_iovec_s[0]))
+       {
+               n= IOVEC_NR;
+               if (i+n > count)
+                       n= count-i;
+               r= sys_safecopyfrom(fxp_client, iov_grant, iov_offset,
+                       (vir_bytes)fp->fxp_iovec_s,
+                       n * sizeof(fp->fxp_iovec_s[0]), D);
+               if (r != OK)
+                       panic("FXP","fxp_readv_s: sys_safecopyfrom failed", r);
+
+               for (j= 0, iovp= fp->fxp_iovec_s; j<n; j++, iovp++)
+               {
+                       s= iovp->iov_size;
+                       if (size + s > packlen)
+                       {
+                               assert(packlen > size);
+                               s= packlen-size;
+                       }
+
+                       r= sys_safecopyto(fxp_client, iovp->iov_grant,
+                               0, (vir_bytes)(rfdp->rfd_buf+o), s, D);
+                       if (r != OK)
+                       {
+                               panic("FXP","fxp_readv: sys_safecopyto failed",
+                                       r);
+                       }
+
+                       size += s;
+                       if (size == packlen)
+                               break;
+                       o += s;
+               }
+               if (size == packlen)
+                       break;
+       }
+       if (size < packlen)
+       {
+               assert(0);
+       }
+
+       fp->fxp_read_s= packlen;
+       fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV;
+
+       /* Re-init the current buffer */
+       rfdp->rfd_status= 0;
+       rfdp->rfd_command= RFDC_EL;
+       rfdp->rfd_reserved= 0;
+       rfdp->rfd_res= 0;
+       rfdp->rfd_size= sizeof(rfdp->rfd_buf);
+
+       fxp_rx_nbuf= fp->fxp_rx_nbuf;
+       if (fxp_rx_head == 0)
+       {
+               prev_rfdp= &fp->fxp_rx_buf[fxp_rx_nbuf-1];
+       }
+       else
+               prev_rfdp= &rfdp[-1];
+
+       assert(prev_rfdp->rfd_command & RFDC_EL);
+       prev_rfdp->rfd_command &= ~RFDC_EL;
+
+       fxp_rx_head++;
+       if (fxp_rx_head == fxp_rx_nbuf)
+               fxp_rx_head= 0;
+       assert(fxp_rx_head < fxp_rx_nbuf);
+       fp->fxp_rx_head= fxp_rx_head;
+
+       if (!from_int)
+               reply(fp, OK, FALSE);
+
+       return;
+
+suspend:
+       if (fp->fxp_rx_need_restart)
+       {
+               fp->fxp_rx_need_restart= 0;
+
+               /* Check the status of the RU */
+               scb_status= fxp_inb(port, SCB_STATUS);
+               if ((scb_status & SS_RUS_MASK) != SS_RU_NORES)
+               {
+                       /* Race condition? */
+                       printf("fxp_readv: restart race: 0x%x\n",
+                               scb_status);
+                       assert((scb_status & SS_RUS_MASK) == SS_RU_READY);
+               }
+               else
+               {
+                       fxp_restart_ru(fp);
+               }
+       }
+       if (from_int)
+       {
+               assert(fp->fxp_flags & FF_READING);
+
+               /* No need to store any state */
+               return;
+       }
+
+       fp->fxp_rx_mess= *mp;
+       assert(!(fp->fxp_flags & FF_READING));
+       fp->fxp_flags |= FF_READING;
+
+       reply(fp, OK, FALSE);
+}
+
 /*===========================================================================*
  *                             fxp_do_conf                                  *
  *===========================================================================*/
@@ -1529,7 +1857,7 @@ static void fxp_getstat(mp)
 message *mp;
 {
        clock_t t0,t1;
-       int dl_port;
+       int r, dl_port;
        port_t port;
        fxp_t *fp;
        u32_t *p;
@@ -1592,8 +1920,88 @@ message *mp;
        stats.ets_CDheartbeat= 0;
        stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
 
-       put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-               (vir_bytes) sizeof(stats), &stats);
+       r= sys_vircopy(SELF, D, (vir_bytes)&stats,
+               mp->DL_PROC, D, (vir_bytes) mp->DL_ADDR, sizeof(stats));
+       if (r != OK)
+               panic(__FILE__,"fxp_getstat: sys_vircopy failed", r);
+       reply(fp, OK, FALSE);
+}
+
+
+/*===========================================================================*
+ *                             fxp_getstat_s                                *
+ *===========================================================================*/
+static void fxp_getstat_s(mp)
+message *mp;
+{
+       clock_t t0,t1;
+       int r, dl_port;
+       port_t port;
+       fxp_t *fp;
+       u32_t *p;
+       eth_stat_t stats;
+
+       dl_port = mp->DL_PORT;
+       if (dl_port < 0 || dl_port >= FXP_PORT_NR)
+               panic("FXP","fxp_getstat: illegal port", dl_port);
+       fp= &fxp_table[dl_port];
+       fp->fxp_client= mp->DL_PROC;
+
+       assert(fp->fxp_mode == FM_ENABLED);
+       assert(fp->fxp_flags & FF_ENABLED);
+
+       port= fp->fxp_base_port;
+
+       p= &fp->fxp_stat.sc_tx_fcp;
+       *p= 0;
+
+       /* The dump commmand doesn't take a pointer. Setting a pointer
+        * doesn't hurt though.
+        */
+       fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */);
+
+       getuptime(&t0);
+       do {
+               /* Wait for CU command to complete */
+               if (*p != 0)
+                       break;
+       } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000));
+
+       if (*p == 0)
+               panic("FXP","fxp_getstat: CU command failed to complete", NO_NUM);
+       if (*p != SCM_DSC)
+               panic("FXP","fxp_getstat: bad magic", NO_NUM);
+
+       stats.ets_recvErr=
+               fp->fxp_stat.sc_rx_crc +
+               fp->fxp_stat.sc_rx_align +
+               fp->fxp_stat.sc_rx_resource +
+               fp->fxp_stat.sc_rx_overrun +
+               fp->fxp_stat.sc_rx_cd +
+               fp->fxp_stat.sc_rx_short;
+       stats.ets_sendErr=
+               fp->fxp_stat.sc_tx_maxcol +
+               fp->fxp_stat.sc_tx_latecol +
+               fp->fxp_stat.sc_tx_crs;
+       stats.ets_OVW= fp->fxp_stat.sc_rx_overrun;
+       stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc;
+       stats.ets_frameAll= fp->fxp_stat.sc_rx_align;
+       stats.ets_missedP= fp->fxp_stat.sc_rx_resource;
+       stats.ets_packetR= fp->fxp_stat.sc_rx_good;
+       stats.ets_packetT= fp->fxp_stat.sc_tx_good;
+       stats.ets_transDef= fp->fxp_stat.sc_tx_defered;
+       stats.ets_collision= fp->fxp_stat.sc_tx_totcol;
+       stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol;
+       stats.ets_carrSense= fp->fxp_stat.sc_tx_crs;
+       stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun;
+       stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun;
+       stats.ets_CDheartbeat= 0;
+       stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
+
+       r= sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0, (vir_bytes)&stats,
+               sizeof(stats), D);
+       if (r != OK)
+               panic(__FILE__,"fxp_getstat_s: sys_safecopyto failed", r);
        reply(fp, OK, FALSE);
 }
 
@@ -1697,6 +2105,11 @@ fxp_t *fp;
                        fxp_readv(&fp->fxp_rx_mess, TRUE /* from int */,
                                TRUE /* vectored */);
                }
+               else if (fp->fxp_rx_mess.m_type == DL_READV_S)
+               {
+                       fxp_readv_s(&fp->fxp_rx_mess, TRUE /* from int */);
+                               
+               }
                else
                {
                        assert(fp->fxp_rx_mess.m_type == DL_READ);
@@ -1803,6 +2216,11 @@ fxp_t *fp;
                                                TRUE /* from int */,
                                                TRUE /* vectored */);
                                }
+                               else if (fp->fxp_tx_mess.m_type == DL_WRITEV_S)
+                               {
+                                       fxp_writev_s(&fp->fxp_tx_mess,
+                                               TRUE /* from int */);
+                               }
                                else
                                {
                                        assert(fp->fxp_tx_mess.m_type ==
@@ -2212,23 +2630,6 @@ message *reply_mess;
                panic("FXP","fxp: unable to mess_reply", NO_NUM);
 }
 
-/*===========================================================================*
- *                             put_userdata                                 *
- *===========================================================================*/
-static void put_userdata(user_proc, user_addr, count, loc_addr)
-int user_proc;
-vir_bytes user_addr;
-vir_bytes count;
-void *loc_addr;
-{
-       int r;
-
-       r= sys_vircopy(SELF, D, (vir_bytes)loc_addr,
-               user_proc, D, user_addr, count);
-       if (r != OK)
-               panic("FXP","put_userdata: sys_vircopy failed", r);
-}
-
 /*===========================================================================*
  *                             eeprom_read                                  *
  *===========================================================================*/
index c60c5b66f3fdce082ff27df6474d071d52931e64..9b31a326cf985a367d432842021a3cc4f1152649 100644 (file)
@@ -6,24 +6,30 @@
  *
  * The valid messages and their parameters are:
  *
- *   m_type       DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
- * |------------+----------+---------+----------+---------+---------|
- * | HARDINT    |          |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITE   | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITEV  | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READ    | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READV   | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_INIT    | port nr  | proc nr | mode     |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_GETSTAT | port nr  | proc nr |          |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_STOP    | port_nr  |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR   DL_GRANT
+ * |------------+----------+---------+----------+---------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV_S| port nr  | proc nr | count    | mode    |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV_S        | port nr  | proc nr | count    |         |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_CONF   | port nr  | proc nr |          | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * |DL_GETSTAT_S| port nr  | proc nr |          |         |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
  *
  * The messages sent are:
  *
@@ -34,7 +40,7 @@
  *
  *   m_type       m3_i1     m3_i2       m3_ca1
  * |------------+---------+-----------+---------------|
- * |DL_INIT_REPL| port nr | last port | ethernet addr |
+ * |DL_CONF_REPL| port nr | last port | ethernet addr |
  * |------------|---------|-----------|---------------|
  *
  * Created: Jul 27, 2002 by Kazuya Kodama <kazuya@nii.ac.jp>
@@ -144,11 +150,11 @@ _PROTOTYPE( static void reply,
 _PROTOTYPE( static void ec_reset, (ether_card_t *ec)                    );
 _PROTOTYPE( static void ec_send, (ether_card_t *ec)                     );
 _PROTOTYPE( static void ec_recv, (ether_card_t *ec)                     );
-_PROTOTYPE( static void do_vwrite, 
-           (message *mp, int from_int, int vectored)                   );
-_PROTOTYPE( static void do_vread, (message *mp, int vectored)           );
-_PROTOTYPE( static void get_userdata, 
-           (int user_proc, vir_bytes user_addr, 
+_PROTOTYPE( static void do_vwrite_s
+           (message *mp, int from_int)                                 );
+_PROTOTYPE( static void do_vread_s, (message *mp)                      );
+_PROTOTYPE( static void get_userdata_s
+           (int user_proc, cp_grant_id_t grant, vir_bytes offset,
             vir_bytes count, void *loc_addr)                           );
 _PROTOTYPE( static void ec_user2nic, 
            (ether_card_t *dep, iovec_dat_t *iovp, 
@@ -160,11 +166,10 @@ _PROTOTYPE( static void ec_nic2user,
             vir_bytes count)                                           );
 _PROTOTYPE( static int calc_iovec_size, (iovec_dat_t *iovp)             );
 _PROTOTYPE( static void ec_next_iovec, (iovec_dat_t *iovp)              );
-_PROTOTYPE( static void do_getstat, (message *mp)                       );
-_PROTOTYPE( static void put_userdata, 
-           (int user_proc,
-            vir_bytes user_addr, vir_bytes count, 
-            void *loc_addr)                                            );
+_PROTOTYPE( static void do_getstat_s, (message *mp)                     );
+_PROTOTYPE( static void put_userdata_s, 
+           (int user_proc, cp_grant_id_t grant,
+            void *loc_addr, vir_bytes count)                           );
 _PROTOTYPE( static void do_stop, (message *mp)                          );
 _PROTOTYPE( static void do_getname, (message *mp)                       );
 
@@ -356,14 +361,12 @@ void main( int argc, char **argv )
 
       switch (m.m_type){
       case DEV_PING:   notify(m.m_source);             continue;
-      case DL_WRITE:   do_vwrite(&m, FALSE, FALSE);    break;
-      case DL_WRITEV:  do_vwrite(&m, FALSE, TRUE);     break;
-      case DL_READ:    do_vread(&m, FALSE);            break;
-      case DL_READV:   do_vread(&m, TRUE);             break;
-      case DL_INIT:    do_init(&m);                    break;
-      case DL_GETSTAT: do_getstat(&m);                 break;
+      case DL_WRITEV_S: do_vwrite_s(&m, FALSE);       break;
+      case DL_READV_S: do_vread_s(&m);                break;
+      case DL_CONF:    do_init(&m);                    break;
+      case DL_GETSTAT_S: do_getstat_s(&m);             break;
       case DL_STOP:    do_stop(&m);                    break;
-      case DL_GETNAME: do_getname(&m);                         break;
+      case DL_GETNAME: do_getname(&m);                        break;
       case FKEY_PRESSED: lance_dump();                 break;
       /*case HARD_STOP:  lance_stop();                   break;*/
       case SYS_SIG:
@@ -493,7 +496,7 @@ pci_init();
   port = mp->DL_PORT;
   if (port < 0 || port >= EC_PORT_NR_MAX)
     {
-      reply_mess.m_type= DL_INIT_REPLY;
+      reply_mess.m_type= DL_CONF_REPLY;
       reply_mess.m3_i1= ENXIO;
       mess_reply(mp, &reply_mess);
       return;
@@ -517,7 +520,7 @@ pci_init();
       if (ec->mode == EC_DISABLED)
        {
          /* Probe failed, or the device is configured off. */
-         reply_mess.m_type= DL_INIT_REPLY;
+         reply_mess.m_type= DL_CONF_REPLY;
          reply_mess.m3_i1= ENXIO;
          mess_reply(mp, &reply_mess);
          return;
@@ -535,7 +538,7 @@ pci_init();
        ec->mac_address.ea_addr[4] = 
        ec->mac_address.ea_addr[5] = 0;
       ec_confaddr(ec);
-      reply_mess.m_type = DL_INIT_REPLY;
+      reply_mess.m_type = DL_CONF_REPLY;
       reply_mess.m3_i1 = mp->DL_PORT;
       reply_mess.m3_i2 = EC_PORT_NR_MAX;
       *(ether_addr_t *) reply_mess.m3_ca1 = ec->mac_address;
@@ -557,7 +560,7 @@ pci_init();
   ec->client = mp->m_source;
   ec_reinit(ec);
 
-  reply_mess.m_type = DL_INIT_REPLY;
+  reply_mess.m_type = DL_CONF_REPLY;
   reply_mess.m3_i1 = mp->DL_PORT;
   reply_mess.m3_i2 = EC_PORT_NR_MAX;
   *(ether_addr_t *) reply_mess.m3_ca1 = ec->mac_address;
@@ -1071,8 +1074,7 @@ ether_card_t *ec;
   ec->flags &= ~ECF_SEND_AVAIL;
   switch(ec->sendmsg.m_type)
     {
-    case DL_WRITE:  do_vwrite(&ec->sendmsg, TRUE, FALSE);       break;
-    case DL_WRITEV: do_vwrite(&ec->sendmsg, TRUE, TRUE);        break;
+    case DL_WRITEV_S: do_vwrite_s(&ec->sendmsg, TRUE);        break;
     default:
       panic( "lance", "wrong type:", ec->sendmsg.m_type);
       break;
@@ -1080,11 +1082,10 @@ ether_card_t *ec;
 }
 
 /*===========================================================================*
- *                              do_vread                                     *
+ *                              do_vread_s                                   *
  *===========================================================================*/
-static void do_vread(mp, vectored)
+static void do_vread_s(mp)
 message *mp;
-int vectored;
 {
   int port, count, size;
   ether_card_t *ec;
@@ -1094,28 +1095,17 @@ int vectored;
   ec= &ec_table[port];
   ec->client= mp->DL_PROC;
 
-  if (vectored)
-    {
-      get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-                   (count > IOVEC_NR ? IOVEC_NR : count) *
-                   sizeof(iovec_t), ec->read_iovec.iod_iovec);
-      ec->read_iovec.iod_iovec_s    = count;
-      ec->read_iovec.iod_proc_nr    = mp->DL_PROC;
-      ec->read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
-      
-      ec->tmp_iovec = ec->read_iovec;
-      size= calc_iovec_size(&ec->tmp_iovec);
-    }
-  else
-    {
-      ec->read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
-      ec->read_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
-      ec->read_iovec.iod_iovec_s           = 1;
-      ec->read_iovec.iod_proc_nr           = mp->DL_PROC;
-      ec->read_iovec.iod_iovec_addr        = 0;
+  get_userdata_s(mp->DL_PROC, (vir_bytes) mp->DL_GRANT, 0,
+          (count > IOVEC_NR ? IOVEC_NR : count) *
+          sizeof(iovec_s_t), ec->read_iovec.iod_iovec);
+  ec->read_iovec.iod_iovec_s    = count;
+  ec->read_iovec.iod_proc_nr    = mp->DL_PROC;
+  ec->read_iovec.iod_grant = (vir_bytes) mp->DL_GRANT;
+  ec->read_iovec.iod_iovec_offset = 0;
+
+  ec->tmp_iovec = ec->read_iovec;
+  size= calc_iovec_size(&ec->tmp_iovec);
 
-      size= count;
-    }
   ec->flags |= ECF_READING;
 
   ec_recv(ec);
@@ -1195,12 +1185,11 @@ ether_card_t *ec;
 }
 
 /*===========================================================================*
- *                              do_vwrite                                    *
+ *                              do_vwrite_s                                  *
  *===========================================================================*/
-static void do_vwrite(mp, from_int, vectored)
+static void do_vwrite_s(mp, from_int)
 message *mp;
 int from_int;
-int vectored;
 {
   int port, count, check;
   ether_card_t *ec;
@@ -1221,30 +1210,17 @@ int vectored;
     }
 
   /* convert the message to write_iovec */
-  if (vectored)
-    {
-      get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-                   (count > IOVEC_NR ? IOVEC_NR : count) *
-                   sizeof(iovec_t), ec->write_iovec.iod_iovec);
+  get_userdata_s(mp->DL_PROC, mp->DL_GRANT, 0,
+          (count > IOVEC_NR ? IOVEC_NR : count) *
+          sizeof(iovec_s_t), ec->write_iovec.iod_iovec);
 
-      ec->write_iovec.iod_iovec_s    = count;
-      ec->write_iovec.iod_proc_nr    = mp->DL_PROC;
-      ec->write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
+  ec->write_iovec.iod_iovec_s    = count;
+  ec->write_iovec.iod_proc_nr    = mp->DL_PROC;
+  ec->write_iovec.iod_grant      = mp->DL_GRANT;
+  ec->write_iovec.iod_iovec_offset = 0;
 
-      ec->tmp_iovec = ec->write_iovec;
-      ec->write_s = calc_iovec_size(&ec->tmp_iovec);
-    }
-  else
-    {  
-      ec->write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
-      ec->write_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
-
-      ec->write_iovec.iod_iovec_s    = 1;
-      ec->write_iovec.iod_proc_nr    = mp->DL_PROC;
-      ec->write_iovec.iod_iovec_addr = 0;
-
-      ec->write_s = mp->DL_COUNT;
-    }
+  ec->tmp_iovec = ec->write_iovec;
+  ec->write_s = calc_iovec_size(&ec->tmp_iovec);
 
   /* copy write_iovec to the slot on DMA address */
   ec_user2nic(ec, &ec->write_iovec, 0,
@@ -1279,26 +1255,21 @@ int vectored;
 
 
 /*===========================================================================*
- *                              get_userdata                                 *
+ *                              get_userdata_s                               *
  *===========================================================================*/
-static void get_userdata(user_proc, user_addr, count, loc_addr)
+static void get_userdata_s(user_proc, grant, offset, count, loc_addr)
 int user_proc;
-vir_bytes user_addr;
+cp_grant_id_t grant;
+vir_bytes offset;
 vir_bytes count;
 void *loc_addr;
 {
-       /*
-  phys_bytes src;
-
-  src = numap_local(user_proc, user_addr, count);
-  if (!src)
-    panic( "lance", "umap failed", NO_NUM);
-
-  phys_copy(src, vir2phys(loc_addr), (phys_bytes) count);
-  */
        int cps;
-       cps = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes) loc_addr, count);
-       if (cps != OK) printf("lance: warning, scopy failed: %d\n", cps);
+       cps = sys_safecopyfrom(user_proc, grant, offset,
+               (vir_bytes)loc_addr, count, D);
+       if (cps != OK)
+               panic(__FILE__,
+                       "get_userdata_s: sys_safecopyfrom failed: %d\n", cps);
 }
 
 /*===========================================================================*
@@ -1311,12 +1282,8 @@ vir_bytes offset;
 int nic_addr;
 vir_bytes count;
 {
-  /*phys_bytes phys_hw, phys_user;*/
   int bytes, i, r;
 
-  /*
-  phys_hw = vir2phys(nic_addr);
-  */
   i= 0;
   while (count > 0)
     {
@@ -1336,15 +1303,10 @@ vir_bytes count;
       if (bytes > count)
         bytes = count;
       
-      /*
-      phys_user = numap_local(iovp->iod_proc_nr,
-                        iovp->iod_iovec[i].iov_addr + offset, bytes);
-      
-      phys_copy(phys_user, phys_hw, (phys_bytes) bytes);
-      */
-      if ( (r=sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr + offset,
-       SELF, nic_addr, count )) != OK )
-       panic( "lance", "sys_datacopy failed", r );
+      if ( (r=sys_safecopyfrom(iovp->iod_proc_nr,
+       iovp->iod_iovec[i].iov_grant, offset,
+       nic_addr, bytes, D )) != OK )
+       panic( __FILE__, "ec_user2nic: sys_safecopyfrom failed", r );
        
       count -= bytes;
       nic_addr += bytes;
@@ -1362,11 +1324,8 @@ iovec_dat_t *iovp;
 vir_bytes offset;
 vir_bytes count;
 {
-  /*phys_bytes phys_hw, phys_user;*/
   int bytes, i, r;
 
-  /*phys_hw = vir2phys(nic_addr);*/
-
   i= 0;
   while (count > 0)
     {
@@ -1385,14 +1344,9 @@ vir_bytes count;
       bytes = iovp->iod_iovec[i].iov_size - offset;
       if (bytes > count)
         bytes = count;
-      /*
-      phys_user = numap_local(iovp->iod_proc_nr,
-                        iovp->iod_iovec[i].iov_addr + offset, bytes);
-
-      phys_copy(phys_hw, phys_user, (phys_bytes) bytes);
-      */
-      if ( (r=sys_datacopy( SELF, nic_addr, iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr + offset, bytes )) != OK )
-       panic( "lance", "sys_datacopy failed: ", r );
+      if ( (r=sys_safecopyto( iovp->iod_proc_nr, iovp->iod_iovec[i].iov_grant,
+               offset, nic_addr, bytes, D )) != OK )
+       panic( __FILE__, "ec_nic2user: sys_safecopyto failed: ", r );
       
       count -= bytes;
       nic_addr += bytes;
@@ -1433,19 +1387,20 @@ static void ec_next_iovec(iovp)
 iovec_dat_t *iovp;
 {
   iovp->iod_iovec_s -= IOVEC_NR;
-  iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
+  iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_s_t);
 
-  get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr, 
+  get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, 
+               iovp->iod_iovec_offset,
                (iovp->iod_iovec_s > IOVEC_NR ? 
-                IOVEC_NR : iovp->iod_iovec_s) * sizeof(iovec_t), 
+                IOVEC_NR : iovp->iod_iovec_s) * sizeof(iovec_s_t), 
                iovp->iod_iovec); 
 }
 
 
 /*===========================================================================*
- *                              do_getstat                                   *
+ *                              do_getstat_s                                 *
  *===========================================================================*/
-static void do_getstat(mp)
+static void do_getstat_s(mp)
 message *mp;
 {
   int port;
@@ -1458,31 +1413,26 @@ message *mp;
   ec= &ec_table[port];
   ec->client= mp->DL_PROC;
 
-  put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-               (vir_bytes) sizeof(ec->eth_stat), &ec->eth_stat);
+  put_userdata_s(mp->DL_PROC, mp->DL_GRANT,
+               &ec->eth_stat, sizeof(ec->eth_stat));
   reply(ec, OK, FALSE);
 }
 
 /*===========================================================================*
- *                              put_userdata                                 *
+ *                              put_userdata_s                               *
  *===========================================================================*/
-static void put_userdata(user_proc, user_addr, count, loc_addr)
+static void put_userdata_s(user_proc, grant, loc_addr, count)
 int user_proc;
-vir_bytes user_addr;
-vir_bytes count;
+cp_grant_id_t grant;
 void *loc_addr;
+vir_bytes count;
 {
-  /*phys_bytes dst;
-
-  dst = numap_local(user_proc, user_addr, count);
-  if (!dst)
-    panic( "lance", "umap failed", NO_NUM);
-
-  phys_copy(vir2phys(loc_addr), dst, (phys_bytes) count);
-  */
        int cps;
-       cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
-       if (cps != OK) printf("lance: warning, scopy failed: %d\n", cps);
+       cps = sys_safecopyto(user_proc, grant, 0,
+               (vir_bytes) loc_addr, count, D);
+       if (cps != OK)
+               panic(__FILE__,
+                       "put_userdata_s: sys_safecopyto failed: %d\n", cps);
 }
 
 /*===========================================================================*
index f6b93ecdbbca4a8e997fe4135f7c874650956e56..8f6d00f9612ef71dc6a4d5552b845ed0f8cc47f2 100644 (file)
 #define IOVEC_NR        16
 typedef struct iovec_dat
 {
-  iovec_t iod_iovec[IOVEC_NR];
+  iovec_s_t iod_iovec[IOVEC_NR];
   int iod_iovec_s;
   int iod_proc_nr;
-  vir_bytes iod_iovec_addr;
+  cp_grant_id_t iod_grant;
+  vir_bytes iod_iovec_offset;
 } iovec_dat_t;
 
 #define ETH0_SELECTOR  0x61
index 2d7c81e8af999d24690fd225dcf125434ddcb48c..3944036e8f9cc22b13d669abe2ea9562ac4e3234 100755 (executable)
@@ -6,26 +6,30 @@
  *
  * The valid messages and their parameters are:
  *
- *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
- * |------------+----------+---------+----------+---------+---------|
- * | HARD_INT  |          |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READ   | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_READV  | port nr  | proc nr | count    |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_INIT   | port nr  | proc nr | mode     |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_GETSTAT        | port nr  | proc nr |          |         | address |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_GETNAME        |          |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
- * | DL_STOP   | port_nr  |         |          |         |         |
- * |------------|----------|---------|----------|---------|---------|
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR   DL_GRANT
+ * |------------+----------+---------+----------+---------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV_S| port nr  | proc nr | count    | mode    |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV_S        | port nr  | proc nr | count    |         |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_CONF   | port nr  | proc nr |          | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * |DL_GETSTAT_S| port nr  | proc nr |          |         |        |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
  *
  * The messages sent are:
  *
@@ -36,7 +40,7 @@
  *
  *   m_type      m3_i1     m3_i2       m3_ca1
  * |------------+---------+-----------+---------------|
- * |DL_INIT_REPL| port nr | last port | ethernet addr |
+ * |DL_CONF_REPL| port nr | last port | ethernet addr |
  * |------------|---------|-----------|---------------|
  *
  * Created:    Aug 2003 by Philip Homburg <philip@cs.vu.nl>
@@ -155,6 +159,7 @@ typedef struct re
        message re_tx_mess;
        char re_name[sizeof("rtl8139#n")];
        iovec_t re_iovec[IOVEC_NR];
+       iovec_s_t re_iovec_s[IOVEC_NR];
 }
 re_t;
 
@@ -238,8 +243,10 @@ _PROTOTYPE( static void rl_confaddr, (re_t *rep)                   );
 _PROTOTYPE( static void rl_rec_mode, (re_t *rep)                       );
 _PROTOTYPE( static void rl_readv, (message *mp, int from_int, 
                                                        int vectored)   );
+_PROTOTYPE( static void rl_readv_s, (message *mp, int from_int)        );
 _PROTOTYPE( static void rl_writev, (message *mp, int from_int,
                                                        int vectored)   );
+_PROTOTYPE( static void rl_writev_s, (message *mp, int from_int)       );
 _PROTOTYPE( static void rl_check_ints, (re_t *rep)                     );
 _PROTOTYPE( static void rl_report_link, (re_t *rep)                    );
 _PROTOTYPE( static void mii_print_techab, (U16_t techab)               );
@@ -248,11 +255,10 @@ _PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
 _PROTOTYPE( static void rl_clear_rx, (re_t *rep)                       );
 _PROTOTYPE( static void rl_do_reset, (re_t *rep)                       );
 _PROTOTYPE( static void rl_getstat, (message *mp)                      );
+_PROTOTYPE( static void rl_getstat_s, (message *mp)                    );
 _PROTOTYPE( static void rl_getname, (message *mp)                      );
 _PROTOTYPE( static void reply, (re_t *rep, int err, int may_block)     );
 _PROTOTYPE( static void mess_reply, (message *req, message *reply)     );
-_PROTOTYPE( static void put_userdata, (int user_proc,
-               vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
 _PROTOTYPE( static void rtl8139_stop, (void)                           );
 _PROTOTYPE( static void check_int_events, (void)                               );
 _PROTOTYPE( static int do_hard_int, (void)                             );
@@ -314,15 +320,16 @@ int main(int argc, char *argv[])
 
                switch (m.m_type)
                {
-               case DEV_PING: notify(m.m_source);              continue;
-               case DL_WRITEV: rl_writev(&m, FALSE, TRUE);     break;
+               case DEV_PING: notify(m.m_source);              break;
                case DL_WRITE:  rl_writev(&m, FALSE, FALSE);    break;
-#if 0
-               case DL_READ:   do_vread(&m, FALSE);            break;
-#endif
+               case DL_WRITEV: rl_writev(&m, FALSE, TRUE);     break;
+               case DL_WRITEV_S: rl_writev_s(&m, FALSE);       break;
+               case DL_READ:   rl_readv(&m, FALSE, FALSE);     break;
                case DL_READV:  rl_readv(&m, FALSE, TRUE);      break;
-               case DL_INIT:   rl_init(&m);                    break;
+               case DL_READV_S: rl_readv_s(&m, FALSE);         break;
+               case DL_CONF:   rl_init(&m);                    break;
                case DL_GETSTAT: rl_getstat(&m);                break;
+               case DL_GETSTAT_S: rl_getstat_s(&m);            break;
                case DL_GETNAME: rl_getname(&m);                break;
 #if 0
                case DL_STOP:   do_stop(&m);                    break;
@@ -490,7 +497,7 @@ message *mp;
        port = mp->DL_PORT;
        if (port < 0 || port >= RE_PORT_NR)
        {
-               reply_mess.m_type= DL_INIT_REPLY;
+               reply_mess.m_type= DL_CONF_REPLY;
                reply_mess.m3_i1= ENXIO;
                mess_reply(mp, &reply_mess);
                return;
@@ -503,7 +510,7 @@ message *mp;
                if (rep->re_mode == REM_DISABLED)
                {
                        /* Probe failed, or the device is configured off. */
-                       reply_mess.m_type= DL_INIT_REPLY;
+                       reply_mess.m_type= DL_CONF_REPLY;
                        reply_mess.m3_i1= ENXIO;
                        mess_reply(mp, &reply_mess);
                        return;
@@ -530,7 +537,7 @@ message *mp;
        rep->re_client = mp->m_source;
        rl_rec_mode(rep);
 
-       reply_mess.m_type = DL_INIT_REPLY;
+       reply_mess.m_type = DL_CONF_REPLY;
        reply_mess.m3_i1 = mp->DL_PORT;
        reply_mess.m3_i2 = RE_PORT_NR;
        *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
@@ -1058,14 +1065,6 @@ int vectored;
 
        rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
 
-#if DEAD_CODE
-       src_phys= rep->re_rx_buf + d_start;
-       cps = sys_physcopy(
-               NONE, PHYS_SEG, src_phys,
-               SELF, D, (vir_bytes) &rxstat, sizeof(rxstat));
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#endif
-
        if (rep->re_clear_rx)
        {
 #if 0
@@ -1113,11 +1112,6 @@ int vectored;
        if (vectored)
        {
                int iov_offset = 0;
-#if 0
-               if ((cps = sys_umap(re_client, D, (vir_bytes) mp->DL_ADDR,
-                       count * sizeof(rep->re_iovec[0]), &iov_src)) != OK)
-                       printf("sys_umap failed: %d\n", cps);
-#endif
 
                size= 0;
                o= d_start+4;
@@ -1129,15 +1123,15 @@ int vectored;
                        n= IOVEC_NR;
                        if (i+n > count)
                                n= count-i;
-#if 0
-                       cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec, 
+
+                       cps = sys_vircopy(re_client, D,
+                               (vir_bytes) mp->DL_ADDR + iov_offset,
+                               SELF, D, (vir_bytes) rep->re_iovec,
                                n * sizeof(rep->re_iovec[0]));
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#else
-                       cps = sys_vircopy(re_client, D, (vir_bytes) mp->DL_ADDR + iov_offset,
-                               SELF, D, (vir_bytes) rep->re_iovec, n * sizeof(rep->re_iovec[0]));
-       if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
-#endif
+                       if (cps != OK)
+                               printf(
+                       "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
+                                       cps, __LINE__);
 
                        for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
                        {
@@ -1148,11 +1142,6 @@ int vectored;
                                        s= packlen-size;
                                }
 
-#if 0
-                               if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
-                                 panic("rtl8139","umap_local failed\n", NO_NUM);
-#endif
-
                                if (o >= RX_BUFSIZE)
                                {
                                        o -= RX_BUFSIZE;
@@ -1164,30 +1153,33 @@ int vectored;
                                        assert(o<RX_BUFSIZE);
                                        s1= RX_BUFSIZE-o;
 
-#if 0
-                                       cps = sys_abscopy(src_phys+o, dst_phys, s1);
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-                                       cps = sys_abscopy(src_phys, dst_phys+s1, s-s1);
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#else
-                                       cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
-                                       re_client, D, iovp->iov_addr, s1);
-       if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
-                                       cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf,
-                                       re_client, D, iovp->iov_addr+s1, s-s1);
-       if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
-#endif
+                                       cps = sys_vircopy(SELF, D,
+                                               (vir_bytes) rep->v_re_rx_buf+o,
+                                               re_client, D, iovp->iov_addr,
+                                               s1);
+                                       if (cps != OK)
+                                               printf(
+                       "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
+                                                       cps, __LINE__);
+                                       cps = sys_vircopy(SELF, D,
+                                               (vir_bytes) rep->v_re_rx_buf,
+                                               re_client, D,
+                                               iovp->iov_addr+s1, s-s1);
+                                       if (cps != OK)
+                                               printf(
+                       "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
+                                                       cps, __LINE__);
                                }
                                else
                                {
-#if 0
-                                       cps = sys_abscopy(src_phys+o, dst_phys, s);
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#else
-                                       cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
-                                       re_client, D, iovp->iov_addr, s);
-       if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
-#endif
+                                       cps = sys_vircopy(SELF, D,
+                                               (vir_bytes) rep->v_re_rx_buf+o,
+                                               re_client, D, iovp->iov_addr,
+                                               s);
+                                       if (cps != OK)
+                                               printf(
+                       "RTL8139: warning, sys_vircopy failed: %d (%d)\n",
+                                                       cps, __LINE__);
                                }
 
                                size += s;
@@ -1217,145 +1209,367 @@ int vectored;
                cps = sys_abscopy(phys_user, p, size);
                if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
 #endif
-               }
+       }
 
-               if (rep->re_clear_rx)
-               {
-                       /* For some reason the receiver FIFO is not stopped when
-                        * the buffer is full.
-                        */
-       #if 0
-                       printf("rl_readv: later buffer overflow\n");
-       #endif
-                       goto suspend;   /* Buffer overflow */
-               }
+       if (rep->re_clear_rx)
+       {
+               /* For some reason the receiver FIFO is not stopped when
+                * the buffer is full.
+                */
+#if 0
+               printf("rl_readv: later buffer overflow\n");
+#endif
+               goto suspend;   /* Buffer overflow */
+       }
 
-               rep->re_stat.ets_packetR++;
-               rep->re_read_s= packlen;
-               rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
+       rep->re_stat.ets_packetR++;
+       rep->re_read_s= packlen;
+       rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
 
-               /* Avoid overflow in 16-bit computations */
-               l= d_start;
-               l += totlen+4;
-               l= (l+3) & ~3;  /* align */
-               if (l >= RX_BUFSIZE)
-               {
-                       l -= RX_BUFSIZE;
-                       assert(l < RX_BUFSIZE);
-               }
-               rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
+       /* Avoid overflow in 16-bit computations */
+       l= d_start;
+       l += totlen+4;
+       l= (l+3) & ~3;  /* align */
+       if (l >= RX_BUFSIZE)
+       {
+               l -= RX_BUFSIZE;
+               assert(l < RX_BUFSIZE);
+       }
+       rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
 
-               if (!from_int)
-                       reply(rep, OK, FALSE);
+       if (!from_int)
+               reply(rep, OK, FALSE);
 
+       return;
+
+suspend:
+       if (from_int)
+       {
+               assert(rep->re_flags & REF_READING);
+
+               /* No need to store any state */
                return;
+       }
 
-       suspend:
-               if (from_int)
-               {
-                       assert(rep->re_flags & REF_READING);
+       rep->re_rx_mess= *mp;
+       assert(!(rep->re_flags & REF_READING));
+       rep->re_flags |= REF_READING;
 
-                       /* No need to store any state */
-                       return;
-               }
+       reply(rep, OK, FALSE);
+}
 
-               rep->re_rx_mess= *mp;
-               assert(!(rep->re_flags & REF_READING));
-               rep->re_flags |= REF_READING;
+/*===========================================================================*
+ *                             rl_readv_s                                   *
+ *===========================================================================*/
+static void rl_readv_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       int i, j, n, o, s, s1, dl_port, re_client, count, size;
+       port_t port;
+       unsigned amount, totlen, packlen;
+       phys_bytes src_phys, dst_phys, iov_src;
+       u16_t d_start, d_end;
+       u32_t l, rxstat = 0x12345678;
+       re_t *rep;
+       iovec_s_t *iovp;
+       int cps;
+       int iov_offset = 0;
 
-               reply(rep, OK, FALSE);
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= RE_PORT_NR)
+               panic("rtl8139"," illegal port", dl_port);
+       rep= &re_table[dl_port];
+       re_client= mp->DL_PROC;
+       rep->re_client= re_client;
+
+       if (rep->re_clear_rx)
+               goto suspend;   /* Buffer overflow */
+
+       assert(rep->re_mode == REM_ENABLED);
+       assert(rep->re_flags & REF_ENABLED);
+
+       port= rep->re_base_port;
+
+       /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
+        */
+       if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
+       {
+               /* Receive buffer is empty, suspend */
+               goto suspend;
        }
 
-       /*===========================================================================*
-        *                              rl_writev                                    *
-        *===========================================================================*/
-       static void rl_writev(mp, from_int, vectored)
-       message *mp;
-       int from_int;
-       int vectored;
-       {
-               phys_bytes p, iov_src, phys_user;
-               int i, j, n, s, port, count, size;
-               int tx_head, re_client;
-               re_t *rep;
-               iovec_t *iovp;
-               char *ret;
-               int cps;
-
-               port = mp->DL_PORT;
-               count = mp->DL_COUNT;
-               if (port < 0 || port >= RE_PORT_NR)
-                       panic("rtl8139","illegal port", port);
-               rep= &re_table[port];
-               re_client= mp->DL_PROC;
-               rep->re_client= re_client;
-
-               assert(rep->re_mode == REM_ENABLED);
-               assert(rep->re_flags & REF_ENABLED);
-
-               if (from_int)
-               {
-                       assert(rep->re_flags & REF_SEND_AVAIL);
-                       rep->re_flags &= ~REF_SEND_AVAIL;
-                       rep->re_send_int= FALSE;
-                       rep->re_tx_alive= TRUE;
-               }
+       d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
+       d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
 
-               tx_head= rep->re_tx_head;
-               if (rep->re_tx[tx_head].ret_busy)
+       if (d_start >= RX_BUFSIZE)
+       {
+               printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
+                       rl_inw(port, RL_CAPR));
+               d_start %= RX_BUFSIZE;
+       }
+
+       if (d_end > d_start)
+               amount= d_end-d_start;
+       else
+               amount= d_end+RX_BUFSIZE - d_start;
+
+       rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
+
+       if (rep->re_clear_rx)
+       {
+#if 0
+               printf("rl_readv: late buffer overflow\n");
+#endif
+               goto suspend;   /* Buffer overflow */
+       }
+
+       /* Should convert from little endian to host byte order */
+
+       if (!(rxstat & RL_RXS_ROK))
+       {
+               printf("rxstat = 0x%08lx\n", rxstat);
+               printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
+                       d_start, d_end, rxstat);
+               panic("rtl8139","received packet not OK", NO_NUM);
+       }
+       totlen= (rxstat >> RL_RXS_LEN_S);
+       if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
+       {
+               /* Someting went wrong */
+               printf(
+               "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
+                       totlen, rxstat, d_start);
+               printf(
+               "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
+                       d_start, d_end, totlen, rxstat);
+               panic(NULL, NULL, NO_NUM);
+       }
+
+#if 0
+       printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
+               d_start, d_end, totlen, rxstat);
+#endif
+
+       if (totlen+4 > amount)
+       {
+               printf("rl_readv: packet not yet ready\n");
+               goto suspend;
+       }
+
+       /* Should subtract the CRC */
+       packlen= totlen - ETH_CRC_SIZE;
+
+       size= 0;
+       o= d_start+4;
+       src_phys= rep->re_rx_buf;
+       for (i= 0; i<count; i += IOVEC_NR,
+               iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]),
+               iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
+       {
+               n= IOVEC_NR;
+               if (i+n > count)
+                       n= count-i;
+
+               cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
+                       (vir_bytes) rep->re_iovec_s,
+                       n * sizeof(rep->re_iovec_s[0]), D);
+               if (cps != OK)
                {
-                       assert(!(rep->re_flags & REF_SEND_AVAIL));
-                       rep->re_flags |= REF_SEND_AVAIL;
-                       if (rep->re_tx[tx_head].ret_busy)
-                               goto suspend;
-
-                       /* Race condition, the interrupt handler may clear re_busy
-                        * before we got a chance to set REF_SEND_AVAIL. Checking
-                        * ret_busy twice should be sufficient.
-                        */
-       #if 0
-                       printf("rl_writev: race detected\n");
-       #endif
-                       rep->re_flags &= ~REF_SEND_AVAIL;
-                       rep->re_send_int= FALSE;
+                       panic(__FILE__, "rl_readv_s: sys_safecopyfrom failed",
+                               cps);
                }
 
-               assert(!(rep->re_flags & REF_SEND_AVAIL));
-               assert(!(rep->re_flags & REF_PACK_SENT));
-
-               if (vectored)
+               for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
                {
-                       int iov_offset = 0;
+                       s= iovp->iov_size;
+                       if (size + s > packlen)
+                       {
+                               assert(packlen > size);
+                               s= packlen-size;
+                       }
 
 #if 0
-                       if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR,
-                               count * sizeof(rep->re_iovec[0]), &iov_src))
-                               panic("rtl8139","umap_local failed", NO_NUM);
+                       if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
+                         panic("rtl8139","umap_local failed\n", NO_NUM);
 #endif
 
-                       size= 0;
+                       if (o >= RX_BUFSIZE)
+                       {
+                               o -= RX_BUFSIZE;
+                               assert(o < RX_BUFSIZE);
+                       }
+
+                       if (o+s > RX_BUFSIZE)
+                       {
+                               assert(o<RX_BUFSIZE);
+                               s1= RX_BUFSIZE-o;
+
+                               cps = sys_safecopyto(re_client,
+                                       iovp->iov_grant, 0, 
+                                       (vir_bytes) rep->v_re_rx_buf+o, s1, D);
+                               if (cps != OK)
+                               {
+                                       panic(__FILE__,
+                                       "rl_readv_s: sys_safecopyto failed",
+                                               cps);
+                               }
+                               cps = sys_safecopyto(re_client,
+                                       iovp->iov_grant, s1, 
+                                       (vir_bytes) rep->v_re_rx_buf, s-s1, S);
+                               if (cps != OK)
+                               {
+                                       panic(__FILE__,
+                                       "rl_readv_s: sys_safecopyto failed",
+                                               cps);
+                               }
+                       }
+                       else
+                       {
+                               cps = sys_safecopyto(re_client,
+                                       iovp->iov_grant, 0,
+                                       (vir_bytes) rep->v_re_rx_buf+o, s, D);
+                               if (cps != OK)
+                                       panic(__FILE__,
+                                       "rl_readv_s: sys_vircopy failed",
+                                               cps);
+                       }
+
+                       size += s;
+                       if (size == packlen)
+                               break;
+                       o += s;
+               }
+               if (size == packlen)
+                       break;
+       }
+       if (size < packlen)
+       {
+               assert(0);
+       }
+
+       if (rep->re_clear_rx)
+       {
+               /* For some reason the receiver FIFO is not stopped when
+                * the buffer is full.
+                */
 #if 0
-                       p= rep->re_tx[tx_head].ret_buf;
-#else
-                       ret = rep->re_tx[tx_head].v_ret_buf;
+               printf("rl_readv: later buffer overflow\n");
 #endif
-                       for (i= 0; i<count; i += IOVEC_NR,
-                               iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
-                               iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
-                       {
-                               n= IOVEC_NR;
-                               if (i+n > count)
-                                       n= count-i;
+               goto suspend;   /* Buffer overflow */
+       }
+
+       rep->re_stat.ets_packetR++;
+       rep->re_read_s= packlen;
+       rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
+
+       /* Avoid overflow in 16-bit computations */
+       l= d_start;
+       l += totlen+4;
+       l= (l+3) & ~3;  /* align */
+       if (l >= RX_BUFSIZE)
+       {
+               l -= RX_BUFSIZE;
+               assert(l < RX_BUFSIZE);
+       }
+       rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
+
+       if (!from_int)
+               reply(rep, OK, FALSE);
+
+       return;
+
+suspend:
+       if (from_int)
+       {
+               assert(rep->re_flags & REF_READING);
+
+               /* No need to store any state */
+               return;
+       }
+
+       rep->re_rx_mess= *mp;
+       assert(!(rep->re_flags & REF_READING));
+       rep->re_flags |= REF_READING;
+
+       reply(rep, OK, FALSE);
+}
+
+/*===========================================================================*
+ *                             rl_writev                                    *
+ *===========================================================================*/
+static void rl_writev(mp, from_int, vectored)
+message *mp;
+int from_int;
+int vectored;
+{
+       phys_bytes iov_src, phys_user;
+       int i, j, n, s, port, count, size;
+       int tx_head, re_client;
+       re_t *rep;
+       iovec_t *iovp;
+       char *ret;
+       int cps;
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= RE_PORT_NR)
+               panic("rtl8139","illegal port", port);
+       rep= &re_table[port];
+       re_client= mp->DL_PROC;
+       rep->re_client= re_client;
+
+       assert(rep->re_mode == REM_ENABLED);
+       assert(rep->re_flags & REF_ENABLED);
+
+       if (from_int)
+       {
+               assert(rep->re_flags & REF_SEND_AVAIL);
+               rep->re_flags &= ~REF_SEND_AVAIL;
+               rep->re_send_int= FALSE;
+               rep->re_tx_alive= TRUE;
+       }
+
+       tx_head= rep->re_tx_head;
+       if (rep->re_tx[tx_head].ret_busy)
+       {
+               assert(!(rep->re_flags & REF_SEND_AVAIL));
+               rep->re_flags |= REF_SEND_AVAIL;
+               if (rep->re_tx[tx_head].ret_busy)
+                       goto suspend;
+
+               /* Race condition, the interrupt handler may clear re_busy
+                * before we got a chance to set REF_SEND_AVAIL. Checking
+                * ret_busy twice should be sufficient.
+                */
 #if 0
-                               cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec, 
-                                       n * sizeof(rep->re_iovec[0]));
-               if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#else
-                               cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
-                                       SELF, D, (vir_bytes) rep->re_iovec, 
-                                       n * sizeof(rep->re_iovec[0]));
-       if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
+               printf("rl_writev: race detected\n");
 #endif
+               rep->re_flags &= ~REF_SEND_AVAIL;
+               rep->re_send_int= FALSE;
+       }
+
+       assert(!(rep->re_flags & REF_SEND_AVAIL));
+       assert(!(rep->re_flags & REF_PACK_SENT));
+
+       if (vectored)
+       {
+               int iov_offset = 0;
+
+               size= 0;
+               ret = rep->re_tx[tx_head].v_ret_buf;
+               for (i= 0; i<count; i += IOVEC_NR,
+                       iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
+                       iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
+               {
+                       n= IOVEC_NR;
+                       if (i+n > count)
+                               n= count-i;
+                       cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
+                               SELF, D, (vir_bytes) rep->re_iovec, 
+                               n * sizeof(rep->re_iovec[0]));
+if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
 
                        for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
                        {
@@ -1369,18 +1583,10 @@ int vectored;
                                if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
                                  panic("rtl8139","umap_local failed\n", NO_NUM);
 
-#if 0
-                               cps = sys_abscopy(phys_user, p, s);
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#else
                                cps = sys_vircopy(re_client, D, iovp->iov_addr,
                                        SELF, D, (vir_bytes) ret, s);
                if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
-#endif
                                size += s;
-#if 0
-                               p += s;
-#endif
                                ret += s;
                        }
                }
@@ -1392,20 +1598,148 @@ int vectored;
                size= mp->DL_COUNT;
                if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
                        panic("rtl8139","invalid packet size", size);
-#if 0
-               if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
-                       panic("rtl8139","umap_local failed\n", NO_NUM);
-
-               p= rep->re_tx[tx_head].ret_buf;
-               cps = sys_abscopy(phys_user, p, size);
-       if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
-#else
                ret = rep->re_tx[tx_head].v_ret_buf;
                cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR, 
                        SELF, D, (vir_bytes) ret, size);
        if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
+       }
+
+       rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, 
+               rep->re_ertxth | size);
+       rep->re_tx[tx_head].ret_busy= TRUE;
+
+       if (++tx_head == N_TX_BUF)
+               tx_head= 0;
+       assert(tx_head < RL_N_TX);
+       rep->re_tx_head= tx_head;
+
+       rep->re_flags |= REF_PACK_SENT;
+
+       /* If the interrupt handler called, don't send a reply. The reply
+        * will be sent after all interrupts are handled. 
+        */
+       if (from_int)
+               return;
+       reply(rep, OK, FALSE);
+       return;
+
+suspend:
+#if 0
+               printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
+                       tx_head, rep->re_tx_tail,
+                       rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
+                       rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
+               printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
+                       rl_inl(rep->re_base_port, RL_TSD0+0*4),
+                       rl_inl(rep->re_base_port, RL_TSD0+1*4),
+                       rl_inl(rep->re_base_port, RL_TSD0+2*4),
+                       rl_inl(rep->re_base_port, RL_TSD0+3*4));
+#endif
+
+       if (from_int)
+               panic("rtl8139","should not be sending\n", NO_NUM);
+
+       rep->re_tx_mess= *mp;
+       reply(rep, OK, FALSE);
+}
+
+/*===========================================================================*
+ *                             rl_writev_s                                  *
+ *===========================================================================*/
+static void rl_writev_s(mp, from_int)
+message *mp;
+int from_int;
+{
+       phys_bytes iov_src;
+       int i, j, n, s, port, count, size;
+       int tx_head, re_client;
+       re_t *rep;
+       iovec_s_t *iovp;
+       char *ret;
+       int cps;
+       int iov_offset = 0;
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= RE_PORT_NR)
+               panic("rtl8139","illegal port", port);
+       rep= &re_table[port];
+       re_client= mp->DL_PROC;
+       rep->re_client= re_client;
+
+       assert(rep->re_mode == REM_ENABLED);
+       assert(rep->re_flags & REF_ENABLED);
+
+       if (from_int)
+       {
+               assert(rep->re_flags & REF_SEND_AVAIL);
+               rep->re_flags &= ~REF_SEND_AVAIL;
+               rep->re_send_int= FALSE;
+               rep->re_tx_alive= TRUE;
+       }
+
+       tx_head= rep->re_tx_head;
+       if (rep->re_tx[tx_head].ret_busy)
+       {
+               assert(!(rep->re_flags & REF_SEND_AVAIL));
+               rep->re_flags |= REF_SEND_AVAIL;
+               if (rep->re_tx[tx_head].ret_busy)
+                       goto suspend;
+
+               /* Race condition, the interrupt handler may clear re_busy
+                * before we got a chance to set REF_SEND_AVAIL. Checking
+                * ret_busy twice should be sufficient.
+                */
+#if 0
+               printf("rl_writev: race detected\n");
 #endif
+               rep->re_flags &= ~REF_SEND_AVAIL;
+               rep->re_send_int= FALSE;
+       }
+
+       assert(!(rep->re_flags & REF_SEND_AVAIL));
+       assert(!(rep->re_flags & REF_PACK_SENT));
+
+       size= 0;
+       ret = rep->re_tx[tx_head].v_ret_buf;
+       for (i= 0; i<count; i += IOVEC_NR,
+               iov_src += IOVEC_NR * sizeof(rep->re_iovec_s[0]),
+               iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0]))
+       {
+               n= IOVEC_NR;
+               if (i+n > count)
+                       n= count-i;
+               cps = sys_safecopyfrom(re_client, mp->DL_GRANT, iov_offset,
+                       (vir_bytes) rep->re_iovec_s,
+                       n * sizeof(rep->re_iovec_s[0]), D);
+               if (cps != OK)
+               {
+                       panic(__FILE__, "rl_writev_s: sys_safecopyfrom failed",
+                               cps);
+               }
+
+               for (j= 0, iovp= rep->re_iovec_s; j<n; j++, iovp++)
+               {
+                       s= iovp->iov_size;
+                       if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
+                       {
+                         panic("rtl8139","invalid packet size",
+                           NO_NUM);
+                       }
+                       cps = sys_safecopyfrom(re_client, iovp->iov_grant, 0,
+                               (vir_bytes) ret, s, D);
+                       if (cps != OK)
+                       {
+                               panic(__FILE__,
+                                       "rl_writev_s: sys_safecopyfrom failed",
+                                       cps);
+                       }
+                       size += s;
+                       ret += s;
+               }
        }
+       if (size < ETH_MIN_PACK_SIZE)
+               panic("rtl8139","invalid packet size", size);
 
        rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, 
                rep->re_ertxth | size);
@@ -1503,6 +1837,10 @@ re_t *rep;
                        rl_readv(&rep->re_rx_mess, TRUE /* from int */,
                                TRUE /* vectored */);
                }
+               else if (rep->re_rx_mess.m_type == DL_READV_S)
+               {
+                       rl_readv_s(&rep->re_rx_mess, TRUE /* from int */);
+               }
                else
                {
                        assert(rep->re_rx_mess.m_type == DL_READ);
@@ -1898,7 +2236,7 @@ re_t *rep;
 static void rl_getstat(mp)
 message *mp;
 {
-       int port;
+       int r, port;
        eth_stat_t stats;
        re_t *rep;
 
@@ -1913,8 +2251,38 @@ message *mp;
 
        stats= rep->re_stat;
 
-       put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-               (vir_bytes) sizeof(stats), &stats);
+       r = sys_datacopy(SELF, (vir_bytes) &stats, mp->DL_PROC,
+               (vir_bytes) mp->DL_ADDR, sizeof(stats));
+       if (r != OK)
+               panic(__FILE__, "rl_getstat: sys_datacopy failed", r);
+       reply(rep, OK, FALSE);
+}
+
+/*===========================================================================*
+ *                             rl_getstat_s                                 *
+ *===========================================================================*/
+static void rl_getstat_s(mp)
+message *mp;
+{
+       int r, port;
+       eth_stat_t stats;
+       re_t *rep;
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= RE_PORT_NR)
+               panic("rtl8139","illegal port", port);
+       rep= &re_table[port];
+       rep->re_client= mp->DL_PROC;
+
+       assert(rep->re_mode == REM_ENABLED);
+       assert(rep->re_flags & REF_ENABLED);
+
+       stats= rep->re_stat;
+
+       r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0,
+               (vir_bytes) &stats, sizeof(stats), D);
+       if (r != OK)
+               panic(__FILE__, "rl_getstat_s: sys_safecopyto failed", r);
        reply(rep, OK, FALSE);
 }
 
@@ -1994,20 +2362,6 @@ message *reply_mess;
                panic("rtl8139","unable to mess_reply", NO_NUM);
 }
 
-/*===========================================================================*
- *                             put_userdata                                 *
- *===========================================================================*/
-static void put_userdata(user_proc, user_addr, count, loc_addr)
-int user_proc;
-vir_bytes user_addr;
-vir_bytes count;
-void *loc_addr;
-{
-       int cps;
-       cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
-       if (cps != OK) printf("RTL8139: warning, scopy failed: %d\n", cps);
-}
-
 #if 0
 static void dump_phy(rep)
 re_t *rep;