diff options
author | Noe Rubinstein <nrubinstein@avencall.com> | 2012-02-09 12:04:05 +0100 |
---|---|---|
committer | Noe Rubinstein <nrubinstein@avencall.com> | 2012-02-16 10:54:51 +0100 |
commit | 9be5a1c601171fd77aca2c978d1895f669a846f3 (patch) | |
tree | 33d83dcb1828941671330cca0168d82f916419bd /drivers/net/ethernet/intel/e1000/e1000_main.c | |
parent | aaf6dd2e34de5db8b8f40297ef4660c7196e8407 (diff) |
net: e1000: Add support for Intel EP80579 and some OEM phys
Support for the following PHYs is addded via the e1000_oem_phy portion of the
addition:
Intel M88E1000
Intel M88E1011
Intel IGP01E1000
Intel M88E1141
Vitesse VSC8211
Vitesse VSC8601
Signed-off-by: Noe Rubinstein <nrubinstein@avencall.com>
Diffstat (limited to 'drivers/net/ethernet/intel/e1000/e1000_main.c')
-rw-r--r-- | drivers/net/ethernet/intel/e1000/e1000_main.c | 212 |
1 files changed, 200 insertions, 12 deletions
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 1f86a70b88a..ea12cc65646 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -27,6 +27,11 @@ *******************************************************************************/ #include "e1000.h" +#include "e1000_oem_phy.h" +#ifdef CONFIG_E1000_EP80579 +#include "gcu_if.h" +#endif + #include <net/ip6_checksum.h> #include <linux/io.h> #include <linux/prefetch.h> @@ -83,6 +88,18 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { INTEL_E1000_ETHERNET_DEVICE(0x108A), INTEL_E1000_ETHERNET_DEVICE(0x1099), INTEL_E1000_ETHERNET_DEVICE(0x10B5), + INTEL_E1000_ETHERNET_DEVICE(0x5040), + INTEL_E1000_ETHERNET_DEVICE(0x5041), + INTEL_E1000_ETHERNET_DEVICE(0x5042), + INTEL_E1000_ETHERNET_DEVICE(0x5043), + INTEL_E1000_ETHERNET_DEVICE(0x5044), + INTEL_E1000_ETHERNET_DEVICE(0x5045), + INTEL_E1000_ETHERNET_DEVICE(0x5046), + INTEL_E1000_ETHERNET_DEVICE(0x5047), + INTEL_E1000_ETHERNET_DEVICE(0x5048), + INTEL_E1000_ETHERNET_DEVICE(0x5049), + INTEL_E1000_ETHERNET_DEVICE(0x504A), + INTEL_E1000_ETHERNET_DEVICE(0x504B), INTEL_E1000_ETHERNET_DEVICE(0x2E6E), /* required last entry */ {0,} @@ -219,6 +236,13 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +#ifdef CONFIG_E1000_EP80579 +static uint8_t gcu_suspend = 0x0; +static uint8_t gcu_resume = 0x0; +static struct pci_dev *gcu; +#endif + + /** * e1000_get_hw_dev - return device * used by hardware layer to print debugging information @@ -252,10 +276,15 @@ static int __init e1000_init_module(void) pr_info("copybreak enabled for " "packets <= %u bytes\n", copybreak); } + return ret; } +#ifdef CONFIG_E1000_EP80579 +late_initcall(e1000_init_module); +#else module_init(e1000_init_module); +#endif /** * e1000_exit_module - Driver Exit Cleanup Routine @@ -580,6 +609,7 @@ void e1000_reset(struct e1000_adapter *adapter) case e1000_82540: case e1000_82541: case e1000_82541_rev_2: + case e1000_icp_xxxx: legacy_pba_adjust = true; pba = E1000_PBA_48K; break; @@ -912,12 +942,13 @@ static int e1000_init_hw_struct(struct e1000_adapter *adapter, /* Copper options */ - if (hw->media_type == e1000_media_type_copper) { + if (hw->media_type == e1000_media_type_copper + || (hw->media_type == e1000_media_type_oem + && e1000_oem_phy_is_copper(&adapter->hw))) { hw->mdix = AUTO_ALL_MODES; hw->disable_polarity_correction = false; hw->master_slave = E1000_MASTER_SLAVE; } - return 0; } @@ -1143,6 +1174,12 @@ static int __devinit e1000_probe(struct pci_dev *pdev, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); eeprom_apme_mask = E1000_EEPROM_82544_APM; break; + case e1000_icp_xxxx: + e1000_read_eeprom(&adapter->hw, + EEPROM_INIT_CONTROL3_ICP_xxxx(adapter->bd_number), + 1, &eeprom_data); + eeprom_apme_mask = EEPROM_CTRL3_APME_ICP_xxxx; + break; case e1000_82546: case e1000_82546_rev_3: if (er32(STATUS) & E1000_STATUS_FUNC_1){ @@ -1189,6 +1226,17 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->wol = adapter->eeprom_wol; device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + /* The ICP_xxxx device has multiple, duplicate interrupt + * registers, so disable all but the first one + */ + if (adapter->hw.mac_type == e1000_icp_xxxx) { + int offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_ST) + + PCI_ST_SMIA_OFFSET; + pci_write_config_dword(adapter->pdev, offset, 0x00000006); + E1000_WRITE_REG(&adapter->hw, IMC1, ~0UL); + E1000_WRITE_REG(&adapter->hw, IMC2, ~0UL); + } + /* Auto detect PHY address */ if (hw->mac_type == e1000_ce4100) { for (i = 0; i < 32; i++) { @@ -1206,7 +1254,28 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* reset the hardware with the new settings */ e1000_reset(adapter); - strcpy(netdev->name, "eth%d"); + if (adapter->hw.mac_type != e1000_icp_xxxx) { + strcpy(netdev->name, "eth%d"); + } else { + uint32_t dev_num; + dev_num = PCI_SLOT(adapter->pdev->devfn); + + switch (dev_num) { + case ICP_XXXX_MAC_0: + strcpy(netdev->name, + CONFIG_E1000_EP80579_MAC0_BASE_NAME "%d"); + break; + case ICP_XXXX_MAC_1: + strcpy(netdev->name, + CONFIG_E1000_EP80579_MAC1_BASE_NAME "%d"); + break; + case ICP_XXXX_MAC_2: + strcpy(netdev->name, + CONFIG_E1000_EP80579_MAC2_BASE_NAME "%d"); + break; + } + } + err = register_netdev(netdev); if (err) goto err_register; @@ -1314,6 +1383,14 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) /* Explicitly disable IRQ since the NIC can be in any state. */ e1000_irq_disable(adapter); + /* + * for ICP_XXXX style controllers, it is necessary to keep + * track of the last known state of the link to determine if + * the link experienced a change in state when e1000_watchdog + * fires + */ + adapter->hw.icp_xxxx_is_link_up = false; + spin_lock_init(&adapter->stats_lock); mutex_init(&adapter->mutex); @@ -1624,8 +1701,12 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) if ((hw->media_type == e1000_media_type_fiber || hw->media_type == e1000_media_type_internal_serdes)) tipg = DEFAULT_82543_TIPG_IPGT_FIBER; - else + else if (hw->media_type != e1000_media_type_oem) tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + else + tipg = (0xFFFFFFFFUL >> (sizeof(tipg)*0x8 - + E1000_TIPG_IPGR1_SHIFT)) + & e1000_oem_get_tipg(&adapter->hw); switch (hw->mac_type) { case e1000_82542_rev2_0: @@ -2381,6 +2462,23 @@ bool e1000_has_link(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; bool link_active = false; + /* + * Test the PHY for link status on icp_xxxx MACs. + * If the link status is different than the last link status stored + * in the adapter->hw structure, then set hw->get_link_status = 1 + */ + if (adapter->hw.mac_type == e1000_icp_xxxx) { + int isUp = 0; + int32_t ret_val; + + ret_val = e1000_oem_phy_is_link_up(&adapter->hw, &isUp); + if (ret_val != E1000_SUCCESS) + isUp = 0; + + if (isUp != adapter->hw.icp_xxxx_is_link_up) + adapter->hw.get_link_status = 1; + } + /* get_link_status is set on LSC (link status) interrupt or rx * sequence error interrupt (except on intel ce4100). * get_link_status will stay false until the @@ -2406,10 +2504,23 @@ bool e1000_has_link(struct e1000_adapter *adapter) e1000_check_for_link(hw); link_active = hw->serdes_has_link; break; + case e1000_media_type_oem: + e1000_check_for_link(hw); + break; default: break; } + if (adapter->hw.mac_type == e1000_icp_xxxx) { + int isUp = 0x0; + + if (e1000_oem_phy_is_link_up(&adapter->hw, &isUp) != + E1000_SUCCESS) + isUp = 0x0; + + link_active = isUp; + } + return link_active; } @@ -3708,7 +3819,9 @@ void e1000_update_stats(struct e1000_adapter *adapter) /* Tx Dropped needs to be maintained elsewhere */ /* Phy Stats */ - if (hw->media_type == e1000_media_type_copper) { + if (hw->media_type == e1000_media_type_copper + || (hw->media_type == e1000_media_type_oem + && e1000_oem_phy_is_copper(&adapter->hw))) { if ((adapter->link_speed == SPEED_1000) && (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; @@ -4648,7 +4761,10 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, u16 mii_reg; unsigned long flags; - if (hw->media_type != e1000_media_type_copper) + if ((adapter->hw.media_type == e1000_media_type_oem + && !e1000_oem_phy_is_copper(&adapter->hw)) + || (adapter->hw.media_type != e1000_media_type_copper + && adapter->hw.media_type != e1000_media_type_oem)) return -EOPNOTSUPP; switch (cmd) { @@ -4675,7 +4791,11 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, return -EIO; } spin_unlock_irqrestore(&adapter->stats_lock, flags); - if (hw->media_type == e1000_media_type_copper) { + if (adapter->hw.phy_type == e1000_phy_oem) { + retval = e1000_oem_mii_ioctl(adapter, flags, ifr, cmd); + if (retval) + return retval; + } else if (hw->media_type == e1000_media_type_copper) { switch (data->reg_num) { case PHY_CTRL: if (mii_reg & MII_CR_POWER_DOWN) @@ -4897,11 +5017,14 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) goto err_inval; /* Fiber NICs only allow 1000 gbps Full duplex */ - if ((hw->media_type == e1000_media_type_fiber) && + if ((hw->media_type == e1000_media_type_fiber || + (adapter->hw.media_type == e1000_media_type_oem && + !e1000_oem_phy_is_copper(&adapter->hw))) && spd != SPEED_1000 && dplx != DUPLEX_FULL) goto err_inval; + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: hw->forced_speed_duplex = e1000_10_half; @@ -4954,9 +5077,22 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) return retval; #endif - status = er32(STATUS); - if (status & E1000_STATUS_LU) - wufc &= ~E1000_WUFC_LNKC; + /* + * ICP_XXXX style MACs do not have a link up bit in + * the STATUS register, query the PHY directly + */ + if (adapter->hw.mac_type != e1000_icp_xxxx) { + status = er32(STATUS); + if (status & E1000_STATUS_LU) + wufc &= ~E1000_WUFC_LNKC; + } else { + int isUp = 0; + if (e1000_oem_phy_is_link_up(&adapter->hw, &isUp) != + E1000_SUCCESS) + isUp = 0; + if (isUp) + wufc &= ~E1000_WUFC_LNKC; + } if (wufc) { e1000_setup_rctl(adapter); @@ -4976,7 +5112,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) /* phy power management enable */ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 ctrl |= E1000_CTRL_ADVD3WUC | - E1000_CTRL_EN_PHY_PWR_MGMT; + (adapter->hw.mac_type != e1000_icp_xxxx + ? E1000_CTRL_EN_PHY_PWR_MGMT : 0x0); ew32(CTRL, ctrl); } @@ -5014,8 +5151,11 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) #ifdef CONFIG_PM static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); int retval; bool wake; + u16 cmd_word; retval = __e1000_shutdown(pdev, &wake); if (retval) @@ -5028,6 +5168,34 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_set_power_state(pdev, PCI_D3hot); } + if (adapter->hw.mac_type == e1000_icp_xxxx) { + /* + * ICP xxxx devices are not true PCI devices, in the context + * of power management, disabling the bus mastership is not + * sufficient to disable the device, it is also necessary to + * disable IO, Memory, and Interrupts if they are enabled. + */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd_word); + + cmd_word &= ~PCI_COMMAND_IO; + cmd_word &= ~PCI_COMMAND_MEMORY; + cmd_word &= ~PCI_COMMAND_INTX_DISABLE; + + pci_write_config_word(pdev, PCI_COMMAND, cmd_word); + } + +#ifdef CONFIG_E1000_EP80579 + if (gcu_suspend == 0x0) { + if (gcu == NULL) + gcu = + pci_get_device(PCI_VENDOR_ID_INTEL, GCU_DEVID, + NULL); + gcu_e1000_suspend(gcu, 0x3); + gcu_suspend = 0x1; + gcu_resume = 0x0; + } +#endif + return 0; } @@ -5037,6 +5205,26 @@ static int e1000_resume(struct pci_dev *pdev) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u32 err; + u32 vdid; + +#ifdef CONFIG_E1000_EP80579 + if (gcu_resume == 0x0) { + if (gcu == NULL) { + gcu = + pci_get_device(PCI_VENDOR_ID_INTEL, GCU_DEVID, + NULL); + pci_read_config_dword(gcu, 0x00, &vdid); + } + + if (gcu) { + gcu_e1000_resume(gcu); + gcu_resume = 0x1; + gcu_suspend = 0x0; + } else { + printk(KERN_ERR "Unable to resume GCU!\n"); + } + } +#endif pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); |