static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; /* * When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (e1000_check_reset_block(hw)) { e_err("Cannot change link characteristics when SoL/IDER is " "active.\n"); return -EINVAL; } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; if (hw->phy.media_type == e1000_media_type_fiber) hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; else hw->phy.autoneg_advertised = ecmd->advertising | ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } } /* reset the link */ if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else { e1000e_reset(adapter); } clear_bit(__E1000_RESETTING, &adapter->state); return 0; }
static int e1000_set_rx_csum(struct net_device *netdev, u32 data) { struct e1000_adapter *adapter = netdev_priv(netdev); if (data) adapter->flags |= FLAG_RX_CSUM_ENABLED; else adapter->flags &= ~FLAG_RX_CSUM_ENABLED; if (netif_running(netdev)) e1000e_reinit_locked(adapter); else e1000e_reset(adapter); return 0; }
static int e1000_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; int retval = 0; adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else { e1000e_reset(adapter); } } else { if (pause->rx_pause && pause->tx_pause) hw->fc.requested_mode = e1000_fc_full; else if (pause->rx_pause && !pause->tx_pause) hw->fc.requested_mode = e1000_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) hw->fc.requested_mode = e1000_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) hw->fc.requested_mode = e1000_fc_none; hw->fc.current_mode = hw->fc.requested_mode; if (hw->phy.media_type == e1000_media_type_fiber) { retval = hw->mac.ops.setup_link(hw); /* implicit goto out */ } else { retval = e1000e_force_mac_fc(hw); if (retval) goto out; e1000e_set_fc_watermarks(hw); } } out: clear_bit(__E1000_RESETTING, &adapter->state); return retval; }
/** * e1000e_remove - Device Removal Routine * * @v pdev PCI device information struct * **/ void e1000e_remove ( struct pci_device *pdev ) { struct net_device *netdev = pci_get_drvdata ( pdev ); struct e1000_adapter *adapter = netdev_priv ( netdev ); DBGP ( "e1000e_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 ); e1000e_reset ( adapter ); netdev_nullify ( netdev ); netdev_put ( netdev ); }
/** * e1000e_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 e1000e_open ( struct net_device *netdev ) { struct e1000_adapter *adapter = netdev_priv(netdev); int err; DBGP ( "e1000e_open\n" ); /* allocate transmit descriptors */ err = e1000e_setup_tx_resources ( adapter ); if ( err ) { DBG ( "Error setting up TX resources!\n" ); goto err_setup_tx; } /* allocate receive descriptors */ err = e1000e_setup_rx_resources ( adapter ); if ( err ) { DBG ( "Error setting up RX resources!\n" ); goto err_setup_rx; } e1000e_configure_tx ( adapter ); e1000e_configure_rx ( adapter ); DBG ( "E1000_RXDCTL(0): %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) ); return 0; err_setup_rx: DBG ( "err_setup_rx\n" ); e1000e_free_tx_resources ( adapter ); err_setup_tx: DBG ( "err_setup_tx\n" ); e1000e_reset ( adapter ); return err; }
/** * e1000_close - Disables a network interface * * @v netdev network interface device structure * **/ static void e1000e_close ( struct net_device *netdev ) { struct e1000_adapter *adapter = netdev_priv ( netdev ); struct e1000_hw *hw = &adapter->hw; uint32_t rctl; uint32_t icr; DBGP ( "e1000_close\n" ); /* Acknowledge interrupts */ icr = E1000_READ_REG ( hw, E1000_ICR ); e1000e_irq_disable ( adapter ); /* disable receives */ rctl = E1000_READ_REG ( hw, E1000_RCTL ); E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); e1e_flush(); e1000e_reset ( adapter ); e1000e_free_tx_resources ( adapter ); e1000e_free_rx_resources ( adapter ); }
static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; /* * When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw)) { e_err("Cannot change link characteristics when SoL/IDER is active.\n"); return -EINVAL; } /* * MDI setting is only allowed when autoneg enabled because * some hardware doesn't allow MDI setting when speed or * duplex is forced. */ if (ecmd->eth_tp_mdix_ctrl) { if (hw->phy.media_type != e1000_media_type_copper) return -EOPNOTSUPP; if ((ecmd->eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) && (ecmd->autoneg != AUTONEG_ENABLE)) { e_err("forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); return -EINVAL; } } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; if (hw->phy.media_type == e1000_media_type_fiber) hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; else hw->phy.autoneg_advertised = ecmd->advertising | ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { u32 speed = ethtool_cmd_speed(ecmd); /* calling this overrides forced MDI setting */ if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } } /* MDI-X => 2; MDI => 1; Auto => 3 */ if (ecmd->eth_tp_mdix_ctrl) { /* * fix up the value for auto (3 => 0) as zero is mapped * internally to auto */ if (ecmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) hw->phy.mdix = AUTO_ALL_MODES; else hw->phy.mdix = ecmd->eth_tp_mdix_ctrl; } /* reset the link */ if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); } else e1000e_reset(adapter); clear_bit(__E1000_RESETTING, &adapter->state); return 0; }
/** * e1000_probe - Initial configuration of e1000 NIC * * @v pci PCI device * @v id PCI IDs * * @ret rc Return status code **/ int e1000e_probe ( struct pci_device *pdev, const struct pci_device_id *ent) { int i, err; struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; unsigned long flash_start, flash_len; struct e1000_hw *hw; const struct e1000_info *ei = e1000_info_tbl[ent->driver_data]; DBGP ( "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 ) { DBG ( "err_alloc_etherdev\n" ); goto err_alloc_etherdev; } /* Associate e1000-specific network operations operations with * generic network device layer */ netdev_init ( netdev, &e1000e_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->device_id = pdev->device; adapter->irqno = pdev->irq; adapter->netdev = netdev; adapter->hw.back = adapter; adapter->ei = ei; adapter->pba = ei->pba; adapter->flags = ei->flags; adapter->flags2 = ei->flags2; adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; 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; } /* Flash BAR mapping depends on mac_type */ if ( ( adapter->flags & FLAG_HAS_FLASH) && ( pdev->ioaddr ) ) { flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 ); flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 ); adapter->hw.flash_address = ioremap ( flash_start, flash_len ); if ( ! adapter->hw.flash_address ) { DBG ( "err_flashmap\n" ); goto err_flashmap; } } /* setup adapter struct */ err = e1000e_sw_init ( adapter ); if (err) { DBG ( "err_sw_init\n" ); goto err_sw_init; } if (ei->get_variants) { err = ei->get_variants(adapter); if (err) { DBG ( "err_hw_initr\n" ); goto err_hw_init; } } /* Copper options */ if (adapter->hw.phy.media_type == e1000_media_type_copper) { adapter->hw.phy.mdix = AUTO_ALL_MODES; adapter->hw.phy.disable_polarity_correction = 0; adapter->hw.phy.ms_type = e1000_ms_hw_default; } DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type ); /* Force auto-negotiation */ adapter->hw.mac.autoneg = 1; adapter->fc_autoneg = 1; adapter->hw.phy.autoneg_wait_to_complete = true; adapter->hw.mac.adaptive_ifs = true; adapter->hw.fc.requested_mode = e1000_fc_default; adapter->hw.fc.current_mode = e1000_fc_default; /* * before reading the NVM, reset the controller to * put the device in a known good starting state */ adapter->hw.mac.ops.reset_hw(&adapter->hw); /* * systems with ASPM and others may see the checksum fail on the first * attempt. Let's give it a few tries */ for (i = 0;; i++) { if (e1000e_validate_nvm_checksum(&adapter->hw) >= 0) break; if (i == 2) { DBG("The NVM Checksum Is Not Valid\n"); err = -EIO; goto err_eeprom; } } /* copy the MAC address out of the EEPROM */ if ( e1000e_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 */ e1000e_reset ( 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; } for (i = 0; i < 6; i++) DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":"); DBG ( "e1000e_probe succeeded!\n" ); /* No errors, return success */ return 0; /* Error return paths */ err_register: err_hw_init: err_eeprom: err_flashmap: if (!e1000e_check_reset_block(&adapter->hw)) e1000e_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; }