| /******************************************************************************* |
| |
| 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_phys() 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_phys ( 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_phys ( 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_phys ( 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; |
| |
| 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; |
| 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; |
| 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; |
| 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, &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_phys ( 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; |
| 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; |
| 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; |
| 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; |
| 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 = pci_ioremap ( pdev, 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; |
| |
| 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, |
| }; |