diff options
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/net/netvsc.c | 47 | ||||
-rw-r--r-- | src/drivers/net/netvsc.h | 15 |
2 files changed, 62 insertions, 0 deletions
diff --git a/src/drivers/net/netvsc.c b/src/drivers/net/netvsc.c index d269cd63..5be52fb8 100644 --- a/src/drivers/net/netvsc.c +++ b/src/drivers/net/netvsc.c @@ -259,6 +259,15 @@ static int netvsc_revoke_buffer ( struct netvsc_device *netvsc, struct netvsc_revoke_buffer_message msg; int rc; + /* If the buffer's GPADL is obsolete (i.e. was created before + * the most recent Hyper-V reset), then we will never receive + * a response to the revoke message. Since the GPADL is + * already destroyed as far as the hypervisor is concerned, no + * further action is required. + */ + if ( netvsc_is_obsolete ( netvsc ) ) + return 0; + /* Construct message */ memset ( &msg, 0, sizeof ( msg ) ); msg.header.type = cpu_to_le32 ( buffer->revoke_type ); @@ -474,6 +483,14 @@ static int netvsc_transmit ( struct rndis_device *rndis, uint64_t xid; int rc; + /* If the device is obsolete (i.e. was opened before the most + * recent Hyper-V reset), then we will never receive transmit + * completions. Fail transmissions immediately to minimise + * the delay in closing and reopening the device. + */ + if ( netvsc_is_obsolete ( netvsc ) ) + return -EPIPE; + /* Sanity check */ assert ( iob_len ( iobuf ) >= sizeof ( *header ) ); assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) ); @@ -824,6 +841,35 @@ static int netvsc_probe ( struct vmbus_device *vmdev ) { } /** + * Reset device + * + * @v vmdev VMBus device + * @ret rc Return status code + */ +static int netvsc_reset ( struct vmbus_device *vmdev ) { + struct rndis_device *rndis = vmbus_get_drvdata ( vmdev ); + struct netvsc_device *netvsc = rndis->priv; + struct net_device *netdev = rndis->netdev; + int rc; + + /* A closed device holds no NetVSC (or RNDIS) state, so there + * is nothing to reset. + */ + if ( ! netdev_is_open ( netdev ) ) + return 0; + + /* Close and reopen device to reset any stale state */ + netdev_close ( netdev ); + if ( ( rc = netdev_open ( netdev ) ) != 0 ) { + DBGC ( netvsc, "NETVSC %s could not reopen: %s\n", + netvsc->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** * Remove device * * @v vmdev VMBus device @@ -844,5 +890,6 @@ struct vmbus_driver netvsc_driver __vmbus_driver = { .type = VMBUS_TYPE ( 0xf8615163, 0xdf3e, 0x46c5, 0x913f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e ), .probe = netvsc_probe, + .reset = netvsc_reset, .remove = netvsc_remove, }; diff --git a/src/drivers/net/netvsc.h b/src/drivers/net/netvsc.h index 39eeb891..93192357 100644 --- a/src/drivers/net/netvsc.h +++ b/src/drivers/net/netvsc.h @@ -362,4 +362,19 @@ struct netvsc_device { int wait_rc; }; +/** + * Check if NetVSC device is obsolete + * + * @v netvsc NetVSC device + * @v is_obsolete NetVSC device is obsolete + * + * Check if NetVSC device is obsolete (i.e. was opened before the most + * recent Hyper-V reset). + */ +static inline __attribute__ (( always_inline )) int +netvsc_is_obsolete ( struct netvsc_device *netvsc ) { + + return vmbus_gpadl_is_obsolete ( netvsc->rx.gpadl ); +} + #endif /* _NETVSC_H */ |