Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / net / igbvf / igbvf_main.c
diff --git a/qemu/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c b/qemu/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
new file mode 100644 (file)
index 0000000..aace5ad
--- /dev/null
@@ -0,0 +1,953 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 2009 Intel Corporation.
+
+  Copyright(c) 2010 Eric Keller <ekeller@princeton.edu>
+  Copyright(c) 2010 Red Hat Inc.
+       Alex Williamson <alex.williamson@redhat.com>
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include "igbvf.h"
+
+/**
+ * igbvf_setup_tx_resources - allocate Tx resources (Descriptors)
+ *
+ * @v adapter   e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter )
+{
+       DBG ( "igbvf_setup_tx_resources\n" );
+
+       /* Allocate transmit descriptor ring memory.
+          It must not cross a 64K boundary because of hardware errata #23
+          so we use malloc_dma() requesting a 128 byte block that is
+          128 byte aligned. This should guarantee that the memory
+          allocated will not cross a 64K boundary, because 128 is an
+          even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
+          allocations of 128 bytes on a 128 byte boundary will not
+          cross 64K bytes.
+        */
+
+       adapter->tx_base =
+               malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
+
+       if ( ! adapter->tx_base ) {
+               return -ENOMEM;
+       }
+
+       memset ( adapter->tx_base, 0, adapter->tx_ring_size );
+
+       DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
+
+       return 0;
+}
+
+/**
+ * igbvf_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+void igbvf_free_tx_resources ( struct igbvf_adapter *adapter )
+{
+       DBG ( "igbvf_free_tx_resources\n" );
+
+       free_dma ( adapter->tx_base, adapter->tx_ring_size );
+}
+
+/**
+ * igbvf_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+void igbvf_free_rx_resources ( struct igbvf_adapter *adapter )
+{
+       int i;
+
+       DBG ( "igbvf_free_rx_resources\n" );
+
+       free_dma ( adapter->rx_base, adapter->rx_ring_size );
+
+       for ( i = 0; i < NUM_RX_DESC; i++ ) {
+               free_iob ( adapter->rx_iobuf[i] );
+       }
+}
+
+/**
+ * igbvf_refill_rx_ring - allocate Rx io_buffers
+ *
+ * @v adapter   e1000 private structure
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ **/
+static int igbvf_refill_rx_ring ( struct igbvf_adapter *adapter )
+{
+       int i, rx_curr;
+       int rc = 0;
+       union e1000_adv_rx_desc *rx_curr_desc;
+       struct e1000_hw *hw = &adapter->hw;
+       struct io_buffer *iob;
+
+       DBGP ("igbvf_refill_rx_ring\n");
+
+       for ( i = 0; i < NUM_RX_DESC; i++ ) {
+               rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
+               rx_curr_desc = adapter->rx_base + rx_curr;
+
+               if ( rx_curr_desc->wb.upper.status_error & E1000_RXD_STAT_DD )
+                       continue;
+
+               if ( adapter->rx_iobuf[rx_curr] != NULL )
+                       continue;
+
+               DBG2 ( "Refilling rx desc %d\n", rx_curr );
+
+               iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+               adapter->rx_iobuf[rx_curr] = iob;
+
+               rx_curr_desc->wb.upper.status_error = 0;
+
+               if ( ! iob ) {
+                       DBG ( "alloc_iob failed\n" );
+                       rc = -ENOMEM;
+                       break;
+               } else {
+                       rx_curr_desc->read.pkt_addr = virt_to_bus ( iob->data );
+                       rx_curr_desc->read.hdr_addr = 0;
+                       ew32 ( RDT(0), rx_curr );
+               }
+       }
+       return rc;
+}
+
+/**
+ * igbvf_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static void igbvf_irq_disable ( struct igbvf_adapter *adapter )
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       ew32 ( EIMC, ~0 );
+}
+
+/**
+ * igbvf_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static void igbvf_irq_enable ( struct igbvf_adapter *adapter )
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       ew32 ( EIAC, IMS_ENABLE_MASK );
+       ew32 ( EIAM, IMS_ENABLE_MASK );
+       ew32 ( EIMS, IMS_ENABLE_MASK );
+}
+
+/**
+ * igbvf_irq - enable or Disable interrupts
+ *
+ * @v adapter   e1000 adapter
+ * @v action    requested interrupt action
+ **/
+static void igbvf_irq ( struct net_device *netdev, int enable )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+
+       DBG ( "igbvf_irq\n" );
+
+       if ( enable ) {
+               igbvf_irq_enable ( adapter );
+       } else {
+               igbvf_irq_disable ( adapter );
+       }
+}
+
+/**
+ * igbvf_process_tx_packets - process transmitted packets
+ *
+ * @v netdev    network interface device structure
+ **/
+static void igbvf_process_tx_packets ( struct net_device *netdev )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+       uint32_t i;
+       uint32_t tx_status;
+       union e1000_adv_tx_desc *tx_curr_desc;
+
+       /* Check status of transmitted packets
+        */
+       DBGP ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
+             adapter->tx_tail );
+
+       while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
+
+               tx_curr_desc = ( void * )  ( adapter->tx_base ) +
+                                          ( i * sizeof ( *adapter->tx_base ) );
+
+               tx_status = tx_curr_desc->wb.status;
+               DBG ( "  tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+               DBG ( "  tx_status = %#08x\n", tx_status );
+
+               /* if the packet at tx_head is not owned by hardware it is for us */
+               if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
+                       break;
+
+               DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
+                     adapter->tx_head, adapter->tx_tail, tx_status );
+
+               netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
+               DBG ( "Success transmitting packet, tx_status: %#08x\n",
+                     tx_status );
+
+               /* Decrement count of used descriptors, clear this descriptor
+                */
+               adapter->tx_fill_ctr--;
+               memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+               adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
+       }
+}
+
+/**
+ * igbvf_process_rx_packets - process received packets
+ *
+ * @v netdev    network interface device structure
+ **/
+static void igbvf_process_rx_packets ( struct net_device *netdev )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+       struct e1000_hw *hw = &adapter->hw;
+       uint32_t i;
+       uint32_t rx_status;
+       uint32_t rx_len;
+       uint32_t rx_err;
+       union e1000_adv_rx_desc *rx_curr_desc;
+
+       DBGP ( "igbvf_process_rx_packets\n" );
+
+       /* Process received packets
+        */
+       while ( 1 ) {
+               i = adapter->rx_curr;
+
+               rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+                                 ( i * sizeof ( *adapter->rx_base ) );
+               rx_status = rx_curr_desc->wb.upper.status_error;
+
+               DBG2 ( "Before DD Check RX_status: %#08x, rx_curr: %d\n",
+                      rx_status, i );
+
+               if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+                       break;
+
+               if ( adapter->rx_iobuf[i] == NULL )
+                       break;
+
+               DBG ( "E1000_RCTL = %#08x\n", er32 (RCTL) );
+
+               rx_len = rx_curr_desc->wb.upper.length;
+
+               DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
+                     i, rx_status, rx_len );
+
+               rx_err = rx_status;
+
+               iob_put ( adapter->rx_iobuf[i], rx_len );
+
+               if ( rx_err & E1000_RXDEXT_ERR_FRAME_ERR_MASK ) {
+
+                       netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
+                       DBG ( "igbvf_process_rx_packets: Corrupted packet received!"
+                             " rx_err: %#08x\n", rx_err );
+               } else  {
+                       /* Add this packet to the receive queue. */
+                       netdev_rx ( netdev, adapter->rx_iobuf[i] );
+               }
+               adapter->rx_iobuf[i] = NULL;
+
+               memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+               adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
+       }
+}
+
+/**
+ * igbvf_poll - Poll for received packets
+ *
+ * @v netdev    Network device
+ */
+static void igbvf_poll ( struct net_device *netdev )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+       uint32_t rx_status;
+       union e1000_adv_rx_desc *rx_curr_desc;
+
+       DBGP ( "igbvf_poll\n" );
+
+       rx_curr_desc = ( void * )  ( adapter->rx_base ) +
+                       ( adapter->rx_curr * sizeof ( *adapter->rx_base ) );
+       rx_status = rx_curr_desc->wb.upper.status_error;
+
+       if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
+               return;
+
+       igbvf_process_tx_packets ( netdev );
+
+       igbvf_process_rx_packets ( netdev );
+
+       igbvf_refill_rx_ring ( adapter );
+}
+
+/**
+ *  igbvf_config_collision_dist_generic - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void igbvf_config_collision_dist ( struct e1000_hw *hw )
+{
+       u32 tctl;
+
+       DBG ("igbvf_config_collision_dist");
+
+       tctl = er32 (TCTL);
+
+       tctl &= ~E1000_TCTL_COLD;
+       tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+       ew32 (TCTL, tctl);
+       e1e_flush();
+}
+
+/**
+ * igbvf_configure_tx - Configure Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void igbvf_configure_tx ( struct igbvf_adapter *adapter )
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 tctl, txdctl;
+
+       DBG ( "igbvf_configure_tx\n" );
+
+       /* disable transmits while setting up the descriptors */
+       tctl = er32 ( TCTL );
+       ew32 ( TCTL, tctl & ~E1000_TCTL_EN );
+       e1e_flush();
+       mdelay (10);
+
+       ew32 ( TDBAH(0), 0 );
+       ew32 ( TDBAL(0), virt_to_bus ( adapter->tx_base ) );
+       ew32 ( TDLEN(0), adapter->tx_ring_size );
+
+       DBG ( "E1000_TDBAL(0): %#08x\n",  er32 ( TDBAL(0) ) );
+       DBG ( "E1000_TDLEN(0): %d\n",     er32 ( TDLEN(0) ) );
+
+       /* Setup the HW Tx Head and Tail descriptor pointers */
+       ew32 ( TDH(0), 0 );
+       ew32 ( TDT(0), 0 );
+
+       adapter->tx_head = 0;
+       adapter->tx_tail = 0;
+       adapter->tx_fill_ctr = 0;
+
+       txdctl = er32(TXDCTL(0));
+       txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+       ew32 ( TXDCTL(0), txdctl );
+
+       txdctl = er32 ( TXDCTL(0) );
+       txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+       ew32 ( TXDCTL(0), txdctl );
+
+       /* Setup Transmit Descriptor Settings for eop descriptor */
+       adapter->txd_cmd  = E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_IFCS;
+
+       /* Advanced descriptor */
+       adapter->txd_cmd |= E1000_ADVTXD_DCMD_DEXT;
+
+       /* (not part of cmd, but in same 32 bit word...) */
+       adapter->txd_cmd |= E1000_ADVTXD_DTYP_DATA;
+
+       /* enable Report Status bit */
+       adapter->txd_cmd |= E1000_ADVTXD_DCMD_RS;
+
+       /* Program the Transmit Control Register */
+       tctl &= ~E1000_TCTL_CT;
+       tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+               (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+       igbvf_config_collision_dist ( hw );
+
+       /* Enable transmits */
+       tctl |= E1000_TCTL_EN;
+       ew32(TCTL, tctl);
+       e1e_flush();
+}
+
+/* igbvf_reset - bring the hardware into a known good state
+ *
+ * This function boots the hardware and enables some settings that
+ * require a configuration cycle of the hardware - those cannot be
+ * set/changed during runtime. After reset the device needs to be
+ * properly configured for Rx, Tx etc.
+ */
+void igbvf_reset ( struct igbvf_adapter *adapter )
+{
+       struct e1000_mac_info *mac = &adapter->hw.mac;
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+
+       /* Allow time for pending master requests to run */
+       if ( mac->ops.reset_hw(hw) )
+               DBG ("PF still resetting\n");
+
+       mac->ops.init_hw ( hw );
+
+       if ( is_valid_ether_addr(adapter->hw.mac.addr) ) {
+               memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN );
+       }
+}
+
+extern void igbvf_init_function_pointers_vf(struct e1000_hw *hw);
+
+/**
+ * igbvf_sw_init - Initialize general software structures (struct igbvf_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igbvf_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit igbvf_sw_init ( struct igbvf_adapter *adapter )
+{
+        struct e1000_hw *hw = &adapter->hw;
+        struct pci_device *pdev = adapter->pdev;
+        int rc;
+
+        /* PCI config space info */
+
+        hw->vendor_id = pdev->vendor;
+        hw->device_id = pdev->device;
+
+        pci_read_config_byte ( pdev, PCI_REVISION_ID, &hw->revision_id );
+
+        pci_read_config_word ( pdev, PCI_COMMAND, &hw->bus.pci_cmd_word );
+
+        adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ETH_HLEN + ETH_FCS_LEN;
+        adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+       /* Set various function pointers */
+        igbvf_init_function_pointers_vf ( &adapter->hw );
+
+       rc = adapter->hw.mac.ops.init_params ( &adapter->hw );
+       if (rc) {
+                DBG ("hw.mac.ops.init_params(&adapter->hw) Failure\n");
+               return rc;
+        }
+
+       rc = adapter->hw.mbx.ops.init_params ( &adapter->hw );
+       if (rc) {
+                DBG ("hw.mbx.ops.init_params(&adapter->hw) Failure\n");
+               return rc;
+        }
+
+       /* Explicitly disable IRQ since the NIC can be in any state. */
+       igbvf_irq_disable ( adapter );
+
+       return 0;
+}
+
+/**
+ * igbvf_setup_srrctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+static void igbvf_setup_srrctl ( struct igbvf_adapter *adapter )
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 srrctl = 0;
+
+       DBG ( "igbvf_setup_srrctl\n" );
+
+       srrctl &= ~(E1000_SRRCTL_DESCTYPE_MASK |
+                   E1000_SRRCTL_BSIZEHDR_MASK |
+                   E1000_SRRCTL_BSIZEPKT_MASK);
+
+       /* Enable queue drop to avoid head of line blocking */
+       srrctl |= E1000_SRRCTL_DROP_EN;
+
+       /* Setup buffer sizes */
+        srrctl |= 2048 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+       srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+       ew32 ( SRRCTL(0), srrctl );
+}
+
+/**
+ * igbvf_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void igbvf_configure_rx ( struct igbvf_adapter *adapter )
+{
+        struct e1000_hw *hw = &adapter->hw;
+        u32 rxdctl;
+
+       DBG ( "igbvf_configure_rx\n" );
+
+        /* disable receives */
+        rxdctl = er32 ( RXDCTL(0) );
+        ew32 ( RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE );
+        msleep ( 10 );
+
+        /*
+         * Setup the HW Rx Head and Tail Descriptor Pointers and
+         * the Base and Length of the Rx Descriptor Ring
+         */
+        ew32 ( RDBAL(0), virt_to_bus (adapter->rx_base) );
+        ew32 ( RDBAH(0), 0 );
+        ew32 ( RDLEN(0), adapter->rx_ring_size );
+       adapter->rx_curr = 0;
+        ew32 ( RDH(0), 0 );
+        ew32 ( RDT(0), 0 );
+
+        rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+        rxdctl &= 0xFFF00000;
+        rxdctl |= IGBVF_RX_PTHRESH;
+        rxdctl |= IGBVF_RX_HTHRESH << 8;
+        rxdctl |= IGBVF_RX_WTHRESH << 16;
+
+        igbvf_rlpml_set_vf ( hw, adapter->max_frame_size );
+
+        /* enable receives */
+        ew32 ( RXDCTL(0), rxdctl );
+        ew32 ( RDT(0), NUM_RX_DESC );
+}
+
+/**
+ * igbvf_setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v adapter   e1000 private structure
+ **/
+int igbvf_setup_rx_resources ( struct igbvf_adapter *adapter )
+{
+       int i;
+       union e1000_adv_rx_desc *rx_curr_desc;
+        struct io_buffer *iob;
+
+       DBG ( "igbvf_setup_rx_resources\n" );
+
+       /* Allocate receive descriptor ring memory.
+          It must not cross a 64K boundary because of hardware errata
+        */
+
+       adapter->rx_base =
+               malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
+
+       if ( ! adapter->rx_base ) {
+               return -ENOMEM;
+       }
+       memset ( adapter->rx_base, 0, adapter->rx_ring_size );
+
+       for ( i = 0; i < NUM_RX_DESC; i++ ) {
+                rx_curr_desc = adapter->rx_base + i;
+                iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
+                adapter->rx_iobuf[i] = iob;
+                rx_curr_desc->wb.upper.status_error = 0;
+                if ( ! iob ) {
+                        DBG ( "alloc_iob failed\n" );
+                        return -ENOMEM;
+                } else {
+                        rx_curr_desc->read.pkt_addr = virt_to_bus ( iob->data );
+                        rx_curr_desc->read.hdr_addr = 0;
+                }
+       }
+
+       return 0;
+}
+
+/**
+ * igbvf_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int igbvf_open ( struct net_device *netdev )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+       int err;
+
+       DBG ("igbvf_open\n");
+
+       /* Update MAC address */
+       memcpy ( adapter->hw.mac.addr, netdev->ll_addr, ETH_ALEN );
+       igbvf_reset( adapter );
+
+       /* allocate transmit descriptors */
+       err = igbvf_setup_tx_resources ( adapter );
+       if (err) {
+               DBG ( "Error setting up TX resources!\n" );
+               goto err_setup_tx;
+       }
+
+       igbvf_configure_tx ( adapter );
+
+       igbvf_setup_srrctl( adapter );
+
+       err = igbvf_setup_rx_resources( adapter );
+       if (err) {
+               DBG ( "Error setting up RX resources!\n" );
+               goto err_setup_rx;
+       }
+
+       igbvf_configure_rx ( adapter );
+
+       return 0;
+
+err_setup_rx:
+       DBG ( "err_setup_rx\n" );
+       igbvf_free_tx_resources ( adapter );
+       return err;
+
+err_setup_tx:
+       DBG ( "err_setup_tx\n" );
+       igbvf_reset ( adapter );
+
+       return err;
+}
+
+/**
+ * igbvf_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static void igbvf_close ( struct net_device *netdev )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+        struct e1000_hw *hw = &adapter->hw;
+        uint32_t rxdctl;
+
+        DBG ( "igbvf_close\n" );
+
+       /* Disable and acknowledge interrupts */
+        igbvf_irq_disable ( adapter );
+        er32(EICR);
+
+        /* disable receives */
+        rxdctl = er32 ( RXDCTL(0) );
+        ew32 ( RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE );
+        mdelay ( 10 );
+
+        igbvf_reset ( adapter );
+
+       igbvf_free_tx_resources( adapter );
+       igbvf_free_rx_resources( adapter );
+}
+
+/**
+ * igbvf_transmit - Transmit a packet
+ *
+ * @v netdev    Network device
+ * @v iobuf     I/O buffer
+ *
+ * @ret rc       Returns 0 on success, negative on failure
+ */
+static int igbvf_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+       struct e1000_hw *hw = &adapter->hw;
+       uint32_t tx_curr = adapter->tx_tail;
+       union e1000_adv_tx_desc *tx_curr_desc;
+
+       DBGP ("igbvf_transmit\n");
+
+       if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
+               DBG ("TX overflow\n");
+               return -ENOBUFS;
+       }
+
+       /* Save pointer to iobuf we have been given to transmit,
+          netdev_tx_complete() will need it later
+        */
+       adapter->tx_iobuf[tx_curr] = iobuf;
+
+       tx_curr_desc = ( void * ) ( adapter->tx_base ) +
+                      ( tx_curr * sizeof ( *adapter->tx_base ) );
+
+       DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+       DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
+       DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+
+       /* Add the packet to TX ring
+        */
+       tx_curr_desc->read.buffer_addr = virt_to_bus ( iobuf->data );
+       tx_curr_desc->read.cmd_type_len = adapter->txd_cmd |(iob_len ( iobuf )) ;
+       // minus hdr_len ????
+       tx_curr_desc->read.olinfo_status = ((iob_len ( iobuf )) << E1000_ADVTXD_PAYLEN_SHIFT);
+
+       DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+             tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
+
+       /* Point to next free descriptor */
+       adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
+       adapter->tx_fill_ctr++;
+
+       /* Write new tail to NIC, making packet available for transmit
+        */
+       ew32 ( TDT(0), adapter->tx_tail );
+       e1e_flush ();
+
+       return 0;
+}
+
+/** igbvf net device operations */
+static struct net_device_operations igbvf_operations = {
+       .open           = igbvf_open,
+       .close          = igbvf_close,
+       .transmit       = igbvf_transmit,
+       .poll           = igbvf_poll,
+       .irq            = igbvf_irq,
+};
+
+/**
+ * igbvf_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
+ *
+ **/
+void igbvf_get_hw_control ( struct igbvf_adapter *adapter )
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl_ext;
+
+       /* Let firmware know the driver has taken over */
+       ctrl_ext = er32 ( CTRL_EXT );
+       ew32 ( CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD );
+}
+
+/**
+ * igbvf_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in igbvf_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * igbvf_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+int igbvf_probe ( struct pci_device *pdev )
+{
+       int err;
+       struct net_device *netdev;
+       struct igbvf_adapter *adapter;
+       unsigned long mmio_start, mmio_len;
+       struct e1000_hw *hw;
+
+        DBG ( "igbvf_probe\n" );
+
+       err = -ENOMEM;
+
+       /* Allocate net device ( also allocates memory for netdev->priv
+         and makes netdev-priv point to it ) */
+       netdev = alloc_etherdev ( sizeof ( struct igbvf_adapter ) );
+       if ( ! netdev )
+               goto err_alloc_etherdev;
+
+       /* Associate igbvf-specific network operations operations with
+        * generic network device layer */
+       netdev_init ( netdev, &igbvf_operations );
+
+       /* Associate this network device with given PCI device */
+       pci_set_drvdata ( pdev, netdev );
+       netdev->dev = &pdev->dev;
+
+       /* Initialize driver private storage */
+       adapter = netdev_priv ( netdev );
+       memset ( adapter, 0, ( sizeof ( *adapter ) ) );
+
+       adapter->pdev = pdev;
+
+       adapter->ioaddr = pdev->ioaddr;
+       adapter->hw.io_base = pdev->ioaddr;
+
+       hw = &adapter->hw;
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+
+       adapter->irqno = pdev->irq;
+       adapter->netdev = netdev;
+       adapter->hw.back = adapter;
+
+       adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+       adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+
+       adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
+       adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
+
+       /* Fix up PCI device */
+       adjust_pci_device ( pdev );
+
+       err = -EIO;
+
+       mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
+       mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
+
+       DBG ( "mmio_start: %#08lx\n", mmio_start );
+       DBG ( "mmio_len: %#08lx\n", mmio_len );
+
+       adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
+       DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
+
+       if ( ! adapter->hw.hw_addr ) {
+               DBG ( "err_ioremap\n" );
+               goto err_ioremap;
+       }
+
+       /* setup adapter struct */
+       err = igbvf_sw_init ( adapter );
+       if (err) {
+               DBG ( "err_sw_init\n" );
+               goto err_sw_init;
+       }
+
+       /* reset the controller to put the device in a known good state */
+       err = hw->mac.ops.reset_hw ( hw );
+       if ( err ) {
+               DBG ("PF still in reset state, assigning new address\n");
+               netdev->hw_addr[0] = 0x21;
+               netdev->hw_addr[1] = 0x21;
+               netdev->hw_addr[2] = 0x21;
+               netdev->hw_addr[3] = 0x21;
+               netdev->hw_addr[4] = 0x21;
+               netdev->hw_addr[5] = 0x21;
+               netdev->hw_addr[6] = 0x21;
+       } else {
+               err = hw->mac.ops.read_mac_addr(hw);
+               if (err) {
+                       DBG ("Error reading MAC address\n");
+                       goto err_hw_init;
+               }
+               if ( ! is_valid_ether_addr(adapter->hw.mac.addr) ) {
+                       /* Assign random MAC address */
+                       eth_random_addr(adapter->hw.mac.addr);
+               }
+       }
+
+       memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN );
+
+       /* reset the hardware with the new settings */
+       igbvf_reset ( adapter );
+
+       /* let the f/w know that the h/w is now under the control of the
+        * driver. */
+       igbvf_get_hw_control ( adapter );
+
+       /* Mark as link up; we don't yet handle link state */
+       netdev_link_up ( netdev );
+
+       if ( ( err = register_netdev ( netdev ) ) != 0) {
+               DBG ( "err_register\n" );
+               goto err_register;
+       }
+
+       DBG ("igbvf_probe_succeeded\n");
+
+       return 0;
+
+err_register:
+err_hw_init:
+err_sw_init:
+       iounmap ( adapter->hw.hw_addr );
+err_ioremap:
+       netdev_put ( netdev );
+err_alloc_etherdev:
+       return err;
+}
+
+/**
+ * igbvf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * igbvf_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+void igbvf_remove ( struct pci_device *pdev )
+{
+       struct net_device *netdev = pci_get_drvdata ( pdev );
+       struct igbvf_adapter *adapter = netdev_priv ( netdev );
+
+       DBG ( "igbvf_remove\n" );
+
+       if ( adapter->hw.flash_address )
+               iounmap ( adapter->hw.flash_address );
+       if  ( adapter->hw.hw_addr )
+               iounmap ( adapter->hw.hw_addr );
+
+       unregister_netdev ( netdev );
+       igbvf_reset  ( adapter );
+       netdev_nullify ( netdev );
+       netdev_put ( netdev );
+}
+
+static struct pci_device_id igbvf_pci_tbl[] = {
+       PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0),
+       PCI_ROM(0x8086, 0x1520, "i350vf", "E1000_DEV_ID_I350_VF", 0),
+};
+
+
+struct pci_driver igbvf_driver __pci_driver = {
+       .ids = igbvf_pci_tbl,
+       .id_count = (sizeof(igbvf_pci_tbl) / sizeof(igbvf_pci_tbl[0])),
+       .probe = igbvf_probe,
+       .remove = igbvf_remove,
+};