FORWARD _PROTOTYPE( void setup_read, (eth_port_t *eth_port) );
FORWARD _PROTOTYPE( void read_int, (eth_port_t *eth_port, int count) );
+FORWARD _PROTOTYPE( void eth_issue_send, (eth_port_t *eth_port) );
FORWARD _PROTOTYPE( void write_int, (eth_port_t *eth_port) );
FORWARD _PROTOTYPE( void eth_recvev, (event_t *ev, ev_arg_t ev_arg) );
FORWARD _PROTOTYPE( void eth_sendev, (event_t *ev, ev_arg_t ev_arg) );
FORWARD _PROTOTYPE( eth_port_t *find_port, (message *m) );
FORWARD _PROTOTYPE( void eth_restart, (eth_port_t *eth_port, int tasknr) );
+FORWARD _PROTOTYPE( void send_getstat, (eth_port_t *eth_port) );
+
+FORWARD _PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) );
PUBLIC void osdep_eth_init()
{
eth_port->etp_osdep.etp_rd_iovec[j].iov_grant= -1;
eth_port->etp_osdep.etp_rd_vec_grant= -1;
+ eth_port->etp_osdep.etp_state= OEPS_INIT;
+ eth_port->etp_osdep.etp_flags= OEPF_EMPTY;
+ eth_port->etp_osdep.etp_stat_gid= -1;
+ eth_port->etp_osdep.etp_stat_buf= NULL;
+
if (eth_is_vlan(ecp))
continue;
r= ENXIO;
else
{
- r= send(eth_port->etp_osdep.etp_task, &mess);
- if (r<0)
+ assert(eth_port->etp_osdep.etp_state == OEPS_INIT);
+ r= asynsend(eth_port->etp_osdep.etp_task, &mess);
+ if (r == OK)
+ eth_port->etp_osdep.etp_state= OEPS_CONF_SENT;
+ else
{
printf(
"osdep_eth_init: unable to send to ethernet task, error= %d\n",
}
}
- if (r == OK)
- {
- r= receive(eth_port->etp_osdep.etp_task, &mess);
- if (r<0)
- {
- printf(
- "osdep_eth_init: unable to receive from ethernet task, error= %d\n",
- r);
- }
- }
-
- if (r == OK)
- {
- r= mess.m3_i1;
- if (r == ENXIO)
- {
- printf(
- "osdep_eth_init: no ethernet device at task=%d,port=%d\n",
- eth_port->etp_osdep.etp_task,
- eth_port->etp_osdep.etp_port);
- }
- else if (r < 0)
- {
- ip_panic((
- "osdep_eth_init: DL_INIT returned error %d\n",
- r));
- }
- else if (mess.m3_i1 != eth_port->etp_osdep.etp_port)
- {
- ip_panic((
- "osdep_eth_init: got reply for wrong port (got %d, expected %d)\n",
- mess.m3_i1,
- eth_port->etp_osdep.etp_port));
- }
- }
+ r= ENXIO;
sr_add_minor(if2minor(ecp->ec_ifno, ETH_DEV_OFF),
i, eth_open, eth_close, eth_read,
if (r == OK)
{
eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1;
+ printf("osdep_eth_init: setting EPF_GOT_ADDR\n");
eth_port->etp_flags |= EPF_GOT_ADDR;
setup_read (eth_port);
}
if (rep->etp_flags & EPF_GOT_ADDR)
{
eth_port->etp_ethaddr= rep->etp_ethaddr;
+ printf("osdep_eth_init: setting EPF_GOT_ADDR\n");
eth_port->etp_flags |= EPF_GOT_ADDR;
}
{
eth_port_t *loc_port;
message mess1, block_msg;
- int i, pack_size;
- acc_t *pack_ptr;
- iovec_s_t *iovec;
u8_t *eth_dst_ptr;
int multicast, r;
ev_arg_t ev_arg;
assert(eth_port->etp_wr_pack == NULL);
eth_port->etp_wr_pack= pack;
- iovec= eth_port->etp_osdep.etp_wr_iovec;
- pack_size= 0;
- for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr; i++,
- pack_ptr= pack_ptr->acc_next)
+ if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
{
- r= cpf_setgrant_direct(iovec[i].iov_grant,
- eth_port->etp_osdep.etp_task,
- (vir_bytes)ptr2acc_data(pack_ptr),
- (vir_bytes)pack_ptr->acc_length,
- CPF_READ);
- if (r != 0)
- {
- ip_panic((
- "eth_write_port: cpf_setgrant_direct failed: %d\n",
- errno));
- }
- pack_size += iovec[i].iov_size= pack_ptr->acc_length;
+ eth_port->etp_osdep.etp_flags |= OEPF_NEED_SEND;
+ return;
}
- if (i>= IOVEC_NR)
+
+
+ eth_issue_send(eth_port);
+}
+
+PRIVATE int notification_count;
+
+PUBLIC void eth_rec(m)
+message *m;
+{
+ int i, r, m_type, stat;
+ eth_port_t *loc_port, *vlan_port;
+ char *drivername;
+ struct eth_conf *ecp;
+
+ m_type= m->m_type;
+ if (m_type == DL_NAME_REPLY)
{
- pack= bf_pack(pack); /* packet is too fragmented */
- eth_port->etp_wr_pack= pack;
- pack_size= 0;
- for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr;
- i++, pack_ptr= pack_ptr->acc_next)
+ drivername= m->m3_ca1;
+ printf("eth_rec: got name: %s\n", drivername);
+
+ notification_count= 0;
+
+ /* Re-init ethernet interfaces */
+ for (i= 0, ecp= eth_conf, loc_port= eth_port_table;
+ i<eth_conf_nr; i++, ecp++, loc_port++)
{
- r= cpf_setgrant_direct(iovec[i].iov_grant,
- eth_port->etp_osdep.etp_task,
- (vir_bytes)ptr2acc_data(pack_ptr),
- (vir_bytes)pack_ptr->acc_length,
- CPF_READ);
- if (r != 0)
+ if (eth_is_vlan(ecp))
+ continue;
+
+ if (strcmp(ecp->ec_task, drivername) != 0)
{
- ip_panic((
- "eth_write_port: cpf_setgrant_direct failed: %d\n",
- errno));
+ /* Wrong driver */
+ continue;
}
- pack_size += iovec[i].iov_size= pack_ptr->acc_length;
+ eth_restart(loc_port, m->m_source);
}
+ return;
}
- assert (i< IOVEC_NR);
- assert (pack_size >= ETH_MIN_PACK_SIZE);
+ assert(m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY ||
+ m_type == DL_STAT_REPLY);
- r= cpf_setgrant_direct(eth_port->etp_osdep.etp_wr_vec_grant,
- eth_port->etp_osdep.etp_task,
- (vir_bytes)iovec,
- (vir_bytes)(i * sizeof(iovec[0])),
- CPF_READ);
- if (r != 0)
+ for (i=0, loc_port= eth_port_table; i<eth_conf_nr; i++, loc_port++)
{
- ip_panic((
- "eth_write_port: cpf_setgrant_direct failed: %d\n",
- errno));
+ if (loc_port->etp_osdep.etp_port == m->DL_PORT &&
+ loc_port->etp_osdep.etp_task == m->m_source)
+ break;
+ }
+ if (i >= eth_conf_nr)
+ {
+ printf("eth_rec: bad port %d in message type 0x%x from %d\n",
+ m->DL_PORT, m_type, m->m_source);
+ return;
}
- mess1.DL_COUNT= i;
- mess1.DL_GRANT= eth_port->etp_osdep.etp_wr_vec_grant;
- mess1.m_type= DL_WRITEV_S;
-
- mess1.DL_PORT= eth_port->etp_osdep.etp_port;
- mess1.DL_PROC= this_proc;
- mess1.DL_MODE= DL_NOMODE;
- for (;;)
+ if (loc_port->etp_osdep.etp_state == OEPS_CONF_SENT)
{
- r= sendrec(eth_port->etp_osdep.etp_task, &mess1);
- if (r != ELOCKED)
- break;
+ if (m_type == DL_TASK_REPLY)
+ {
+ stat= m->DL_STAT & 0xffff;
- /* ethernet task is sending to this task, I hope */
- r= receive(eth_port->etp_osdep.etp_task, &block_msg);
- if (r < 0)
- ip_panic(("unable to receive"));
+ if (stat & DL_PACK_SEND)
+ write_int(loc_port);
+ if (stat & DL_PACK_RECV)
+ read_int(loc_port, m->DL_COUNT);
+ return;
+ }
- loc_port= eth_port;
- if (loc_port->etp_osdep.etp_port != block_msg.DL_PORT ||
- loc_port->etp_osdep.etp_task != block_msg.m_source)
+ if (m_type != DL_CONF_REPLY)
{
- loc_port= find_port(&block_msg);
+ printf(
+ "eth_rec: got bad message type 0x%x from %d in CONF state\n",
+ m_type, m->m_source);
+ return;
}
- assert(block_msg.DL_STAT & (DL_PACK_SEND|DL_PACK_RECV));
- if (block_msg.DL_STAT & DL_PACK_SEND)
+
+ r= m->m3_i1;
+ if (r == ENXIO)
+ {
+ printf(
+ "eth_rec(conf_reply): no ethernet device at task=%d,port=%d\n",
+ loc_port->etp_osdep.etp_task,
+ loc_port->etp_osdep.etp_port);
+ return;
+ }
+ if (r < 0)
{
- assert(loc_port != eth_port);
- loc_port->etp_osdep.etp_sendrepl= block_msg;
- ev_arg.ev_ptr= loc_port;
- assert(!loc_port->etp_osdep.etp_send_ev);
- loc_port->etp_osdep.etp_send_ev= 1;
- ev_enqueue(&loc_port->etp_sendev, eth_sendev, ev_arg);
+ ip_panic(("eth_rec: DL_INIT returned error %d\n", r));
+ return;
}
- if (block_msg.DL_STAT & DL_PACK_RECV)
+
+ loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_CONF;
+ loc_port->etp_osdep.etp_state= OEPS_IDLE;
+ loc_port->etp_flags |= EPF_ENABLED;
+
+ loc_port->etp_ethaddr= *(ether_addr_t *)m->m3_ca1;
+ if (!(loc_port->etp_flags & EPF_GOT_ADDR))
{
- if (recv_debug)
+ loc_port->etp_flags |= EPF_GOT_ADDR;
+ printf("eth_rec: calling eth_restart_ioctl\n");
+ eth_restart_ioctl(loc_port);
+
+ /* Also update any VLANs on this device */
+ for (i=0, vlan_port= eth_port_table; i<eth_conf_nr;
+ i++, vlan_port++)
{
- printf(
- "eth_write_port(block_msg): eth%d got DL_PACK_RECV\n",
- loc_port-eth_port_table);
+ if (!(vlan_port->etp_flags & EPF_ENABLED))
+ continue;
+ if (vlan_port->etp_vlan_port != loc_port)
+ continue;
+
+ vlan_port->etp_ethaddr= loc_port->etp_ethaddr;
+ vlan_port->etp_flags |= EPF_GOT_ADDR;
+ eth_restart_ioctl(vlan_port);
}
- loc_port->etp_osdep.etp_recvrepl= block_msg;
- ev_arg.ev_ptr= loc_port;
- ev_enqueue(&loc_port->etp_osdep.etp_recvev,
- eth_recvev, ev_arg);
}
- }
+ if (!(loc_port->etp_flags & EPF_READ_IP))
+ setup_read (loc_port);
- if (r < 0)
- {
- printf("eth_write_port: sendrec to %d failed: %d\n",
- eth_port->etp_osdep.etp_task, r);
- return;
- }
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND)
+ {
+ printf("eth_rec(conf): OEPF_NEED_SEND is set\n");
+ }
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV)
+ {
+ printf("eth_rec(conf): OEPF_NEED_RECV is set\n");
+ }
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT)
+ {
+ printf("eth_rec(conf): OEPF_NEED_STAT is set\n");
+ }
- if (mess1.m_type != DL_TASK_REPLY ||
- mess1.DL_PORT != eth_port->etp_osdep.etp_port ||
- mess1.DL_PROC != this_proc)
- {
- printf(
-"eth_write_port: ignoring bad message (type = 0x%x, port = %d, proc = %d) from %d\n",
- mess1.m_type, mess1.DL_PORT, mess1.DL_PROC,
- mess1.m_source);
return;
}
-
- assert(mess1.m_type == DL_TASK_REPLY &&
- mess1.DL_PORT == eth_port->etp_osdep.etp_port &&
- mess1.DL_PROC == this_proc);
- assert((mess1.DL_STAT >> 16) == OK);
-
- if (mess1.DL_STAT & DL_PACK_RECV)
+ if (loc_port->etp_osdep.etp_state == OEPS_GETSTAT_SENT)
{
- if (recv_debug)
+ if (m_type != DL_STAT_REPLY)
{
printf(
- "eth_write_port(mess1): eth%d got DL_PACK_RECV\n",
- mess1.DL_PORT);
+ "eth_rec: got bad message type 0x%x from %d in GETSTAT state\n",
+ m_type, m->m_source);
+ return;
}
- eth_port->etp_osdep.etp_recvrepl= mess1;
- ev_arg.ev_ptr= eth_port;
- ev_enqueue(ð_port->etp_osdep.etp_recvev, eth_recvev,
- ev_arg);
- }
- if (!(mess1.DL_STAT & DL_PACK_SEND))
- {
- /* Packet is not yet sent. */
- return;
- }
- /* If the port is in promiscuous mode or the packet is
- * broad- or multicast, enqueue the reply packet.
- */
- eth_dst_ptr= (u8_t *)ptr2acc_data(pack);
- multicast= (*eth_dst_ptr & 1); /* low order bit indicates multicast */
- if (multicast || (eth_port->etp_osdep.etp_recvconf & NWEO_EN_PROMISC))
- {
- eth_port->etp_osdep.etp_sendrepl= mess1;
- ev_arg.ev_ptr= eth_port;
- assert(!eth_port->etp_osdep.etp_send_ev);
- eth_port->etp_osdep.etp_send_ev= 1;
- ev_enqueue(ð_port->etp_sendev, eth_sendev, ev_arg);
+ r= m->DL_STAT;
+ if (r != OK)
+ {
+ ip_warning(("eth_rec: DL_STAT returned error %d\n",
+ r));
+ return;
+ }
+
+ loc_port->etp_osdep.etp_state= OEPS_IDLE;
+ loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_STAT;
- /* Pretend that we didn't get a reply. */
+ assert(loc_port->etp_osdep.etp_stat_gid != -1);
+ cpf_revoke(loc_port->etp_osdep.etp_stat_gid);
+ loc_port->etp_osdep.etp_stat_gid= -1;
+ loc_port->etp_osdep.etp_stat_buf= NULL;
+
+ /* Finish ioctl */
+ assert(loc_port->etp_flags & EPF_GOT_ADDR);
+ eth_restart_ioctl(loc_port);
+
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND)
+ {
+ printf("eth_rec(stat): OEPF_NEED_SEND is set\n");
+ }
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV)
+ {
+ printf("eth_rec(stat): OEPF_NEED_RECV is set\n");
+ }
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)
+ {
+ printf("eth_rec(stat): OEPF_NEED_CONF is set\n");
+ }
+#if 0
+ if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+ (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF))
+ {
+ eth_set_rec_conf(loc_port,
+ loc_port->etp_osdep.etp_recvconf);
+ }
+#endif
return;
}
+ assert(loc_port->etp_osdep.etp_state == OEPS_IDLE ||
+ loc_port->etp_osdep.etp_state == OEPS_RECV_SENT ||
+ loc_port->etp_osdep.etp_state == OEPS_SEND_SENT ||
+ (printf("etp_state = %d\n", loc_port->etp_osdep.etp_state), 0));
+ loc_port->etp_osdep.etp_state= OEPS_IDLE;
- /* packet is sent */
- bf_afree(eth_port->etp_wr_pack);
- eth_port->etp_wr_pack= NULL;
-}
-
-PUBLIC void eth_rec(m)
-message *m;
-{
- int i;
- eth_port_t *loc_port;
- int stat;
-
- assert(m->m_type == DL_TASK_REPLY);
-
+#if 0 /* Ethernet driver is not trusted */
set_time (m->DL_CLCK);
-
- for (i=0, loc_port= eth_port_table; i<eth_conf_nr; i++, loc_port++)
- {
- if (loc_port->etp_osdep.etp_port == m->DL_PORT &&
- loc_port->etp_osdep.etp_task == m->m_source)
- break;
- }
- if (i == eth_conf_nr)
- {
- ip_panic(("message from unknown source: %d:%d",
- m->m_source, m->DL_PORT));
- }
+#endif
stat= m->DL_STAT & 0xffff;
+#if 0
if (!(stat & (DL_PACK_SEND|DL_PACK_RECV)))
printf("eth_rec: neither DL_PACK_SEND nor DL_PACK_RECV\n");
+#endif
if (stat & DL_PACK_SEND)
write_int(loc_port);
if (stat & DL_PACK_RECV)
}
read_int(loc_port, m->DL_COUNT);
}
+
+ if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+ loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND)
+ {
+ loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_SEND;
+ if (loc_port->etp_wr_pack)
+ eth_issue_send(loc_port);
+ }
+ if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+ (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV))
+ {
+ printf("eth_rec: OEPF_NEED_RECV is set\n");
+ loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_RECV;
+ if (!(loc_port->etp_flags & EPF_READ_IP))
+ setup_read (loc_port);
+ }
+ if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)
+ {
+ printf("eth_rec: OEPF_NEED_CONF is set\n");
+ }
+ if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+ (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT))
+ {
+ send_getstat(loc_port);
+ }
}
PUBLIC void eth_check_drivers(m)
message *m;
{
int i, r, tasknr;
- struct eth_conf *ecp;
- eth_port_t *eth_port;
- char *drivername;
tasknr= m->m_source;
- printf("eth_check_drivers: got a notification from %d\n", tasknr);
-
+ if (notification_count < 100)
+ {
+ notification_count++;
+ printf("eth_check_drivers: got a notification #%d from %d\n",
+ notification_count, tasknr);
+ }
+
m->m_type= DL_GETNAME;
- r= sendrec(tasknr, m);
+ r= asynsend(tasknr, m);
if (r != OK)
{
- printf("eth_check_drivers: sendrec to %d failed: %d\n",
+ printf("eth_check_drivers: asynsend to %d failed: %d\n",
tasknr, r);
return;
}
- if (m->m_type != DL_NAME_REPLY)
- {
- printf(
- "eth_check_drivers: got bad getname reply (%d) from %d\n",
- m->m_type, tasknr);
- return;
- }
-
- drivername= m->m3_ca1;
- printf("eth_check_drivers: got name: %s\n", drivername);
-
- /* Re-init ethernet interfaces */
- for (i= 0, ecp= eth_conf, eth_port= eth_port_table;
- i<eth_conf_nr; i++, ecp++, eth_port++)
- {
- if (eth_is_vlan(ecp))
- continue;
-
- if (strcmp(ecp->ec_task, drivername) != 0)
- {
- /* Wrong driver */
- continue;
- }
-
- eth_restart(eth_port, tasknr);
- }
}
PUBLIC int eth_get_stat(eth_port, eth_stat)
{
int r;
cp_grant_id_t gid;
- message mess, mlocked;
assert(!eth_port->etp_vlan);
+ if (eth_port->etp_osdep.etp_flags & OEPF_NEED_STAT)
+ ip_panic(( "eth_get_stat: getstat already in progress" ));
+
gid= cpf_grant_direct(eth_port->etp_osdep.etp_task,
(vir_bytes)eth_stat, sizeof(*eth_stat), CPF_WRITE);
if (gid == -1)
ip_panic(( "eth_get_stat: cpf_grant_direct failed: %d\n",
errno));
}
+ assert(eth_port->etp_osdep.etp_stat_gid == -1);
+ eth_port->etp_osdep.etp_stat_gid= gid;
+ eth_port->etp_osdep.etp_stat_buf= eth_stat;
- mess.m_type= DL_GETSTAT_S;
- mess.DL_PORT= eth_port->etp_osdep.etp_port;
- mess.DL_PROC= this_proc;
- mess.DL_GRANT= gid;
-
- for (;;)
- {
- r= sendrec(eth_port->etp_osdep.etp_task, &mess);
- if (r != ELOCKED)
- break;
-
- r= receive(eth_port->etp_osdep.etp_task, &mlocked);
- assert(r == OK);
-
- compare(mlocked.m_type, ==, DL_TASK_REPLY);
- eth_rec(&mlocked);
- }
- cpf_revoke(gid);
-
- if (r != OK)
+ if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
{
- printf("eth_get_stat: sendrec to %d failed: %d\n",
- eth_port->etp_osdep.etp_task, r);
- return EIO;
+ eth_port->etp_osdep.etp_flags |= OEPF_NEED_STAT;
+ return SUSPEND;
}
- assert(mess.m_type == DL_TASK_REPLY);
-
- r= mess.DL_STAT >> 16;
- assert (r == 0);
+ send_getstat(eth_port);
- if (mess.DL_STAT)
- {
- eth_rec(&mess);
- }
- return OK;
+ return SUSPEND;
}
PUBLIC void eth_set_rec_conf (eth_port, flags)
return;
}
+ if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
+ {
+ printf(
+ "eth_set_rec_conf: setting OEPF_NEED_CONF, state = %d\n",
+ eth_port->etp_osdep.etp_state);
+ eth_port->etp_osdep.etp_flags |= OEPF_NEED_CONF;
+ return;
+ }
+
eth_port->etp_osdep.etp_recvconf= flags;
dl_flags= DL_NOMODE;
if (flags & NWEO_EN_BROAD)
mess.DL_PROC= this_proc;
mess.DL_MODE= dl_flags;
- do
+ assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
+ r= asynsend(eth_port->etp_osdep.etp_task, &mess);
+ eth_port->etp_osdep.etp_state= OEPS_CONF_SENT;
+
+ if (r < 0)
{
- r= sendrec(eth_port->etp_osdep.etp_task, &mess);
- if (r == ELOCKED) /* etp_task is sending to this task,
- I hope */
+ printf("eth_set_rec_conf: asynsend to %d failed: %d\n",
+ eth_port->etp_osdep.etp_task, r);
+ return;
+ }
+}
+
+PRIVATE void eth_issue_send(eth_port)
+eth_port_t *eth_port;
+{
+ int i, r, pack_size;
+ acc_t *pack, *pack_ptr;
+ iovec_s_t *iovec;
+ message m;
+
+ iovec= eth_port->etp_osdep.etp_wr_iovec;
+ pack= eth_port->etp_wr_pack;
+ pack_size= 0;
+ for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr; i++,
+ pack_ptr= pack_ptr->acc_next)
+ {
+ r= cpf_setgrant_direct(iovec[i].iov_grant,
+ eth_port->etp_osdep.etp_task,
+ (vir_bytes)ptr2acc_data(pack_ptr),
+ (vir_bytes)pack_ptr->acc_length,
+ CPF_READ);
+ if (r != 0)
{
- if (receive (eth_port->etp_osdep.etp_task,
- &repl_mess)< 0)
+ ip_panic((
+ "eth_write_port: cpf_setgrant_direct failed: %d\n",
+ errno));
+ }
+ pack_size += iovec[i].iov_size= pack_ptr->acc_length;
+ }
+ if (i>= IOVEC_NR)
+ {
+ pack= bf_pack(pack); /* packet is too fragmented */
+ eth_port->etp_wr_pack= pack;
+ pack_size= 0;
+ for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr;
+ i++, pack_ptr= pack_ptr->acc_next)
+ {
+ r= cpf_setgrant_direct(iovec[i].iov_grant,
+ eth_port->etp_osdep.etp_task,
+ (vir_bytes)ptr2acc_data(pack_ptr),
+ (vir_bytes)pack_ptr->acc_length,
+ CPF_READ);
+ if (r != 0)
{
- ip_panic(("unable to receive"));
+ ip_panic((
+ "eth_write_port: cpf_setgrant_direct failed: %d\n",
+ errno));
}
-
- compare(repl_mess.m_type, ==, DL_TASK_REPLY);
- eth_rec(&repl_mess);
+ pack_size += iovec[i].iov_size= pack_ptr->acc_length;
}
- } while (r == ELOCKED);
-
- if (r < 0)
+ }
+ assert (i< IOVEC_NR);
+ assert (pack_size >= ETH_MIN_PACK_SIZE);
+
+ r= cpf_setgrant_direct(eth_port->etp_osdep.etp_wr_vec_grant,
+ eth_port->etp_osdep.etp_task,
+ (vir_bytes)iovec,
+ (vir_bytes)(i * sizeof(iovec[0])),
+ CPF_READ);
+ if (r != 0)
{
- printf("eth_set_rec_conf: sendrec to %d failed: %d\n",
- eth_port->etp_osdep.etp_task, r);
- return;
+ ip_panic((
+ "eth_write_port: cpf_setgrant_direct failed: %d\n",
+ errno));
}
+ m.DL_COUNT= i;
+ m.DL_GRANT= eth_port->etp_osdep.etp_wr_vec_grant;
+ m.m_type= DL_WRITEV_S;
+
+ m.DL_PORT= eth_port->etp_osdep.etp_port;
+ m.DL_PROC= this_proc;
+ m.DL_MODE= DL_NOMODE;
+
+ assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
+ r= asynsend(eth_port->etp_osdep.etp_task, &m);
- assert (mess.m_type == DL_CONF_REPLY);
- if (mess.m3_i1 != eth_port->etp_osdep.etp_port)
+ if (r < 0)
{
- ip_panic(("got reply for wrong port"));
+ printf("eth_issue_send: send to %d failed: %d\n",
+ eth_port->etp_osdep.etp_task, r);
+ return;
}
+ eth_port->etp_osdep.etp_state= OEPS_SEND_SENT;
}
PRIVATE void write_int(eth_port)
assert(!eth_port->etp_vlan);
assert(!(eth_port->etp_flags & (EPF_READ_IP|EPF_READ_SP)));
- do
+ if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
{
- assert (!eth_port->etp_rd_pack);
+ printf("setup_read: setting OEPF_NEED_RECV\n");
+ eth_port->etp_osdep.etp_flags |= OEPF_NEED_RECV;
- iovec= eth_port->etp_osdep.etp_rd_iovec;
- pack= bf_memreq (ETH_MAX_PACK_SIZE_TAGGED);
+ return;
+ }
- for (i=0, pack_ptr= pack; i<RD_IOVEC && pack_ptr;
- i++, pack_ptr= pack_ptr->acc_next)
- {
- r= cpf_setgrant_direct(iovec[i].iov_grant,
- eth_port->etp_osdep.etp_task,
- (vir_bytes)ptr2acc_data(pack_ptr),
- (vir_bytes)pack_ptr->acc_length,
- CPF_WRITE);
- if (r != 0)
- {
- ip_panic((
- "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n",
- errno));
- }
- iovec[i].iov_size= (vir_bytes)pack_ptr->acc_length;
- }
- assert (!pack_ptr);
+ assert (!eth_port->etp_rd_pack);
- r= cpf_setgrant_direct(eth_port->etp_osdep.etp_rd_vec_grant,
+ iovec= eth_port->etp_osdep.etp_rd_iovec;
+ pack= bf_memreq (ETH_MAX_PACK_SIZE_TAGGED);
+
+ for (i=0, pack_ptr= pack; i<RD_IOVEC && pack_ptr;
+ i++, pack_ptr= pack_ptr->acc_next)
+ {
+ r= cpf_setgrant_direct(iovec[i].iov_grant,
eth_port->etp_osdep.etp_task,
- (vir_bytes)iovec,
- (vir_bytes)(i * sizeof(iovec[0])),
- CPF_READ);
+ (vir_bytes)ptr2acc_data(pack_ptr),
+ (vir_bytes)pack_ptr->acc_length,
+ CPF_WRITE);
if (r != 0)
{
ip_panic((
"mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n",
errno));
}
+ iovec[i].iov_size= (vir_bytes)pack_ptr->acc_length;
+ }
+ assert (!pack_ptr);
- mess1.m_type= DL_READV_S;
- mess1.DL_PORT= eth_port->etp_osdep.etp_port;
- mess1.DL_PROC= this_proc;
- mess1.DL_COUNT= i;
- mess1.DL_GRANT= eth_port->etp_osdep.etp_rd_vec_grant;
-
- for (;;)
- {
- if (recv_debug)
- {
- printf("eth%d: sending DL_READV_S\n",
- mess1.DL_PORT);
- }
- r= sendrec(eth_port->etp_osdep.etp_task, &mess1);
- if (r != ELOCKED)
- break;
-
- /* ethernet task is sending to this task, I hope */
- r= receive(eth_port->etp_osdep.etp_task, &block_msg);
- if (r < 0)
- ip_panic(("unable to receive"));
-
- loc_port= eth_port;
- if (loc_port->etp_osdep.etp_port != block_msg.DL_PORT ||
- loc_port->etp_osdep.etp_task !=
- block_msg.m_source)
- {
- loc_port= find_port(&block_msg);
- }
- assert(block_msg.DL_STAT &
- (DL_PACK_SEND|DL_PACK_RECV));
- if (block_msg.DL_STAT & DL_PACK_SEND)
- {
- loc_port->etp_osdep.etp_sendrepl=
- block_msg;
- ev_arg.ev_ptr= loc_port;
- assert(!loc_port->etp_osdep.etp_send_ev);
- loc_port->etp_osdep.etp_send_ev= 1;
- ev_enqueue(&loc_port->etp_sendev,
- eth_sendev, ev_arg);
- }
- if (block_msg.DL_STAT & DL_PACK_RECV)
- {
- if (recv_debug)
- {
- printf(
- "setup_read(block_msg): eth%d got DL_PACK_RECV\n",
- block_msg.DL_PORT);
- }
- assert(loc_port != eth_port);
- loc_port->etp_osdep.etp_recvrepl= block_msg;
- ev_arg.ev_ptr= loc_port;
- ev_enqueue(&loc_port->etp_osdep.etp_recvev,
- eth_recvev, ev_arg);
- }
- }
-
- if (r < 0)
- {
- printf("mnx_eth`setup_read: sendrec to %d failed: %d\n",
- eth_port->etp_osdep.etp_task, r);
- eth_port->etp_rd_pack= pack;
- eth_port->etp_flags |= EPF_READ_IP;
- continue;
- }
-
- if (mess1.m_type != DL_TASK_REPLY ||
- mess1.DL_PORT != eth_port->etp_osdep.etp_port ||
- mess1.DL_PROC != this_proc)
- {
- printf("mnx_eth`setup_read: bad type, port or proc\n");
- printf("got type %d, port %d, proc %d\n",
- mess1.m_type, mess1.DL_PORT, mess1.DL_PROC);
- continue;
- }
+ r= cpf_setgrant_direct(eth_port->etp_osdep.etp_rd_vec_grant,
+ eth_port->etp_osdep.etp_task,
+ (vir_bytes)iovec,
+ (vir_bytes)(i * sizeof(iovec[0])),
+ CPF_READ);
+ if (r != 0)
+ {
+ ip_panic((
+ "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n",
+ errno));
+ }
- if ((mess1.DL_STAT >> 16) != OK)
- {
- printf(
- "mnx_eth`setup_read: bad value in DL_STAT: 0x%x\n",
- mess1.DL_STAT);
- mess1.DL_STAT= 0;
- }
+ mess1.m_type= DL_READV_S;
+ mess1.DL_PORT= eth_port->etp_osdep.etp_port;
+ mess1.DL_PROC= this_proc;
+ mess1.DL_COUNT= i;
+ mess1.DL_GRANT= eth_port->etp_osdep.etp_rd_vec_grant;
- if (mess1.DL_STAT & DL_PACK_RECV)
- {
- if (recv_debug)
- {
- printf(
- "setup_read(mess1): eth%d: got DL_PACK_RECV\n",
- mess1.DL_PORT);
- }
+ assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
- if (mess1.DL_COUNT < ETH_MIN_PACK_SIZE)
- {
- printf(
- "mnx_eth`setup_read: packet size too small (%d)\n",
- mess1.DL_COUNT);
- bf_afree(pack);
- }
- else
- {
- /* packet received */
- pack_ptr= bf_cut(pack, 0, mess1.DL_COUNT);
- bf_afree(pack);
-
- assert(!no_ethWritePort);
- no_ethWritePort= 1;
- eth_arrive(eth_port, pack_ptr, mess1.DL_COUNT);
- assert(no_ethWritePort);
- no_ethWritePort= 0;
- }
- }
- else
- {
- /* no packet received */
- eth_port->etp_rd_pack= pack;
- eth_port->etp_flags |= EPF_READ_IP;
- }
+ r= asynsend(eth_port->etp_osdep.etp_task, &mess1);
+ eth_port->etp_osdep.etp_state= OEPS_RECV_SENT;
- if (mess1.DL_STAT & DL_PACK_SEND)
- {
- if (eth_port->etp_osdep.etp_send_ev)
- {
- printf(
- "mnx_eth`setup_read: etp_send_ev is set, ignoring DL_PACK_SEND\n");
- }
- else
- {
- eth_port->etp_osdep.etp_sendrepl= mess1;
- ev_arg.ev_ptr= eth_port;
- assert(!eth_port->etp_osdep.etp_send_ev);
- eth_port->etp_osdep.etp_send_ev= 1;
- ev_enqueue(ð_port->etp_sendev, eth_sendev,
- ev_arg);
- }
- }
- } while (!(eth_port->etp_flags & EPF_READ_IP));
+ if (r < 0)
+ {
+ printf(
+ "mnx_eth`setup_read: asynsend to %d failed: %d\n",
+ eth_port->etp_osdep.etp_task, r);
+ }
+ eth_port->etp_rd_pack= pack;
+ eth_port->etp_flags |= EPF_READ_IP;
eth_port->etp_flags |= EPF_READ_SP;
}
{
int i, r;
unsigned flags, dl_flags;
+ cp_grant_id_t gid;
message mess;
- eth_port_t *loc_port;
printf("eth_restart: restarting eth%d, task %d, port %d\n",
eth_port-eth_port_table, tasknr,
eth_port->etp_osdep.etp_port);
+ if (eth_port->etp_osdep.etp_task == tasknr)
+ {
+ printf(
+ "eth_restart: task number did not change. Aborting restart\n");
+ return;
+ }
eth_port->etp_osdep.etp_task= tasknr;
+ switch(eth_port->etp_osdep.etp_state)
+ {
+ case OEPS_CONF_SENT:
+ case OEPS_RECV_SENT:
+ case OEPS_SEND_SENT:
+ /* We can safely ignore the pending CONF, RECV, and SEND
+ * requests.
+ */
+ eth_port->etp_osdep.etp_state= OEPS_IDLE;
+ break;
+ case OEPS_GETSTAT_SENT:
+ /* Set the OEPF_NEED_STAT to trigger a new request */
+ eth_port->etp_osdep.etp_flags |= OEPF_NEED_STAT;
+ eth_port->etp_osdep.etp_state= OEPS_IDLE;
+ break;
+ }
+
+ /* If there is a pending GETSTAT request then we have to create a
+ * new grant.
+ */
+ if (eth_port->etp_osdep.etp_flags & OEPF_NEED_STAT)
+ {
+ assert(eth_port->etp_osdep.etp_stat_gid != -1);
+ cpf_revoke(eth_port->etp_osdep.etp_stat_gid);
+
+ gid= cpf_grant_direct(eth_port->etp_osdep.etp_task,
+ (vir_bytes)eth_port->etp_osdep.etp_stat_buf,
+ sizeof(*eth_port->etp_osdep.etp_stat_buf), CPF_WRITE);
+ if (gid == -1)
+ {
+ ip_panic((
+ "eth_restart: cpf_grant_direct failed: %d\n",
+ errno));
+ }
+ eth_port->etp_osdep.etp_stat_gid= gid;
+ }
+
flags= eth_port->etp_osdep.etp_recvconf;
dl_flags= DL_NOMODE;
if (flags & NWEO_EN_BROAD)
mess.DL_PROC= this_proc;
mess.DL_MODE= dl_flags;
- r= sendrec(eth_port->etp_osdep.etp_task, &mess);
- /* YYY */
+ compare(eth_port->etp_osdep.etp_state, ==, OEPS_IDLE);
+ r= asynsend(eth_port->etp_osdep.etp_task, &mess);
if (r<0)
{
printf(
- "eth_restart: sendrec to ethernet task %d failed: %d\n",
+ "eth_restart: send to ethernet task %d failed: %d\n",
eth_port->etp_osdep.etp_task, r);
return;
}
-
- if (mess.m3_i1 == ENXIO)
- {
- printf(
- "osdep_eth_init: no ethernet device at task=%d,port=%d\n",
- eth_port->etp_osdep.etp_task,
- eth_port->etp_osdep.etp_port);
- return;
- }
- if (mess.m3_i1 < 0)
- ip_panic(("osdep_eth_init: DL_INIT returned error %d\n",
- mess.m3_i1));
-
- if (mess.m3_i1 != eth_port->etp_osdep.etp_port)
- {
- ip_panic((
-"osdep_eth_init: got reply for wrong port (got %d, expected %d)\n",
- mess.m3_i1, eth_port->etp_osdep.etp_port));
- }
-
- eth_port->etp_flags |= EPF_ENABLED;
-
- eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1;
- if (!(eth_port->etp_flags & EPF_GOT_ADDR))
- {
- eth_port->etp_flags |= EPF_GOT_ADDR;
- eth_restart_ioctl(eth_port);
-
- /* Also update any VLANs on this device */
- for (i=0, loc_port= eth_port_table; i<eth_conf_nr;
- i++, loc_port++)
- {
- if (!(loc_port->etp_flags & EPF_ENABLED))
- continue;
- if (loc_port->etp_vlan_port != eth_port)
- continue;
-
- loc_port->etp_ethaddr= eth_port->etp_ethaddr;
- loc_port->etp_flags |= EPF_GOT_ADDR;
- eth_restart_ioctl(loc_port);
- }
- }
+ eth_port->etp_osdep.etp_state= OEPS_CONF_SENT;
if (eth_port->etp_wr_pack)
{
eth_port->etp_rd_pack= NULL;
eth_port->etp_flags &= ~(EPF_READ_IP|EPF_READ_SP);
}
- setup_read (eth_port);
+
+}
+
+PRIVATE void send_getstat(eth_port)
+eth_port_t *eth_port;
+{
+ int r;
+ message mess;
+
+ mess.m_type= DL_GETSTAT_S;
+ mess.DL_PORT= eth_port->etp_osdep.etp_port;
+ mess.DL_PROC= this_proc;
+ mess.DL_GRANT= eth_port->etp_osdep.etp_stat_gid;
+
+ assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
+
+ r= asynsend(eth_port->etp_osdep.etp_task, &mess);
+ eth_port->etp_osdep.etp_state= OEPS_GETSTAT_SENT;
+
+ if (r != OK)
+ ip_panic(( "eth_get_stat: asynsend failed: %d", r));
+}
+
+PRIVATE asynmsg_t *msgtable= NULL;
+PRIVATE size_t msgtable_n= 0;
+
+PRIVATE int asynsend(dst, mp)
+endpoint_t dst;
+message *mp;
+{
+ int i;
+ unsigned flags;
+
+ if (msgtable == NULL)
+ {
+ printf("asynsend: allocating msg table\n");
+ msgtable_n= 5;
+ msgtable= malloc(msgtable_n * sizeof(msgtable[0]));
+ for (i= 0; i<msgtable_n; i++)
+ msgtable[i].flags= AMF_EMPTY;
+ }
+
+ /* Find slot in table */
+ for (i= 0; i<msgtable_n; i++)
+ {
+ flags= msgtable[i].flags;
+ if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
+ {
+ if (msgtable[i].result != OK)
+ {
+ printf(
+ "asynsend: found completed entry %d with error %d\n",
+ i, msgtable[i].result);
+ }
+ break;
+ }
+ if (flags == AMF_EMPTY)
+ break;
+ }
+ if (i >= msgtable_n)
+ ip_panic(( "asynsend: should resize table" ));
+ msgtable[i].dst= dst;
+ msgtable[i].msg= *mp;
+ msgtable[i].flags= AMF_VALID; /* Has to be last. The kernel
+ * scans this table while we are
+ * sleeping.
+ */
+
+ /* Tell the kernel to rescan the table */
+ return senda(msgtable, msgtable_n);
}
/*