2 * Copyright (C) 2011 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 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
20 FILE_LICENCE ( GPL2_OR_LATER );
28 #include <ipxe/malloc.h>
29 #include <ipxe/profile.h>
30 #include <ipxe/iobuf.h>
31 #include <ipxe/netdevice.h>
32 #include <ipxe/if_ether.h>
33 #include <ipxe/ethernet.h>
39 * VMware vmxnet3 virtual NIC driver
43 /** VM command profiler */
44 static struct profiler vmxnet3_vm_command_profiler __profiler =
45 { .name = "vmxnet3.vm_command" };
47 /** VM transmit profiler */
48 static struct profiler vmxnet3_vm_tx_profiler __profiler =
49 { .name = "vmxnet3.vm_tx" };
51 /** VM receive refill profiler */
52 static struct profiler vmxnet3_vm_refill_profiler __profiler =
53 { .name = "vmxnet3.vm_refill" };
55 /** VM event profiler */
56 static struct profiler vmxnet3_vm_event_profiler __profiler =
57 { .name = "vmxnet3.vm_event" };
62 * @v vmxnet vmxnet3 NIC
63 * @v command Command to issue
64 * @ret result Command result
66 static inline uint32_t vmxnet3_command ( struct vmxnet3_nic *vmxnet,
71 profile_start ( &vmxnet3_vm_command_profiler );
72 writel ( command, ( vmxnet->vd + VMXNET3_VD_CMD ) );
73 result = readl ( vmxnet->vd + VMXNET3_VD_CMD );
74 profile_stop ( &vmxnet3_vm_command_profiler );
75 profile_exclude ( &vmxnet3_vm_command_profiler );
83 * @v netdev Network device
85 * @ret rc Return status code
87 static int vmxnet3_transmit ( struct net_device *netdev,
88 struct io_buffer *iobuf ) {
89 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
90 struct vmxnet3_tx_desc *tx_desc;
91 unsigned int desc_idx;
92 unsigned int generation;
94 /* Check that we have a free transmit descriptor */
95 desc_idx = ( vmxnet->count.tx_prod % VMXNET3_NUM_TX_DESC );
96 generation = ( ( vmxnet->count.tx_prod & VMXNET3_NUM_TX_DESC ) ?
97 0 : cpu_to_le32 ( VMXNET3_TXF_GEN ) );
98 if ( vmxnet->tx_iobuf[desc_idx] ) {
99 DBGC ( vmxnet, "VMXNET3 %p out of transmit descriptors\n",
104 /* Increment producer counter */
105 vmxnet->count.tx_prod++;
107 /* Store I/O buffer for later completion */
108 vmxnet->tx_iobuf[desc_idx] = iobuf;
110 /* Populate transmit descriptor */
111 tx_desc = &vmxnet->dma->tx_desc[desc_idx];
112 tx_desc->address = cpu_to_le64 ( virt_to_bus ( iobuf->data ) );
113 tx_desc->flags[0] = ( generation | cpu_to_le32 ( iob_len ( iobuf ) ) );
114 tx_desc->flags[1] = cpu_to_le32 ( VMXNET3_TXF_CQ | VMXNET3_TXF_EOP );
116 /* Hand over descriptor to NIC */
118 profile_start ( &vmxnet3_vm_tx_profiler );
119 writel ( ( vmxnet->count.tx_prod % VMXNET3_NUM_TX_DESC ),
120 ( vmxnet->pt + VMXNET3_PT_TXPROD ) );
121 profile_stop ( &vmxnet3_vm_tx_profiler );
122 profile_exclude ( &vmxnet3_vm_tx_profiler );
128 * Poll for completed transmissions
130 * @v netdev Network device
132 static void vmxnet3_poll_tx ( struct net_device *netdev ) {
133 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
134 struct vmxnet3_tx_comp *tx_comp;
135 struct io_buffer *iobuf;
136 unsigned int comp_idx;
137 unsigned int desc_idx;
138 unsigned int generation;
142 /* Look for completed descriptors */
143 comp_idx = ( vmxnet->count.tx_cons % VMXNET3_NUM_TX_COMP );
144 generation = ( ( vmxnet->count.tx_cons & VMXNET3_NUM_TX_COMP ) ?
145 0 : cpu_to_le32 ( VMXNET3_TXCF_GEN ) );
146 tx_comp = &vmxnet->dma->tx_comp[comp_idx];
147 if ( generation != ( tx_comp->flags &
148 cpu_to_le32 ( VMXNET3_TXCF_GEN ) ) ) {
152 /* Increment consumer counter */
153 vmxnet->count.tx_cons++;
155 /* Locate corresponding transmit descriptor */
156 desc_idx = ( le32_to_cpu ( tx_comp->index ) %
157 VMXNET3_NUM_TX_DESC );
158 iobuf = vmxnet->tx_iobuf[desc_idx];
160 DBGC ( vmxnet, "VMXNET3 %p completed on empty transmit "
161 "buffer %#x/%#x\n", vmxnet, comp_idx, desc_idx );
162 netdev_tx_err ( netdev, NULL, -ENOTTY );
166 /* Remove I/O buffer from transmit queue */
167 vmxnet->tx_iobuf[desc_idx] = NULL;
169 /* Report transmission completion to network layer */
170 DBGC2 ( vmxnet, "VMXNET3 %p completed TX %#x/%#x (len %#zx)\n",
171 vmxnet, comp_idx, desc_idx, iob_len ( iobuf ) );
172 netdev_tx_complete ( netdev, iobuf );
177 * Flush any uncompleted transmit buffers
179 * @v netdev Network device
181 static void vmxnet3_flush_tx ( struct net_device *netdev ) {
182 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
185 for ( i = 0 ; i < VMXNET3_NUM_TX_DESC ; i++ ) {
186 if ( vmxnet->tx_iobuf[i] ) {
187 netdev_tx_complete_err ( netdev, vmxnet->tx_iobuf[i],
189 vmxnet->tx_iobuf[i] = NULL;
195 * Refill receive ring
197 * @v netdev Network device
199 static void vmxnet3_refill_rx ( struct net_device *netdev ) {
200 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
201 struct vmxnet3_rx_desc *rx_desc;
202 struct io_buffer *iobuf;
203 unsigned int orig_rx_prod = vmxnet->count.rx_prod;
204 unsigned int desc_idx;
205 unsigned int generation;
207 /* Fill receive ring to specified fill level */
208 while ( vmxnet->count.rx_fill < VMXNET3_RX_FILL ) {
210 /* Locate receive descriptor */
211 desc_idx = ( vmxnet->count.rx_prod % VMXNET3_NUM_RX_DESC );
212 generation = ( ( vmxnet->count.rx_prod & VMXNET3_NUM_RX_DESC ) ?
213 0 : cpu_to_le32 ( VMXNET3_RXF_GEN ) );
214 assert ( vmxnet->rx_iobuf[desc_idx] == NULL );
216 /* Allocate I/O buffer */
217 iobuf = alloc_iob ( VMXNET3_MTU + NET_IP_ALIGN );
219 /* Non-fatal low memory condition */
222 iob_reserve ( iobuf, NET_IP_ALIGN );
224 /* Increment producer counter and fill level */
225 vmxnet->count.rx_prod++;
226 vmxnet->count.rx_fill++;
228 /* Store I/O buffer for later completion */
229 vmxnet->rx_iobuf[desc_idx] = iobuf;
231 /* Populate receive descriptor */
232 rx_desc = &vmxnet->dma->rx_desc[desc_idx];
233 rx_desc->address = cpu_to_le64 ( virt_to_bus ( iobuf->data ) );
234 rx_desc->flags = ( generation | cpu_to_le32 ( VMXNET3_MTU ) );
238 /* Hand over any new descriptors to NIC */
239 if ( vmxnet->count.rx_prod != orig_rx_prod ) {
241 profile_start ( &vmxnet3_vm_refill_profiler );
242 writel ( ( vmxnet->count.rx_prod % VMXNET3_NUM_RX_DESC ),
243 ( vmxnet->pt + VMXNET3_PT_RXPROD ) );
244 profile_stop ( &vmxnet3_vm_refill_profiler );
245 profile_exclude ( &vmxnet3_vm_refill_profiler );
250 * Poll for received packets
252 * @v netdev Network device
254 static void vmxnet3_poll_rx ( struct net_device *netdev ) {
255 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
256 struct vmxnet3_rx_comp *rx_comp;
257 struct io_buffer *iobuf;
258 unsigned int comp_idx;
259 unsigned int desc_idx;
260 unsigned int generation;
265 /* Look for completed descriptors */
266 comp_idx = ( vmxnet->count.rx_cons % VMXNET3_NUM_RX_COMP );
267 generation = ( ( vmxnet->count.rx_cons & VMXNET3_NUM_RX_COMP ) ?
268 0 : cpu_to_le32 ( VMXNET3_RXCF_GEN ) );
269 rx_comp = &vmxnet->dma->rx_comp[comp_idx];
270 if ( generation != ( rx_comp->flags &
271 cpu_to_le32 ( VMXNET3_RXCF_GEN ) ) ) {
275 /* Increment consumer counter */
276 vmxnet->count.rx_cons++;
278 /* Locate corresponding receive descriptor */
279 desc_idx = ( le32_to_cpu ( rx_comp->index ) %
280 VMXNET3_NUM_RX_DESC );
281 iobuf = vmxnet->rx_iobuf[desc_idx];
283 DBGC ( vmxnet, "VMXNET3 %p completed on empty receive "
284 "buffer %#x/%#x\n", vmxnet, comp_idx, desc_idx );
285 netdev_rx_err ( netdev, NULL, -ENOTTY );
289 /* Remove I/O buffer from receive queue */
290 vmxnet->rx_iobuf[desc_idx] = NULL;
291 vmxnet->count.rx_fill--;
293 /* Deliver packet to network layer */
294 len = ( le32_to_cpu ( rx_comp->len ) &
295 ( VMXNET3_MAX_PACKET_LEN - 1 ) );
296 DBGC2 ( vmxnet, "VMXNET3 %p completed RX %#x/%#x (len %#zx)\n",
297 vmxnet, comp_idx, desc_idx, len );
298 iob_put ( iobuf, len );
299 netdev_rx ( netdev, iobuf );
304 * Flush any uncompleted receive buffers
306 * @v netdev Network device
308 static void vmxnet3_flush_rx ( struct net_device *netdev ) {
309 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
310 struct io_buffer *iobuf;
313 for ( i = 0 ; i < VMXNET3_NUM_RX_DESC ; i++ ) {
314 if ( ( iobuf = vmxnet->rx_iobuf[i] ) != NULL ) {
315 netdev_rx_err ( netdev, iobuf, -ECANCELED );
316 vmxnet->rx_iobuf[i] = NULL;
324 * @v netdev Network device
326 static void vmxnet3_check_link ( struct net_device *netdev ) {
327 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
330 unsigned int link_speed;
333 state = vmxnet3_command ( vmxnet, VMXNET3_CMD_GET_LINK );
334 link_up = ( state & 1 );
335 link_speed = ( state >> 16 );
337 /* Report link state to network device */
339 DBGC ( vmxnet, "VMXNET3 %p link is up at %d Mbps\n",
340 vmxnet, link_speed );
341 netdev_link_up ( netdev );
343 DBGC ( vmxnet, "VMXNET3 %p link is down\n", vmxnet );
344 netdev_link_down ( netdev );
351 * @v netdev Network device
353 static void vmxnet3_poll_events ( struct net_device *netdev ) {
354 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
357 /* Do nothing unless there are events to process */
358 if ( ! vmxnet->dma->shared.ecr )
360 events = le32_to_cpu ( vmxnet->dma->shared.ecr );
362 /* Acknowledge these events */
363 profile_start ( &vmxnet3_vm_event_profiler );
364 writel ( events, ( vmxnet->vd + VMXNET3_VD_ECR ) );
365 profile_stop ( &vmxnet3_vm_event_profiler );
366 profile_exclude ( &vmxnet3_vm_event_profiler );
368 /* Check for link state change */
369 if ( events & VMXNET3_ECR_LINK ) {
370 vmxnet3_check_link ( netdev );
371 events &= ~VMXNET3_ECR_LINK;
374 /* Check for queue errors */
375 if ( events & ( VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR ) ) {
376 vmxnet3_command ( vmxnet, VMXNET3_CMD_GET_QUEUE_STATUS );
377 DBGC ( vmxnet, "VMXNET3 %p queue error status (TX %08x, RX "
379 le32_to_cpu ( vmxnet->dma->queues.tx.status.error ),
380 le32_to_cpu ( vmxnet->dma->queues.rx.status.error ) );
381 /* Report errors to allow for visibility via "ifstat" */
382 if ( events & VMXNET3_ECR_TQERR )
383 netdev_tx_err ( netdev, NULL, -EPIPE );
384 if ( events & VMXNET3_ECR_RQERR )
385 netdev_rx_err ( netdev, NULL, -EPIPE );
386 events &= ~( VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR );
389 /* Check for unknown events */
391 DBGC ( vmxnet, "VMXNET3 %p unknown events %08x\n",
393 /* Report error to allow for visibility via "ifstat" */
394 netdev_rx_err ( netdev, NULL, -ENODEV );
399 * Poll network device
401 * @v netdev Network device
403 static void vmxnet3_poll ( struct net_device *netdev ) {
405 vmxnet3_poll_events ( netdev );
406 vmxnet3_poll_tx ( netdev );
407 vmxnet3_poll_rx ( netdev );
408 vmxnet3_refill_rx ( netdev );
412 * Enable/disable interrupts
414 * @v netdev Network device
415 * @v enable Interrupts should be enabled
417 static void vmxnet3_irq ( struct net_device *netdev, int enable ) {
418 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
420 DBGC ( vmxnet, "VMXNET3 %p %s IRQ not implemented\n",
421 vmxnet, ( enable ? "enable" : "disable" ) );
427 * @v vmxnet vmxnet3 NIC
428 * @v ll_addr Link-layer address to set
430 static void vmxnet3_set_ll_addr ( struct vmxnet3_nic *vmxnet,
431 const void *ll_addr ) {
435 } __attribute__ (( packed )) mac;
437 memset ( &mac, 0, sizeof ( mac ) );
438 memcpy ( &mac, ll_addr, ETH_ALEN );
439 writel ( cpu_to_le32 ( mac.low ), ( vmxnet->vd + VMXNET3_VD_MACL ) );
440 writel ( cpu_to_le32 ( mac.high ), ( vmxnet->vd + VMXNET3_VD_MACH ) );
446 * @v netdev Network device
447 * @ret rc Return status code
449 static int vmxnet3_open ( struct net_device *netdev ) {
450 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
451 struct vmxnet3_shared *shared;
452 struct vmxnet3_queues *queues;
458 /* Allocate DMA areas */
459 vmxnet->dma = malloc_dma ( sizeof ( *vmxnet->dma ), VMXNET3_DMA_ALIGN );
460 if ( ! vmxnet->dma ) {
461 DBGC ( vmxnet, "VMXNET3 %p could not allocate DMA area\n",
466 memset ( vmxnet->dma, 0, sizeof ( *vmxnet->dma ) );
468 /* Populate queue descriptors */
469 queues = &vmxnet->dma->queues;
470 queues->tx.cfg.desc_address =
471 cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->tx_desc ) );
472 queues->tx.cfg.comp_address =
473 cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->tx_comp ) );
474 queues->tx.cfg.num_desc = cpu_to_le32 ( VMXNET3_NUM_TX_DESC );
475 queues->tx.cfg.num_comp = cpu_to_le32 ( VMXNET3_NUM_TX_COMP );
476 queues->rx.cfg.desc_address[0] =
477 cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->rx_desc ) );
478 queues->rx.cfg.comp_address =
479 cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->rx_comp ) );
480 queues->rx.cfg.num_desc[0] = cpu_to_le32 ( VMXNET3_NUM_RX_DESC );
481 queues->rx.cfg.num_comp = cpu_to_le32 ( VMXNET3_NUM_RX_COMP );
482 queues_bus = virt_to_bus ( queues );
483 DBGC ( vmxnet, "VMXNET3 %p queue descriptors at %08llx+%zx\n",
484 vmxnet, queues_bus, sizeof ( *queues ) );
486 /* Populate shared area */
487 shared = &vmxnet->dma->shared;
488 shared->magic = cpu_to_le32 ( VMXNET3_SHARED_MAGIC );
489 shared->misc.version = cpu_to_le32 ( VMXNET3_VERSION_MAGIC );
490 shared->misc.version_support = cpu_to_le32 ( VMXNET3_VERSION_SELECT );
491 shared->misc.upt_version_support =
492 cpu_to_le32 ( VMXNET3_UPT_VERSION_SELECT );
493 shared->misc.queue_desc_address = cpu_to_le64 ( queues_bus );
494 shared->misc.queue_desc_len = cpu_to_le32 ( sizeof ( *queues ) );
495 shared->misc.mtu = cpu_to_le32 ( VMXNET3_MTU );
496 shared->misc.num_tx_queues = 1;
497 shared->misc.num_rx_queues = 1;
498 shared->interrupt.num_intrs = 1;
499 shared->interrupt.control = cpu_to_le32 ( VMXNET3_IC_DISABLE_ALL );
500 shared->rx_filter.mode = cpu_to_le32 ( VMXNET3_RXM_UCAST |
502 VMXNET3_RXM_ALL_MULTI );
503 shared_bus = virt_to_bus ( shared );
504 DBGC ( vmxnet, "VMXNET3 %p shared area at %08llx+%zx\n",
505 vmxnet, shared_bus, sizeof ( *shared ) );
508 memset ( &vmxnet->count, 0, sizeof ( vmxnet->count ) );
510 /* Set MAC address */
511 vmxnet3_set_ll_addr ( vmxnet, &netdev->ll_addr );
513 /* Pass shared area to device */
514 writel ( ( shared_bus >> 0 ), ( vmxnet->vd + VMXNET3_VD_DSAL ) );
515 writel ( ( shared_bus >> 32 ), ( vmxnet->vd + VMXNET3_VD_DSAH ) );
517 /* Activate device */
518 if ( ( status = vmxnet3_command ( vmxnet,
519 VMXNET3_CMD_ACTIVATE_DEV ) ) != 0 ) {
520 DBGC ( vmxnet, "VMXNET3 %p could not activate (status %#x)\n",
526 /* Fill receive ring */
527 vmxnet3_refill_rx ( netdev );
531 vmxnet3_command ( vmxnet, VMXNET3_CMD_QUIESCE_DEV );
532 vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV );
534 vmxnet3_flush_tx ( netdev );
535 vmxnet3_flush_rx ( netdev );
536 free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) );
544 * @v netdev Network device
546 static void vmxnet3_close ( struct net_device *netdev ) {
547 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
549 vmxnet3_command ( vmxnet, VMXNET3_CMD_QUIESCE_DEV );
550 vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV );
551 vmxnet3_flush_tx ( netdev );
552 vmxnet3_flush_rx ( netdev );
553 free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) );
556 /** vmxnet3 net device operations */
557 static struct net_device_operations vmxnet3_operations = {
558 .open = vmxnet3_open,
559 .close = vmxnet3_close,
560 .transmit = vmxnet3_transmit,
561 .poll = vmxnet3_poll,
568 * @v vmxnet vmxnet3 NIC
569 * @ret rc Return status code
571 static int vmxnet3_check_version ( struct vmxnet3_nic *vmxnet ) {
573 uint32_t upt_version;
576 version = readl ( vmxnet->vd + VMXNET3_VD_VRRS );
577 upt_version = readl ( vmxnet->vd + VMXNET3_VD_UVRS );
578 DBGC ( vmxnet, "VMXNET3 %p is version %d (UPT version %d)\n",
579 vmxnet, version, upt_version );
581 /* Inform NIC of driver version */
582 writel ( VMXNET3_VERSION_SELECT, ( vmxnet->vd + VMXNET3_VD_VRRS ) );
583 writel ( VMXNET3_UPT_VERSION_SELECT, ( vmxnet->vd + VMXNET3_VD_UVRS ) );
589 * Get permanent MAC address
591 * @v vmxnet vmxnet3 NIC
592 * @v hw_addr Hardware address to fill in
594 static void vmxnet3_get_hw_addr ( struct vmxnet3_nic *vmxnet, void *hw_addr ) {
598 } __attribute__ (( packed )) mac;
600 mac.low = le32_to_cpu ( vmxnet3_command ( vmxnet,
601 VMXNET3_CMD_GET_PERM_MAC_LO ) );
602 mac.high = le32_to_cpu ( vmxnet3_command ( vmxnet,
603 VMXNET3_CMD_GET_PERM_MAC_HI ) );
604 memcpy ( hw_addr, &mac, ETH_ALEN );
612 * @ret rc Return status code
614 static int vmxnet3_probe ( struct pci_device *pci ) {
615 struct net_device *netdev;
616 struct vmxnet3_nic *vmxnet;
619 /* Allocate network device */
620 netdev = alloc_etherdev ( sizeof ( *vmxnet ) );
623 goto err_alloc_etherdev;
625 netdev_init ( netdev, &vmxnet3_operations );
626 vmxnet = netdev_priv ( netdev );
627 pci_set_drvdata ( pci, netdev );
628 netdev->dev = &pci->dev;
629 memset ( vmxnet, 0, sizeof ( *vmxnet ) );
631 /* Fix up PCI device */
632 adjust_pci_device ( pci );
635 vmxnet->pt = ioremap ( pci_bar_start ( pci, VMXNET3_PT_BAR ),
637 if ( ! vmxnet->pt ) {
641 vmxnet->vd = ioremap ( pci_bar_start ( pci, VMXNET3_VD_BAR ),
643 if ( ! vmxnet->vd ) {
649 if ( ( rc = vmxnet3_check_version ( vmxnet ) ) != 0 )
650 goto err_check_version;
653 if ( ( rc = vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV ) ) != 0 )
656 /* Read initial MAC address */
657 vmxnet3_get_hw_addr ( vmxnet, &netdev->hw_addr );
659 /* Register network device */
660 if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
661 DBGC ( vmxnet, "VMXNET3 %p could not register net device: "
662 "%s\n", vmxnet, strerror ( rc ) );
663 goto err_register_netdev;
666 /* Get initial link state */
667 vmxnet3_check_link ( netdev );
671 unregister_netdev ( netdev );
675 iounmap ( vmxnet->vd );
677 iounmap ( vmxnet->pt );
679 netdev_nullify ( netdev );
680 netdev_put ( netdev );
690 static void vmxnet3_remove ( struct pci_device *pci ) {
691 struct net_device *netdev = pci_get_drvdata ( pci );
692 struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
694 unregister_netdev ( netdev );
695 iounmap ( vmxnet->vd );
696 iounmap ( vmxnet->pt );
697 netdev_nullify ( netdev );
698 netdev_put ( netdev );
701 /** vmxnet3 PCI IDs */
702 static struct pci_device_id vmxnet3_nics[] = {
703 PCI_ROM ( 0x15ad, 0x07b0, "vmxnet3", "vmxnet3 virtual NIC", 0 ),
706 /** vmxnet3 PCI driver */
707 struct pci_driver vmxnet3_driver __pci_driver = {
709 .id_count = ( sizeof ( vmxnet3_nics ) / sizeof ( vmxnet3_nics[0] ) ),
710 .probe = vmxnet3_probe,
711 .remove = vmxnet3_remove,