summaryrefslogtreecommitdiff
path: root/pfinet
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2014-01-28 23:42:06 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2014-01-28 23:42:06 +0100
commit613f84a0fcd46f2143b046b57c6c6444eafa4d4d (patch)
treef4e175a4e6a55d313012e87d0d1324264604c072 /pfinet
parent9bebcd38f42da289a3eaf9f473a9529f8d3c4664 (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')
-rw-r--r--pfinet/ethernet.c39
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;
}