2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 * Hyper-V network virtual service client
30 * The network virtual service client (NetVSC) connects to the network
31 * virtual service provider (NetVSP) via the Hyper-V virtual machine
32 * bus (VMBus). It provides a transport layer for RNDIS packets.
38 #include <ipxe/umalloc.h>
39 #include <ipxe/rndis.h>
40 #include <ipxe/vmbus.h>
44 * Send control message and wait for completion
46 * @v netvsc NetVSC device
47 * @v xrid Relative transaction ID
49 * @v len Length of data
50 * @ret rc Return status code
52 static int netvsc_control ( struct netvsc_device *netvsc, unsigned int xrid,
53 const void *data, size_t len ) {
54 uint64_t xid = ( NETVSC_BASE_XID + xrid );
58 /* Send control message */
59 if ( ( rc = vmbus_send_control ( netvsc->vmdev, xid, data, len ) ) !=0){
60 DBGC ( netvsc, "NETVSC %s could not send control message: %s\n",
61 netvsc->name, strerror ( rc ) );
65 /* Record transaction ID */
66 netvsc->wait_xrid = xrid;
68 /* Wait for operation to complete */
69 for ( i = 0 ; i < NETVSC_MAX_WAIT_MS ; i++ ) {
71 /* Check for completion */
72 if ( ! netvsc->wait_xrid )
73 return netvsc->wait_rc;
75 /* Poll VMBus device */
76 vmbus_poll ( netvsc->vmdev );
82 DBGC ( netvsc, "NETVSC %s timed out waiting for XRID %d\n",
84 vmbus_dump_channel ( netvsc->vmdev );
89 * Handle generic completion
91 * @v netvsc NetVSC device
93 * @v len Length of data
94 * @ret rc Return status code
96 static int netvsc_completed ( struct netvsc_device *netvsc __unused,
97 const void *data __unused, size_t len __unused ) {
102 * Initialise communication
104 * @v netvsc NetVSC device
105 * @ret rc Return status code
107 static int netvsc_initialise ( struct netvsc_device *netvsc ) {
108 struct netvsc_init_message msg;
111 /* Construct message */
112 memset ( &msg, 0, sizeof ( msg ) );
113 msg.header.type = cpu_to_le32 ( NETVSC_INIT_MSG );
114 msg.min = cpu_to_le32 ( NETVSC_VERSION_1 );
115 msg.max = cpu_to_le32 ( NETVSC_VERSION_1 );
117 /* Send message and wait for completion */
118 if ( ( rc = netvsc_control ( netvsc, NETVSC_INIT_XRID, &msg,
119 sizeof ( msg ) ) ) != 0 ) {
120 DBGC ( netvsc, "NETVSC %s could not initialise: %s\n",
121 netvsc->name, strerror ( rc ) );
129 * Handle initialisation completion
131 * @v netvsc NetVSC device
133 * @v len Length of data
134 * @ret rc Return status code
137 netvsc_initialised ( struct netvsc_device *netvsc, const void *data,
139 const struct netvsc_init_completion *cmplt = data;
141 /* Check completion */
142 if ( len < sizeof ( *cmplt ) ) {
143 DBGC ( netvsc, "NETVSC %s underlength initialisation "
144 "completion (%zd bytes)\n", netvsc->name, len );
147 if ( cmplt->header.type != cpu_to_le32 ( NETVSC_INIT_CMPLT ) ) {
148 DBGC ( netvsc, "NETVSC %s unexpected initialisation completion "
149 "type %d\n", netvsc->name,
150 le32_to_cpu ( cmplt->header.type ) );
153 if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
154 DBGC ( netvsc, "NETVSC %s initialisation failure status %d\n",
155 netvsc->name, le32_to_cpu ( cmplt->status ) );
165 * @v netvsc NetVSC device
166 * @ret rc Return status code
168 static int netvsc_ndis_version ( struct netvsc_device *netvsc ) {
169 struct netvsc_ndis_version_message msg;
172 /* Construct message */
173 memset ( &msg, 0, sizeof ( msg ) );
174 msg.header.type = cpu_to_le32 ( NETVSC_NDIS_VERSION_MSG );
175 msg.major = cpu_to_le32 ( NETVSC_NDIS_MAJOR );
176 msg.minor = cpu_to_le32 ( NETVSC_NDIS_MINOR );
178 /* Send message and wait for completion */
179 if ( ( rc = netvsc_control ( netvsc, NETVSC_NDIS_VERSION_XRID,
180 &msg, sizeof ( msg ) ) ) != 0 ) {
181 DBGC ( netvsc, "NETVSC %s could not set NDIS version: %s\n",
182 netvsc->name, strerror ( rc ) );
190 * Establish data buffer
192 * @v netvsc NetVSC device
193 * @v buffer Data buffer
194 * @ret rc Return status code
196 static int netvsc_establish_buffer ( struct netvsc_device *netvsc,
197 struct netvsc_buffer *buffer ) {
198 struct netvsc_establish_buffer_message msg;
201 /* Construct message */
202 memset ( &msg, 0, sizeof ( msg ) );
203 msg.header.type = cpu_to_le32 ( buffer->establish_type );
204 msg.gpadl = cpu_to_le32 ( buffer->gpadl );
205 msg.pageset = buffer->pages.pageset; /* Already protocol-endian */
207 /* Send message and wait for completion */
208 if ( ( rc = netvsc_control ( netvsc, buffer->establish_xrid, &msg,
209 sizeof ( msg ) ) ) != 0 ) {
210 DBGC ( netvsc, "NETVSC %s could not establish buffer: %s\n",
211 netvsc->name, strerror ( rc ) );
219 * Handle establish receive data buffer completion
221 * @v netvsc NetVSC device
223 * @v len Length of data
224 * @ret rc Return status code
226 static int netvsc_rx_established_buffer ( struct netvsc_device *netvsc,
227 const void *data, size_t len ) {
228 const struct netvsc_rx_establish_buffer_completion *cmplt = data;
230 /* Check completion */
231 if ( len < sizeof ( *cmplt ) ) {
232 DBGC ( netvsc, "NETVSC %s underlength buffer completion (%zd "
233 "bytes)\n", netvsc->name, len );
236 if ( cmplt->header.type != cpu_to_le32 ( NETVSC_RX_ESTABLISH_CMPLT ) ) {
237 DBGC ( netvsc, "NETVSC %s unexpected buffer completion type "
238 "%d\n", netvsc->name, le32_to_cpu ( cmplt->header.type));
241 if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
242 DBGC ( netvsc, "NETVSC %s buffer failure status %d\n",
243 netvsc->name, le32_to_cpu ( cmplt->status ) );
253 * @v netvsc NetVSC device
254 * @v buffer Data buffer
255 * @ret rc Return status code
257 static int netvsc_revoke_buffer ( struct netvsc_device *netvsc,
258 struct netvsc_buffer *buffer ) {
259 struct netvsc_revoke_buffer_message msg;
262 /* Construct message */
263 memset ( &msg, 0, sizeof ( msg ) );
264 msg.header.type = cpu_to_le32 ( buffer->revoke_type );
265 msg.pageset = buffer->pages.pageset; /* Already protocol-endian */
267 /* Send message and wait for completion */
268 if ( ( rc = netvsc_control ( netvsc, buffer->revoke_xrid,
269 &msg, sizeof ( msg ) ) ) != 0 ) {
270 DBGC ( netvsc, "NETVSC %s could not revoke buffer: %s\n",
271 netvsc->name, strerror ( rc ) );
279 * Handle received control packet
281 * @v vmdev VMBus device
282 * @v xid Transaction ID
284 * @v len Length of data
285 * @ret rc Return status code
287 static int netvsc_recv_control ( struct vmbus_device *vmdev, uint64_t xid,
288 const void *data, size_t len ) {
289 struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
290 struct netvsc_device *netvsc = rndis->priv;
292 DBGC ( netvsc, "NETVSC %s received unsupported control packet "
293 "(%08llx):\n", netvsc->name, xid );
294 DBGC_HDA ( netvsc, 0, data, len );
299 * Handle received data packet
301 * @v vmdev VMBus device
302 * @v xid Transaction ID
304 * @v len Length of data
305 * @v list List of I/O buffers
306 * @ret rc Return status code
308 static int netvsc_recv_data ( struct vmbus_device *vmdev, uint64_t xid,
309 const void *data, size_t len,
310 struct list_head *list ) {
311 struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
312 struct netvsc_device *netvsc = rndis->priv;
313 const struct netvsc_rndis_message *msg = data;
314 struct io_buffer *iobuf;
315 struct io_buffer *tmp;
319 if ( len < sizeof ( *msg ) ) {
320 DBGC ( netvsc, "NETVSC %s received underlength RNDIS packet "
321 "(%zd bytes)\n", netvsc->name, len );
325 if ( msg->header.type != cpu_to_le32 ( NETVSC_RNDIS_MSG ) ) {
326 DBGC ( netvsc, "NETVSC %s received unexpected RNDIS packet "
327 "type %d\n", netvsc->name,
328 le32_to_cpu ( msg->header.type ) );
333 /* Send completion back to host */
334 if ( ( rc = vmbus_send_completion ( vmdev, xid, NULL, 0 ) ) != 0 ) {
335 DBGC ( netvsc, "NETVSC %s could not send completion: %s\n",
336 netvsc->name, strerror ( rc ) );
340 /* Hand off to RNDIS */
341 list_for_each_entry_safe ( iobuf, tmp, list, list ) {
342 list_del ( &iobuf->list );
343 rndis_rx ( rndis, iob_disown ( iobuf ) );
350 list_for_each_entry_safe ( iobuf, tmp, list, list ) {
351 list_del ( &iobuf->list );
358 * Handle received completion packet
360 * @v vmdev VMBus device
361 * @v xid Transaction ID
363 * @v len Length of data
364 * @ret rc Return status code
366 static int netvsc_recv_completion ( struct vmbus_device *vmdev, uint64_t xid,
367 const void *data, size_t len ) {
368 struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
369 struct netvsc_device *netvsc = rndis->priv;
370 struct io_buffer *iobuf;
371 int ( * completion ) ( struct netvsc_device *netvsc,
372 const void *data, size_t len );
373 unsigned int xrid = ( xid - NETVSC_BASE_XID );
377 /* Handle transmit completion, if applicable */
378 tx_id = ( xrid - NETVSC_TX_BASE_XRID );
379 if ( ( tx_id < NETVSC_TX_NUM_DESC ) &&
380 ( ( iobuf = netvsc->tx.iobufs[tx_id] ) != NULL ) ) {
383 netvsc->tx.iobufs[tx_id] = NULL;
384 netvsc->tx.ids[ ( netvsc->tx.id_cons++ ) &
385 ( netvsc->tx.count - 1 ) ] = tx_id;
387 /* Hand back to RNDIS */
388 rndis_tx_complete ( rndis, iobuf );
392 /* Otherwise determine completion handler */
393 if ( xrid == NETVSC_INIT_XRID ) {
394 completion = netvsc_initialised;
395 } else if ( xrid == NETVSC_RX_ESTABLISH_XRID ) {
396 completion = netvsc_rx_established_buffer;
397 } else if ( ( netvsc->wait_xrid != 0 ) &&
398 ( xrid == netvsc->wait_xrid ) ) {
399 completion = netvsc_completed;
401 DBGC ( netvsc, "NETVSC %s received unexpected completion "
402 "(%08llx)\n", netvsc->name, xid );
406 /* Hand off to completion handler */
407 rc = completion ( netvsc, data, len );
409 /* Record completion handler result if applicable */
410 if ( xrid == netvsc->wait_xrid ) {
411 netvsc->wait_xrid = 0;
412 netvsc->wait_rc = rc;
419 * Handle received cancellation packet
421 * @v vmdev VMBus device
422 * @v xid Transaction ID
423 * @ret rc Return status code
425 static int netvsc_recv_cancellation ( struct vmbus_device *vmdev,
427 struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
428 struct netvsc_device *netvsc = rndis->priv;
430 DBGC ( netvsc, "NETVSC %s received unsupported cancellation packet "
431 "(%08llx):\n", netvsc->name, xid );
435 /** VMBus channel operations */
436 static struct vmbus_channel_operations netvsc_channel_operations = {
437 .recv_control = netvsc_recv_control,
438 .recv_data = netvsc_recv_data,
439 .recv_completion = netvsc_recv_completion,
440 .recv_cancellation = netvsc_recv_cancellation,
444 * Poll for completed and received packets
446 * @v rndis RNDIS device
448 static void netvsc_poll ( struct rndis_device *rndis ) {
449 struct netvsc_device *netvsc = rndis->priv;
450 struct vmbus_device *vmdev = netvsc->vmdev;
452 /* Poll VMBus device */
453 while ( vmbus_has_data ( vmdev ) )
454 vmbus_poll ( vmdev );
460 * @v rndis RNDIS device
461 * @v iobuf I/O buffer
462 * @ret rc Return status code
464 * If this method returns success then the RNDIS device must
465 * eventually report completion via rndis_tx_complete().
467 static int netvsc_transmit ( struct rndis_device *rndis,
468 struct io_buffer *iobuf ) {
469 struct netvsc_device *netvsc = rndis->priv;
470 struct rndis_header *header = iobuf->data;
471 struct netvsc_rndis_message msg;
478 assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
479 assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) );
481 /* Check that we have space in the transmit ring */
482 if ( netvsc_ring_is_full ( &netvsc->tx ) )
483 return rndis_tx_defer ( rndis, iobuf );
485 /* Allocate buffer ID and calculate transaction ID */
486 tx_id = netvsc->tx.ids[ netvsc->tx.id_prod & ( netvsc->tx.count - 1 ) ];
487 assert ( netvsc->tx.iobufs[tx_id] == NULL );
488 xrid = ( NETVSC_TX_BASE_XRID + tx_id );
489 xid = ( NETVSC_BASE_XID + xrid );
491 /* Construct message */
492 memset ( &msg, 0, sizeof ( msg ) );
493 msg.header.type = cpu_to_le32 ( NETVSC_RNDIS_MSG );
494 msg.channel = ( ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) ?
495 NETVSC_RNDIS_DATA : NETVSC_RNDIS_CONTROL );
496 msg.buffer = cpu_to_le32 ( NETVSC_RNDIS_NO_BUFFER );
499 if ( ( rc = vmbus_send_data ( netvsc->vmdev, xid, &msg, sizeof ( msg ),
501 DBGC ( netvsc, "NETVSC %s could not send RNDIS message: %s\n",
502 netvsc->name, strerror ( rc ) );
506 /* Store I/O buffer and consume buffer ID */
507 netvsc->tx.iobufs[tx_id] = iobuf;
508 netvsc->tx.id_prod++;
514 * Cancel transmission
516 * @v netvsc NetVSC device
517 * @v iobuf I/O buffer
518 * @v tx_id Transmission ID
520 static void netvsc_cancel_transmit ( struct netvsc_device *netvsc,
521 struct io_buffer *iobuf,
522 unsigned int tx_id ) {
526 /* Send cancellation */
527 xrid = ( NETVSC_TX_BASE_XRID + tx_id );
528 xid = ( NETVSC_BASE_XID + xrid );
529 DBGC ( netvsc, "NETVSC %s cancelling transmission %#x\n",
530 netvsc->name, tx_id );
531 vmbus_send_cancellation ( netvsc->vmdev, xid );
533 /* Report back to RNDIS */
534 rndis_tx_complete_err ( netvsc->rndis, iobuf, -ECANCELED );
538 * Create descriptor ring
540 * @v netvsc NetVSC device
541 * @v ring Descriptor ring
542 * @ret rc Return status code
544 static int netvsc_create_ring ( struct netvsc_device *netvsc __unused,
545 struct netvsc_ring *ring ) {
548 /* Initialise buffer ID ring */
549 for ( i = 0 ; i < ring->count ; i++ ) {
551 assert ( ring->iobufs[i] == NULL );
560 * Destroy descriptor ring
562 * @v netvsc NetVSC device
563 * @v ring Descriptor ring
564 * @v discard Method used to discard outstanding buffer, or NULL
566 static void netvsc_destroy_ring ( struct netvsc_device *netvsc,
567 struct netvsc_ring *ring,
568 void ( * discard ) ( struct netvsc_device *,
571 struct io_buffer *iobuf;
574 /* Flush any outstanding buffers */
575 for ( i = 0 ; i < ring->count ; i++ ) {
576 iobuf = ring->iobufs[i];
579 ring->iobufs[i] = NULL;
580 ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = i;
582 discard ( netvsc, iobuf, i );
586 assert ( netvsc_ring_is_empty ( ring ) );
590 * Copy data from data buffer
592 * @v pages Transfer page set
593 * @v data Data buffer
594 * @v offset Offset within page set
595 * @v len Length within page set
596 * @ret rc Return status code
598 static int netvsc_buffer_copy ( struct vmbus_xfer_pages *pages, void *data,
599 size_t offset, size_t len ) {
600 struct netvsc_buffer *buffer =
601 container_of ( pages, struct netvsc_buffer, pages );
604 if ( ( offset > buffer->len ) || ( len > ( buffer->len - offset ) ) )
607 /* Copy data from buffer */
608 copy_from_user ( data, buffer->data, offset, len );
613 /** Transfer page set operations */
614 static struct vmbus_xfer_pages_operations netvsc_xfer_pages_operations = {
615 .copy = netvsc_buffer_copy,
621 * @v netvsc NetVSC device
622 * @v buffer Data buffer
623 * @ret rc Return status code
625 static int netvsc_create_buffer ( struct netvsc_device *netvsc,
626 struct netvsc_buffer *buffer ) {
627 struct vmbus_device *vmdev = netvsc->vmdev;
631 /* Allocate receive buffer */
632 buffer->data = umalloc ( buffer->len );
633 if ( ! buffer->data ) {
634 DBGC ( netvsc, "NETVSC %s could not allocate %zd-byte buffer\n",
635 netvsc->name, buffer->len );
640 /* Establish GPA descriptor list */
641 gpadl = vmbus_establish_gpadl ( vmdev, buffer->data, buffer->len );
644 DBGC ( netvsc, "NETVSC %s could not establish GPADL: %s\n",
645 netvsc->name, strerror ( rc ) );
646 goto err_establish_gpadl;
648 buffer->gpadl = gpadl;
650 /* Register transfer page set */
651 if ( ( rc = vmbus_register_pages ( vmdev, &buffer->pages ) ) != 0 ) {
652 DBGC ( netvsc, "NETVSC %s could not register transfer pages: "
653 "%s\n", netvsc->name, strerror ( rc ) );
654 goto err_register_pages;
659 vmbus_unregister_pages ( vmdev, &buffer->pages );
661 vmbus_gpadl_teardown ( vmdev, gpadl );
663 ufree ( buffer->data );
669 * Destroy data buffer
671 * @v netvsc NetVSC device
672 * @v buffer Data buffer
674 static void netvsc_destroy_buffer ( struct netvsc_device *netvsc,
675 struct netvsc_buffer *buffer ) {
676 struct vmbus_device *vmdev = netvsc->vmdev;
679 /* Unregister transfer pages */
680 vmbus_unregister_pages ( vmdev, &buffer->pages );
682 /* Tear down GPA descriptor list */
683 if ( ( rc = vmbus_gpadl_teardown ( vmdev, buffer->gpadl ) ) != 0 ) {
684 DBGC ( netvsc, "NETVSC %s could not tear down GPADL: %s\n",
685 netvsc->name, strerror ( rc ) );
686 /* Death is imminent. The host may well continue to
687 * write to the data buffer. The best we can do is
688 * leak memory for now and hope that the host doesn't
689 * write to this region after we load an OS.
695 ufree ( buffer->data );
701 * @v rndis RNDIS device
702 * @ret rc Return status code
704 static int netvsc_open ( struct rndis_device *rndis ) {
705 struct netvsc_device *netvsc = rndis->priv;
708 /* Initialise receive buffer */
709 if ( ( rc = netvsc_create_buffer ( netvsc, &netvsc->rx ) ) != 0 )
713 if ( ( rc = vmbus_open ( netvsc->vmdev, &netvsc_channel_operations,
714 PAGE_SIZE, PAGE_SIZE, NETVSC_MTU ) ) != 0 ) {
715 DBGC ( netvsc, "NETVSC %s could not open VMBus: %s\n",
716 netvsc->name, strerror ( rc ) );
720 /* Initialise communication with NetVSP */
721 if ( ( rc = netvsc_initialise ( netvsc ) ) != 0 )
723 if ( ( rc = netvsc_ndis_version ( netvsc ) ) != 0 )
724 goto err_ndis_version;
726 /* Initialise transmit ring */
727 if ( ( rc = netvsc_create_ring ( netvsc, &netvsc->tx ) ) != 0 )
730 /* Establish receive buffer */
731 if ( ( rc = netvsc_establish_buffer ( netvsc, &netvsc->rx ) ) != 0 )
732 goto err_establish_rx;
736 netvsc_revoke_buffer ( netvsc, &netvsc->rx );
738 netvsc_destroy_ring ( netvsc, &netvsc->tx, NULL );
742 vmbus_close ( netvsc->vmdev );
744 netvsc_destroy_buffer ( netvsc, &netvsc->rx );
752 * @v rndis RNDIS device
754 static void netvsc_close ( struct rndis_device *rndis ) {
755 struct netvsc_device *netvsc = rndis->priv;
757 /* Revoke receive buffer */
758 netvsc_revoke_buffer ( netvsc, &netvsc->rx );
760 /* Destroy transmit ring */
761 netvsc_destroy_ring ( netvsc, &netvsc->tx, netvsc_cancel_transmit );
764 vmbus_close ( netvsc->vmdev );
766 /* Destroy receive buffer */
767 netvsc_destroy_buffer ( netvsc, &netvsc->rx );
770 /** RNDIS operations */
771 static struct rndis_operations netvsc_operations = {
773 .close = netvsc_close,
774 .transmit = netvsc_transmit,
781 * @v vmdev VMBus device
782 * @ret rc Return status code
784 static int netvsc_probe ( struct vmbus_device *vmdev ) {
785 struct netvsc_device *netvsc;
786 struct rndis_device *rndis;
789 /* Allocate and initialise structure */
790 rndis = alloc_rndis ( sizeof ( *netvsc ) );
795 rndis_init ( rndis, &netvsc_operations );
796 rndis->netdev->dev = &vmdev->dev;
797 netvsc = rndis->priv;
798 netvsc->vmdev = vmdev;
799 netvsc->rndis = rndis;
800 netvsc->name = vmdev->dev.name;
801 netvsc_init_ring ( &netvsc->tx, NETVSC_TX_NUM_DESC,
802 netvsc->tx_iobufs, netvsc->tx_ids );
803 netvsc_init_buffer ( &netvsc->rx, NETVSC_RX_BUF_PAGESET,
804 &netvsc_xfer_pages_operations,
805 NETVSC_RX_ESTABLISH_MSG, NETVSC_RX_ESTABLISH_XRID,
806 NETVSC_RX_REVOKE_MSG, NETVSC_RX_REVOKE_XRID,
808 vmbus_set_drvdata ( vmdev, rndis );
810 /* Register RNDIS device */
811 if ( ( rc = register_rndis ( rndis ) ) != 0 ) {
812 DBGC ( netvsc, "NETVSC %s could not register: %s\n",
813 netvsc->name, strerror ( rc ) );
819 unregister_rndis ( rndis );
821 free_rndis ( rndis );
829 * @v vmdev VMBus device
831 static void netvsc_remove ( struct vmbus_device *vmdev ) {
832 struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
834 /* Unregister RNDIS device */
835 unregister_rndis ( rndis );
837 /* Free RNDIS device */
838 free_rndis ( rndis );
842 struct vmbus_driver netvsc_driver __vmbus_driver = {
844 .type = VMBUS_TYPE ( 0xf8615163, 0xdf3e, 0x46c5, 0x913f,
845 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e ),
846 .probe = netvsc_probe,
847 .remove = netvsc_remove,