|  | /******************************************************************************* | 
|  |  | 
|  | Intel PRO/1000 Linux driver | 
|  | Copyright(c) 1999 - 2008 Intel Corporation. | 
|  |  | 
|  | Portions Copyright(c) 2010 Marty Connor <mdc@etherboot.org> | 
|  | Portions Copyright(c) 2010 Entity Cyber, Inc. | 
|  |  | 
|  | 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: | 
|  | Linux NICS <linux.nics@intel.com> | 
|  | 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 "e1000.h" | 
|  |  | 
|  | /** | 
|  | * e1000_irq_disable - Disable interrupt generation | 
|  | * | 
|  | * @adapter: board private structure | 
|  | **/ | 
|  | static void e1000_irq_disable(struct e1000_adapter *adapter) | 
|  | { | 
|  | E1000_WRITE_REG(&adapter->hw, E1000_IMC, ~0); | 
|  | E1000_WRITE_FLUSH(&adapter->hw); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_irq_enable - Enable interrupt generation | 
|  | * | 
|  | * @adapter: board private structure | 
|  | **/ | 
|  | static void e1000_irq_enable(struct e1000_adapter *adapter) | 
|  | { | 
|  | E1000_WRITE_REG(&adapter->hw, E1000_IMS, IMS_ENABLE_MASK); | 
|  | E1000_WRITE_FLUSH(&adapter->hw); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_sw_init - Initialize general software structures (struct e1000_adapter) | 
|  | * @adapter: board private structure to initialize | 
|  | * | 
|  | * e1000_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 e1000_sw_init(struct e1000_adapter *adapter) | 
|  | { | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  | struct pci_device *pdev = adapter->pdev; | 
|  |  | 
|  | /* PCI config space info */ | 
|  |  | 
|  | hw->vendor_id = pdev->vendor; | 
|  | hw->device_id = pdev->device; | 
|  |  | 
|  | pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, | 
|  | &hw->subsystem_vendor_id); | 
|  | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_device_id); | 
|  |  | 
|  | pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); | 
|  |  | 
|  | pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); | 
|  |  | 
|  | adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; | 
|  | adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + | 
|  | ETH_HLEN + ETH_FCS_LEN; | 
|  | adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; | 
|  |  | 
|  | hw->fc.requested_mode = e1000_fc_none; | 
|  |  | 
|  | /* Initialize the hardware-specific values */ | 
|  | if (e1000_setup_init_funcs(hw, false)) { | 
|  | DBG("Hardware Initialization Failure\n"); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | /* Explicitly disable IRQ since the NIC can be in any state. */ | 
|  | e1000_irq_disable(adapter); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t e1000_read_pcie_cap_reg(struct e1000_hw * hw, uint32_t reg, | 
|  | uint16_t * value) | 
|  | { | 
|  | struct e1000_adapter *adapter = hw->back; | 
|  | uint16_t cap_offset; | 
|  |  | 
|  | #define  PCI_CAP_ID_EXP        0x10	/* PCI Express */ | 
|  | cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); | 
|  | if (!cap_offset) | 
|  | return -E1000_ERR_CONFIG; | 
|  |  | 
|  | pci_read_config_word(adapter->pdev, cap_offset + reg, value); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void e1000_pci_clear_mwi(struct e1000_hw *hw) | 
|  | { | 
|  | struct e1000_adapter *adapter = hw->back; | 
|  |  | 
|  | pci_write_config_word(adapter->pdev, PCI_COMMAND, | 
|  | hw->bus.pci_cmd_word & ~PCI_COMMAND_INVALIDATE); | 
|  | } | 
|  |  | 
|  | void e1000_pci_set_mwi(struct e1000_hw *hw) | 
|  | { | 
|  | struct e1000_adapter *adapter = hw->back; | 
|  |  | 
|  | pci_write_config_word(adapter->pdev, PCI_COMMAND, hw->bus.pci_cmd_word); | 
|  | } | 
|  |  | 
|  | void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value) | 
|  | { | 
|  | struct e1000_adapter *adapter = hw->back; | 
|  |  | 
|  | pci_read_config_word(adapter->pdev, reg, value); | 
|  | } | 
|  |  | 
|  | void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value) | 
|  | { | 
|  | struct e1000_adapter *adapter = hw->back; | 
|  |  | 
|  | pci_write_config_word(adapter->pdev, reg, *value); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_init_manageability - disable interception of ARP packets | 
|  | * | 
|  | * @v adapter	e1000 private structure | 
|  | **/ | 
|  | static void e1000_init_manageability(struct e1000_adapter *adapter) | 
|  | { | 
|  | if (adapter->en_mng_pt) { | 
|  | u32 manc = E1000_READ_REG(&adapter->hw, E1000_MANC); | 
|  |  | 
|  | /* disable hardware interception of ARP */ | 
|  | manc &= ~(E1000_MANC_ARP_EN); | 
|  |  | 
|  | E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_setup_tx_resources - allocate Tx resources (Descriptors) | 
|  | * | 
|  | * @v adapter	e1000 private structure | 
|  | * | 
|  | * @ret rc       Returns 0 on success, negative on failure | 
|  | **/ | 
|  | static int e1000_setup_tx_resources(struct e1000_adapter *adapter) | 
|  | { | 
|  | DBG("e1000_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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_process_tx_packets - process transmitted packets | 
|  | * | 
|  | * @v netdev	network interface device structure | 
|  | **/ | 
|  | static void e1000_process_tx_packets(struct net_device *netdev) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  | uint32_t i; | 
|  | uint32_t tx_status; | 
|  | struct e1000_tx_desc *tx_curr_desc; | 
|  |  | 
|  | /* Check status of transmitted packets | 
|  | */ | 
|  | 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->upper.data; | 
|  |  | 
|  | /* 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); | 
|  |  | 
|  | if (tx_status & (E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | | 
|  | E1000_TXD_STAT_TU)) { | 
|  | netdev_tx_complete_err(netdev, adapter->tx_iobuf[i], -EINVAL); | 
|  | DBG("Error transmitting packet, tx_status: %#08x\n", tx_status); | 
|  | } else { | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void e1000_free_tx_resources(struct e1000_adapter *adapter) | 
|  | { | 
|  | DBG("e1000_free_tx_resources\n"); | 
|  |  | 
|  | free_dma(adapter->tx_base, adapter->tx_ring_size); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_configure_tx - Configure 8254x Transmit Unit after Reset | 
|  | * @adapter: board private structure | 
|  | * | 
|  | * Configure the Tx unit of the MAC after a reset. | 
|  | **/ | 
|  | static void e1000_configure_tx(struct e1000_adapter *adapter) | 
|  | { | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  | uint32_t tctl; | 
|  |  | 
|  | DBG("e1000_configure_tx\n"); | 
|  |  | 
|  | E1000_WRITE_REG(hw, E1000_TDBAH(0), 0); | 
|  | E1000_WRITE_REG(hw, E1000_TDBAL(0), virt_to_bus(adapter->tx_base)); | 
|  | E1000_WRITE_REG(hw, E1000_TDLEN(0), adapter->tx_ring_size); | 
|  |  | 
|  | DBG("E1000_TDBAL(0): %#08x\n", E1000_READ_REG(hw, E1000_TDBAL(0))); | 
|  | DBG("E1000_TDLEN(0): %d\n", E1000_READ_REG(hw, E1000_TDLEN(0))); | 
|  |  | 
|  | /* Setup the HW Tx Head and Tail descriptor pointers */ | 
|  | E1000_WRITE_REG(hw, E1000_TDH(0), 0); | 
|  | E1000_WRITE_REG(hw, E1000_TDT(0), 0); | 
|  |  | 
|  | adapter->tx_head = 0; | 
|  | adapter->tx_tail = 0; | 
|  | adapter->tx_fill_ctr = 0; | 
|  |  | 
|  | /* Setup Transmit Descriptor Settings for eop descriptor */ | 
|  | tctl = E1000_TCTL_PSP | E1000_TCTL_EN | | 
|  | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT) | | 
|  | (E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); | 
|  |  | 
|  | e1000_config_collision_dist(hw); | 
|  |  | 
|  | E1000_WRITE_REG(hw, E1000_TCTL, tctl); | 
|  | E1000_WRITE_FLUSH(hw); | 
|  | } | 
|  |  | 
|  | static void e1000_free_rx_resources(struct e1000_adapter *adapter) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | DBG("e1000_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]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_refill_rx_ring - allocate Rx io_buffers | 
|  | * | 
|  | * @v adapter	e1000 private structure | 
|  | * | 
|  | * @ret rc       Returns 0 on success, negative on failure | 
|  | **/ | 
|  | static int e1000_refill_rx_ring(struct e1000_adapter *adapter) | 
|  | { | 
|  | int i, rx_curr; | 
|  | int rc = 0; | 
|  | struct e1000_rx_desc *rx_curr_desc; | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  | struct io_buffer *iob; | 
|  |  | 
|  | DBG("e1000_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->status & 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; | 
|  |  | 
|  | if (!iob) { | 
|  | DBG("alloc_iob failed\n"); | 
|  | rc = -ENOMEM; | 
|  | break; | 
|  | } else { | 
|  | rx_curr_desc->buffer_addr = virt_to_bus(iob->data); | 
|  |  | 
|  | E1000_WRITE_REG(hw, E1000_RDT(0), rx_curr); | 
|  | } | 
|  | } | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_setup_rx_resources - allocate Rx resources (Descriptors) | 
|  | * | 
|  | * @v adapter	e1000 private structure | 
|  | * | 
|  | * @ret rc       Returns 0 on success, negative on failure | 
|  | **/ | 
|  | static int e1000_setup_rx_resources(struct e1000_adapter *adapter) | 
|  | { | 
|  | int i, rc = 0; | 
|  |  | 
|  | DBG("e1000_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++) { | 
|  | /* let e1000_refill_rx_ring() io_buffer allocations */ | 
|  | adapter->rx_iobuf[i] = NULL; | 
|  | } | 
|  |  | 
|  | /* allocate io_buffers */ | 
|  | rc = e1000_refill_rx_ring(adapter); | 
|  | if (rc < 0) | 
|  | e1000_free_rx_resources(adapter); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_configure_rx - Configure 8254x Receive Unit after Reset | 
|  | * @adapter: board private structure | 
|  | * | 
|  | * Configure the Rx unit of the MAC after a reset. | 
|  | **/ | 
|  | static void e1000_configure_rx(struct e1000_adapter *adapter) | 
|  | { | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  | uint32_t rctl; | 
|  |  | 
|  | DBG("e1000_configure_rx\n"); | 
|  |  | 
|  | /* disable receives while setting up the descriptors */ | 
|  | rctl = E1000_READ_REG(hw, E1000_RCTL); | 
|  | E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); | 
|  | E1000_WRITE_FLUSH(hw); | 
|  | mdelay(10); | 
|  |  | 
|  | adapter->rx_curr = 0; | 
|  |  | 
|  | /* Setup the HW Rx Head and Tail Descriptor Pointers and | 
|  | * the Base and Length of the Rx Descriptor Ring */ | 
|  |  | 
|  | E1000_WRITE_REG(hw, E1000_RDBAL(0), virt_to_bus(adapter->rx_base)); | 
|  | E1000_WRITE_REG(hw, E1000_RDBAH(0), 0); | 
|  | E1000_WRITE_REG(hw, E1000_RDLEN(0), adapter->rx_ring_size); | 
|  |  | 
|  | E1000_WRITE_REG(hw, E1000_RDH(0), 0); | 
|  | E1000_WRITE_REG(hw, E1000_RDT(0), NUM_RX_DESC - 1); | 
|  |  | 
|  | /* Enable Receives */ | 
|  | rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | | 
|  | E1000_RCTL_MPE; | 
|  | E1000_WRITE_REG(hw, E1000_RCTL, rctl); | 
|  | E1000_WRITE_FLUSH(hw); | 
|  |  | 
|  | DBG("E1000_RDBAL(0): %#08x\n", E1000_READ_REG(hw, E1000_RDBAL(0))); | 
|  | DBG("E1000_RDLEN(0): %d\n", E1000_READ_REG(hw, E1000_RDLEN(0))); | 
|  | DBG("E1000_RCTL:  %#08x\n", E1000_READ_REG(hw, E1000_RCTL)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_process_rx_packets - process received packets | 
|  | * | 
|  | * @v netdev	network interface device structure | 
|  | **/ | 
|  | static void e1000_process_rx_packets(struct net_device *netdev) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  | uint32_t i; | 
|  | uint32_t rx_status; | 
|  | uint32_t rx_len; | 
|  | uint32_t rx_err; | 
|  | struct e1000_rx_desc *rx_curr_desc; | 
|  |  | 
|  | /* 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->status; | 
|  |  | 
|  | DBG2("Before DD Check RX_status: %#08x\n", rx_status); | 
|  |  | 
|  | if (!(rx_status & E1000_RXD_STAT_DD)) | 
|  | break; | 
|  |  | 
|  | if (adapter->rx_iobuf[i] == NULL) | 
|  | break; | 
|  |  | 
|  | DBG("E1000_RCTL = %#08x\n", E1000_READ_REG(&adapter->hw, E1000_RCTL)); | 
|  |  | 
|  | rx_len = rx_curr_desc->length; | 
|  |  | 
|  | DBG("Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n", | 
|  | i, rx_status, rx_len); | 
|  |  | 
|  | rx_err = rx_curr_desc->errors; | 
|  |  | 
|  | iob_put(adapter->rx_iobuf[i], rx_len); | 
|  |  | 
|  | if (rx_err & E1000_RXD_ERR_FRAME_ERR_MASK) { | 
|  |  | 
|  | netdev_rx_err(netdev, adapter->rx_iobuf[i], -EINVAL); | 
|  | DBG("e1000_poll: 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_reset - Put e1000 NIC in known initial state | 
|  | * | 
|  | * @v adapter	e1000 private structure | 
|  | **/ | 
|  | void e1000_reset(struct e1000_adapter *adapter) | 
|  | { | 
|  | struct e1000_mac_info *mac = &adapter->hw.mac; | 
|  | u32 pba = 0; | 
|  |  | 
|  | DBG("e1000_reset\n"); | 
|  |  | 
|  | switch (mac->type) { | 
|  | case e1000_82542: | 
|  | case e1000_82543: | 
|  | case e1000_82544: | 
|  | case e1000_82540: | 
|  | case e1000_82541: | 
|  | case e1000_82541_rev_2: | 
|  | pba = E1000_PBA_48K; | 
|  | break; | 
|  | case e1000_82545: | 
|  | case e1000_82545_rev_3: | 
|  | case e1000_82546: | 
|  | case e1000_82546_rev_3: | 
|  | pba = E1000_PBA_48K; | 
|  | break; | 
|  | case e1000_82547: | 
|  | case e1000_82547_rev_2: | 
|  | pba = E1000_PBA_30K; | 
|  | break; | 
|  | case e1000_undefined: | 
|  | case e1000_num_macs: | 
|  | break; | 
|  | } | 
|  |  | 
|  | E1000_WRITE_REG(&adapter->hw, E1000_PBA, pba); | 
|  |  | 
|  | /* Allow time for pending master requests to run */ | 
|  | e1000_reset_hw(&adapter->hw); | 
|  |  | 
|  | if (mac->type >= e1000_82544) | 
|  | E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); | 
|  |  | 
|  | if (e1000_init_hw(&adapter->hw)) | 
|  | DBG("Hardware Error\n"); | 
|  |  | 
|  | e1000_reset_adaptive(&adapter->hw); | 
|  | e1000_get_phy_info(&adapter->hw); | 
|  |  | 
|  | e1000_init_manageability(adapter); | 
|  | } | 
|  |  | 
|  | /** Functions that implement the gPXE driver API **/ | 
|  |  | 
|  | /** | 
|  | * e1000_close - Disables a network interface | 
|  | * | 
|  | * @v netdev	network interface device structure | 
|  | * | 
|  | **/ | 
|  | static void e1000_close(struct net_device *netdev) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  | uint32_t rctl; | 
|  | uint32_t icr; | 
|  |  | 
|  | DBG("e1000_close\n"); | 
|  |  | 
|  | /* Acknowledge interrupts */ | 
|  | icr = E1000_READ_REG(hw, E1000_ICR); | 
|  |  | 
|  | e1000_irq_disable(adapter); | 
|  |  | 
|  | /* disable receives */ | 
|  | rctl = E1000_READ_REG(hw, E1000_RCTL); | 
|  | E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); | 
|  | E1000_WRITE_FLUSH(hw); | 
|  |  | 
|  | e1000_reset_hw(hw); | 
|  |  | 
|  | e1000_free_tx_resources(adapter); | 
|  | e1000_free_rx_resources(adapter); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_transmit - Transmit a packet | 
|  | * | 
|  | * @v netdev	Network device | 
|  | * @v iobuf	I/O buffer | 
|  | * | 
|  | * @ret rc       Returns 0 on success, negative on failure | 
|  | */ | 
|  | static int e1000_transmit(struct net_device *netdev, struct io_buffer *iobuf) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  | uint32_t tx_curr = adapter->tx_tail; | 
|  | struct e1000_tx_desc *tx_curr_desc; | 
|  |  | 
|  | DBG("e1000_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->buffer_addr = virt_to_bus(iobuf->data); | 
|  | tx_curr_desc->lower.data = | 
|  | E1000_TXD_CMD_RPS | E1000_TXD_CMD_EOP | | 
|  | E1000_TXD_CMD_IFCS | iob_len(iobuf); | 
|  | tx_curr_desc->upper.data = 0; | 
|  |  | 
|  | 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 | 
|  | */ | 
|  | wmb(); | 
|  | E1000_WRITE_REG(hw, E1000_TDT(0), adapter->tx_tail); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_poll - Poll for received packets | 
|  | * | 
|  | * @v netdev	Network device | 
|  | */ | 
|  | static void e1000_poll(struct net_device *netdev) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  | struct e1000_hw *hw = &adapter->hw; | 
|  |  | 
|  | uint32_t icr; | 
|  |  | 
|  | DBGP("e1000_poll\n"); | 
|  |  | 
|  | /* Acknowledge interrupts */ | 
|  | icr = E1000_READ_REG(hw, E1000_ICR); | 
|  | if (!icr) | 
|  | return; | 
|  |  | 
|  | DBG("e1000_poll: intr_status = %#08x\n", icr); | 
|  |  | 
|  | e1000_process_tx_packets(netdev); | 
|  |  | 
|  | e1000_process_rx_packets(netdev); | 
|  |  | 
|  | e1000_refill_rx_ring(adapter); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_irq - enable or Disable interrupts | 
|  | * | 
|  | * @v adapter   e1000 adapter | 
|  | * @v action    requested interrupt action | 
|  | **/ | 
|  | static void e1000_irq(struct net_device *netdev, int enable) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | DBG("e1000_irq\n"); | 
|  |  | 
|  | if (enable) { | 
|  | e1000_irq_enable(adapter); | 
|  | } else { | 
|  | e1000_irq_disable(adapter); | 
|  | } | 
|  | } | 
|  |  | 
|  | static struct net_device_operations e1000_operations; | 
|  |  | 
|  | /** | 
|  | * e1000_probe - Initial configuration of e1000 NIC | 
|  | * | 
|  | * @v pci	PCI device | 
|  | * @v id	PCI IDs | 
|  | * | 
|  | * @ret rc	Return status code | 
|  | **/ | 
|  | int e1000_probe(struct pci_device *pdev, | 
|  | const struct pci_device_id *id __unused) | 
|  | { | 
|  | int i, err; | 
|  | struct net_device *netdev; | 
|  | struct e1000_adapter *adapter; | 
|  | unsigned long mmio_start, mmio_len; | 
|  |  | 
|  | DBG("e1000_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 e1000_adapter)); | 
|  | if (!netdev) | 
|  | goto err_alloc_etherdev; | 
|  |  | 
|  | /* Associate e1000-specific network operations operations with | 
|  | * generic network device layer */ | 
|  | netdev_init(netdev, &e1000_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; | 
|  |  | 
|  | adapter->irqno = pdev->irq; | 
|  | adapter->netdev = netdev; | 
|  | adapter->hw.back = adapter; | 
|  |  | 
|  | adapter->tx_ring_size = sizeof(*adapter->tx_base) * NUM_TX_DESC; | 
|  | adapter->rx_ring_size = sizeof(*adapter->rx_base) * NUM_RX_DESC; | 
|  |  | 
|  | 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); | 
|  |  | 
|  | /* Fix up PCI device */ | 
|  | adjust_pci_device(pdev); | 
|  |  | 
|  | err = -EIO; | 
|  |  | 
|  | 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) | 
|  | goto err_ioremap; | 
|  |  | 
|  | /* Hardware features, flags and workarounds */ | 
|  | if (adapter->hw.mac.type >= e1000_82540) { | 
|  | adapter->flags |= E1000_FLAG_HAS_SMBUS; | 
|  | adapter->flags |= E1000_FLAG_HAS_INTR_MODERATION; | 
|  | } | 
|  |  | 
|  | if (adapter->hw.mac.type == e1000_82543) | 
|  | adapter->flags |= E1000_FLAG_BAD_TX_CARRIER_STATS_FD; | 
|  |  | 
|  | adapter->hw.phy.autoneg_wait_to_complete = true; | 
|  | adapter->hw.mac.adaptive_ifs = true; | 
|  |  | 
|  | /* setup the private structure */ | 
|  | if ((err = e1000_sw_init(adapter))) | 
|  | goto err_sw_init; | 
|  |  | 
|  | if ((err = e1000_init_mac_params(&adapter->hw))) | 
|  | goto err_hw_init; | 
|  |  | 
|  | if ((err = e1000_init_nvm_params(&adapter->hw))) | 
|  | goto err_hw_init; | 
|  |  | 
|  | /* Force auto-negotiated speed and duplex */ | 
|  | adapter->hw.mac.autoneg = 1; | 
|  |  | 
|  | if ((err = e1000_init_phy_params(&adapter->hw))) | 
|  | goto err_hw_init; | 
|  |  | 
|  | DBG("adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type); | 
|  |  | 
|  | /* before reading the EEPROM, reset the controller to | 
|  | * put the device in a known good starting state | 
|  | */ | 
|  | err = e1000_reset_hw(&adapter->hw); | 
|  | if (err < 0) { | 
|  | DBG("Hardware Initialization Failed\n"); | 
|  | goto err_reset; | 
|  | } | 
|  | /* make sure the NVM is good */ | 
|  |  | 
|  | if (e1000_validate_nvm_checksum(&adapter->hw) < 0) { | 
|  | DBG("The NVM Checksum Is Not Valid\n"); | 
|  | err = -EIO; | 
|  | goto err_eeprom; | 
|  | } | 
|  |  | 
|  | /* copy the MAC address out of the EEPROM */ | 
|  | if (e1000_read_mac_addr(&adapter->hw)) | 
|  | DBG("EEPROM Read Error\n"); | 
|  |  | 
|  | memcpy(netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN); | 
|  |  | 
|  | /* reset the hardware with the new settings */ | 
|  | e1000_reset(adapter); | 
|  |  | 
|  | /* Mark as link up; we don't yet handle link state */ | 
|  | netdev_link_up(netdev); | 
|  |  | 
|  | if ((err = register_netdev(netdev)) != 0) | 
|  | goto err_register; | 
|  |  | 
|  | for (i = 0; i < 6; i++) | 
|  | DBG("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":"); | 
|  |  | 
|  | DBG("e1000_probe succeeded!\n"); | 
|  |  | 
|  | /* No errors, return success */ | 
|  | return 0; | 
|  |  | 
|  | /* Error return paths */ | 
|  | err_reset: | 
|  | err_register: | 
|  | err_hw_init: | 
|  | err_eeprom: | 
|  | if (!e1000_check_reset_block(&adapter->hw)) | 
|  | e1000_phy_hw_reset(&adapter->hw); | 
|  | if (adapter->hw.flash_address) | 
|  | iounmap(adapter->hw.flash_address); | 
|  | err_sw_init: | 
|  | iounmap(adapter->hw.hw_addr); | 
|  | err_ioremap: | 
|  | netdev_put(netdev); | 
|  | err_alloc_etherdev: | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_remove - Device Removal Routine | 
|  | * | 
|  | * @v pdev PCI device information struct | 
|  | * | 
|  | **/ | 
|  | void e1000_remove(struct pci_device *pdev) | 
|  | { | 
|  | struct net_device *netdev = pci_get_drvdata(pdev); | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | DBG("e1000_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); | 
|  | e1000_reset_hw(&adapter->hw); | 
|  | netdev_nullify(netdev); | 
|  | netdev_put(netdev); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * e1000_open - Called when a network interface is made active | 
|  | * | 
|  | * @v netdev	network interface device structure | 
|  | * @ret rc	Return status code, 0 on success, negative value on failure | 
|  | * | 
|  | **/ | 
|  | static int e1000_open(struct net_device *netdev) | 
|  | { | 
|  | struct e1000_adapter *adapter = netdev_priv(netdev); | 
|  | int err; | 
|  |  | 
|  | DBG("e1000_open\n"); | 
|  |  | 
|  | /* allocate transmit descriptors */ | 
|  | err = e1000_setup_tx_resources(adapter); | 
|  | if (err) { | 
|  | DBG("Error setting up TX resources!\n"); | 
|  | goto err_setup_tx; | 
|  | } | 
|  |  | 
|  | /* allocate receive descriptors */ | 
|  | err = e1000_setup_rx_resources(adapter); | 
|  | if (err) { | 
|  | DBG("Error setting up RX resources!\n"); | 
|  | goto err_setup_rx; | 
|  | } | 
|  |  | 
|  | e1000_configure_tx(adapter); | 
|  |  | 
|  | e1000_configure_rx(adapter); | 
|  |  | 
|  | DBG("E1000_RXDCTL(0): %#08x\n", | 
|  | E1000_READ_REG(&adapter->hw, E1000_RXDCTL(0))); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err_setup_rx: | 
|  | e1000_free_tx_resources(adapter); | 
|  | err_setup_tx: | 
|  | e1000_reset(adapter); | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /** e1000 net device operations */ | 
|  | static struct net_device_operations e1000_operations = { | 
|  | .open = e1000_open, | 
|  | .close = e1000_close, | 
|  | .transmit = e1000_transmit, | 
|  | .poll = e1000_poll, | 
|  | .irq = e1000_irq, | 
|  | }; |