diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2014-01-28 23:42:06 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2014-01-28 23:42:06 +0100 |
commit | 613f84a0fcd46f2143b046b57c6c6444eafa4d4d (patch) | |
tree | f4e175a4e6a55d313012e87d0d1324264604c072 /pfinet/ethernet.c | |
parent | 9bebcd38f42da289a3eaf9f473a9529f8d3c4664 (diff) |
Make pfinet re-open ethernet device on transmission error
* pfinet/ethernet.c (ethernet_close): New function.
(ethernet_xmit): On EMACH_SEND_INVALID_DEST error, call ethernet_close
and ethernet_open again to re-open ethernet device.
Diffstat (limited to 'pfinet/ethernet.c')
-rw-r--r-- | pfinet/ethernet.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/pfinet/ethernet.c b/pfinet/ethernet.c index 768d5282..74c1a08a 100644 --- a/pfinet/ethernet.c +++ b/pfinet/ethernet.c @@ -233,6 +233,18 @@ ethernet_open (struct device *dev) return 0; } +int +ethernet_close (struct device *dev) +{ + struct ether_device *edev = (struct ether_device *) dev->priv; + + mach_port_deallocate (mach_task_self (), edev->readptname); + edev->readptname = MACH_PORT_NULL; + ports_destroy_right (edev->readpt); + edev->readpt = NULL; + device_close (edev->ether_port); + edev->ether_port = MACH_PORT_NULL; +} /* Transmit an ethernet frame */ int @@ -241,10 +253,31 @@ ethernet_xmit (struct sk_buff *skb, struct device *dev) error_t err; struct ether_device *edev = (struct ether_device *) dev->priv; u_int count; + u_int tried = 0; + + do + { + tried++; + err = device_write (edev->ether_port, D_NOWAIT, 0, skb->data, skb->len, &count); + if (err == EMACH_SEND_INVALID_DEST) + { + /* Device probably just died, try to reopen it. */ + + if (tried == 2) + /* Too many tries, abort */ + break; + + ethernet_close (dev); + ethernet_open (dev); + } + else + { + assert_perror (err); + assert (count == skb->len); + } + } + while (err); - err = device_write (edev->ether_port, D_NOWAIT, 0, skb->data, skb->len, &count); - assert_perror (err); - assert (count == skb->len); dev_kfree_skb (skb); return 0; } |