Commit 7949d93e authored by Scott Feldman's avatar Scott Feldman Committed by Jeff Garzik

e1000 net driver update 3/4:

* Added four new device IDs: 82545EM_COPPER, 82545EM_FIBER,
82546EB_COPPER, 82546EB_FIBER.
* Added a couple magic number definitions for DMA addressable bits.
* Added Power Management Suspend/Resume support.
* Added reboot notifier registration to setup WOL when shutting down.
parent a8ea92e8
......@@ -107,17 +107,21 @@
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
#include <linux/ethtool.h>
#ifdef NETIF_F_HW_VLAN_TX
#include <linux/if_vlan.h>
#endif
#define BAR_0 0
#define PCI_DMA_64BIT 0xffffffffffffffffULL
#define PCI_DMA_32BIT 0x00000000ffffffffULL
struct e1000_adapter;
#include "e1000_hw.h"
#define BAR_0 0
#if DBG
#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
#else
......@@ -233,5 +237,7 @@ struct e1000_adapter {
struct e1000_phy_stats phy_stats;
uint32_t pci_state[16];
};
#endif /* _E1000_H_ */
......@@ -82,7 +82,6 @@ extern char e1000_driver_version[];
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_enable_WOL(struct e1000_adapter *adapter);
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
......@@ -127,6 +126,10 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
SUPPORTED_Autoneg);
ecmd->port = PORT_FIBRE;
if(hw->mac_type >= e1000_82545)
ecmd->transceiver = XCVR_INTERNAL;
else
ecmd->transceiver = XCVR_EXTERNAL;
}
......@@ -264,12 +267,33 @@ e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
struct e1000_hw *hw = &adapter->hw;
if(hw->mac_type < e1000_82544) {
switch(adapter->hw.device_id) {
case E1000_DEV_ID_82542:
case E1000_DEV_ID_82543GC_FIBER:
case E1000_DEV_ID_82543GC_COPPER:
case E1000_DEV_ID_82544EI_FIBER:
default:
wol->supported = 0;
wol->wolopts = 0;
return;
}
case E1000_DEV_ID_82546EB_FIBER:
/* Wake events only supported on port A for dual fiber */
if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) {
wol->supported = 0;
wol->wolopts = 0;
return;
}
/* Fall Through */
case E1000_DEV_ID_82544EI_COPPER:
case E1000_DEV_ID_82544GC_COPPER:
case E1000_DEV_ID_82544GC_LOM:
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
wol->supported = WAKE_PHY | WAKE_UCAST |
WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
......@@ -284,6 +308,8 @@ e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
wol->wolopts |= WAKE_BCAST;
if(adapter->wol & E1000_WUFC_MAG)
wol->wolopts |= WAKE_MAGIC;
return;
}
}
static int
......@@ -291,8 +317,30 @@ e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
struct e1000_hw *hw = &adapter->hw;
if(hw->mac_type < e1000_82544)
switch(adapter->hw.device_id) {
case E1000_DEV_ID_82542:
case E1000_DEV_ID_82543GC_FIBER:
case E1000_DEV_ID_82543GC_COPPER:
case E1000_DEV_ID_82544EI_FIBER:
default:
return wol->wolopts ? -EOPNOTSUPP : 0;
case E1000_DEV_ID_82546EB_FIBER:
/* Wake events only supported on port A for dual fiber */
if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
return wol->wolopts ? -EOPNOTSUPP : 0;
/* Fall Through */
case E1000_DEV_ID_82544EI_COPPER:
case E1000_DEV_ID_82544GC_COPPER:
case E1000_DEV_ID_82544GC_LOM:
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
if(wol->wolopts & WAKE_ARP)
return -EOPNOTSUPP;
adapter->wol = 0;
......@@ -306,8 +354,8 @@ e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
adapter->wol |= E1000_WUFC_BC;
if(wol->wolopts & WAKE_MAGIC)
adapter->wol |= E1000_WUFC_MAG;
}
e1000_enable_WOL(adapter);
return 0;
}
......
......@@ -2070,6 +2070,8 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
break;
case e1000_82540:
case e1000_82545:
case e1000_82546:
if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
break;
default:
......@@ -2530,6 +2532,13 @@ e1000_read_mac_addr(struct e1000_hw * hw)
hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
}
if((hw->mac_type == e1000_82546) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
if(hw->perm_mac_addr[5] & 0x01)
hw->perm_mac_addr[5] &= ~(0x01);
else
hw->perm_mac_addr[5] |= 0x01;
}
for(i = 0; i < NODE_ADDRESS_SIZE; i++)
hw->mac_addr[i] = hw->perm_mac_addr[i];
return 0;
......@@ -2884,8 +2893,22 @@ e1000_setup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82544GC_LOM:
/* No setup necessary */
break;
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_FIBER:
ledctl = E1000_READ_REG(hw, LEDCTL);
/* Save current LEDCTL settings */
hw->ledctl_default = ledctl;
/* Turn off LED0 */
ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
E1000_LEDCTL_LED0_BLINK |
E1000_LEDCTL_LED0_MODE_MASK);
ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
default:
......@@ -2917,6 +2940,10 @@ e1000_cleanup_led(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
/* Restore LEDCTL settings */
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
break;
......@@ -2953,6 +2980,8 @@ e1000_led_on(struct e1000_hw *hw)
case E1000_DEV_ID_82544EI_COPPER:
case E1000_DEV_ID_82544GC_COPPER:
case E1000_DEV_ID_82544GC_LOM:
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_FIBER:
ctrl = E1000_READ_REG(hw, CTRL);
/* Clear SW Defineable Pin 0 to turn on the LED */
ctrl &= ~E1000_CTRL_SWDPIN0;
......@@ -2961,6 +2990,8 @@ e1000_led_on(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
break;
default:
......@@ -2996,6 +3027,8 @@ e1000_led_off(struct e1000_hw *hw)
case E1000_DEV_ID_82544EI_COPPER:
case E1000_DEV_ID_82544GC_COPPER:
case E1000_DEV_ID_82544GC_LOM:
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_FIBER:
ctrl = E1000_READ_REG(hw, CTRL);
/* Set SW Defineable Pin 0 to turn off the LED */
ctrl |= E1000_CTRL_SWDPIN0;
......@@ -3004,6 +3037,8 @@ e1000_led_off(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
default:
......
......@@ -92,6 +92,8 @@ typedef enum {
e1000_82543,
e1000_82544,
e1000_82540,
e1000_82545,
e1000_82546,
e1000_num_macs
} e1000_mac_type;
......@@ -272,7 +274,11 @@ void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
#define E1000_DEV_ID_82544GC_LOM 0x100D
#define E1000_DEV_ID_82540EM 0x100E
#define E1000_DEV_ID_82540EM_LOM 0x1015
#define NUM_DEV_IDS 9
#define E1000_DEV_ID_82545EM_COPPER 0x100F
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
#define NUM_DEV_IDS 13
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
......
......@@ -114,6 +114,10 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
{0,}
};
......@@ -169,13 +173,24 @@ static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
struct e1000_rx_desc *rx_desc,
struct sk_buff *skb);
void e1000_enable_WOL(struct e1000_adapter *adapter);
#ifdef NETIF_F_HW_VLAN_TX
static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
#endif
static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
#ifdef CONFIG_PM
static int e1000_resume(struct pci_dev *pdev);
#endif
struct notifier_block e1000_notifier = {
notifier_call: e1000_notify_reboot,
next: NULL,
priority: 0
};
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
......@@ -189,8 +204,10 @@ static struct pci_driver e1000_driver = {
probe: e1000_probe,
remove: __devexit_p(e1000_remove),
/* Power Managment Hooks */
suspend: NULL,
resume: NULL
#ifdef CONFIG_PM
suspend: e1000_suspend,
resume: e1000_resume
#endif
};
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
......@@ -207,12 +224,16 @@ MODULE_LICENSE("Dual BSD/GPL");
static int __init
e1000_init_module(void)
{
int ret;
printk(KERN_INFO "%s - version %s\n",
e1000_driver_string, e1000_driver_version);
printk(KERN_INFO "%s\n", e1000_copyright);
return pci_module_init(&e1000_driver);
ret = pci_module_init(&e1000_driver);
if(ret >= 0)
register_reboot_notifier(&e1000_notifier);
return ret;
}
module_init(e1000_init_module);
......@@ -227,6 +248,7 @@ module_init(e1000_init_module);
static void __exit
e1000_exit_module(void)
{
unregister_reboot_notifier(&e1000_notifier);
pci_unregister_driver(&e1000_driver);
}
......@@ -290,11 +312,11 @@ e1000_reset(struct e1000_adapter *adapter)
adapter->hw.fc = adapter->hw.original_fc;
e1000_reset_hw(&adapter->hw);
if(adapter->hw.mac_type >= e1000_82544)
E1000_WRITE_REG(&adapter->hw, WUC, 0);
e1000_init_hw(&adapter->hw);
e1000_reset_adaptive(&adapter->hw);
e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
e1000_enable_WOL(adapter);
}
/**
......@@ -324,10 +346,10 @@ e1000_probe(struct pci_dev *pdev,
if((i = pci_enable_device(pdev)))
return i;
if(!(i = pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff))) {
if(!(i = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
pci_using_dac = 1;
} else {
if((i = pci_set_dma_mask(pdev, (u64) 0xffffffff))) {
if((i = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
E1000_ERR("No usable DMA configuration, aborting\n");
return i;
}
......@@ -447,6 +469,15 @@ e1000_probe(struct pci_dev *pdev,
e1000_check_options(adapter);
e1000_proc_dev_setup(adapter);
/* Initial Wake on LAN setting
* If APM wake is enabled in the EEPROM,
* enable the ACPI Magic Packet filter
*/
if((adapter->hw.mac_type >= e1000_82544) &&
(E1000_READ_REG(&adapter->hw, WUC) & E1000_WUC_APME))
adapter->wol |= E1000_WUFC_MAG;
/* reset the hardware with the new settings */
e1000_reset(adapter);
......@@ -557,6 +588,14 @@ e1000_sw_init(struct e1000_adapter *adapter)
case E1000_DEV_ID_82540EM:
hw->mac_type = e1000_82540;
break;
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82545EM_FIBER:
hw->mac_type = e1000_82545;
break;
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
hw->mac_type = e1000_82546;
break;
default:
/* should never have loaded on this device */
BUG();
......@@ -1981,29 +2020,6 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
}
}
/**
* e1000_enable_WOL - Wake On Lan Support (Magic Pkt)
* @adapter: Adapter structure
**/
void
e1000_enable_WOL(struct e1000_adapter *adapter)
{
uint32_t wuc;
if(adapter->hw.mac_type < e1000_82544)
return;
if(adapter->wol) {
wuc = E1000_WUC_APME | E1000_WUC_PME_EN |
E1000_WUC_PME_STATUS | E1000_WUC_APMPME;
E1000_WRITE_REG(&adapter->hw, WUC, wuc);
E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
}
}
void
e1000_write_pci_cfg(struct e1000_hw *hw,
uint32_t reg, uint16_t *value)
......@@ -2091,4 +2107,93 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
}
#endif
static int
e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{
struct pci_dev *pdev = NULL;
switch(event) {
case SYS_DOWN:
case SYS_HALT:
case SYS_POWER_OFF:
pci_for_each_dev(pdev) {
if(pci_dev_driver(pdev) == &e1000_driver)
e1000_suspend(pdev, 3);
}
}
return NOTIFY_DONE;
}
static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev->priv;
uint32_t ctrl, ctrl_ext, rctl;
netif_device_detach(netdev);
if(netif_running(netdev))
e1000_down(adapter);
if(adapter->wol) {
e1000_setup_rctl(adapter);
e1000_set_multi(netdev);
if(adapter->wol & E1000_WUFC_MC) {
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_MPE;
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
}
if(adapter->hw.media_type == e1000_media_type_fiber) {
#define E1000_CTRL_ADVD3WUC 0x00100000
ctrl = E1000_READ_REG(&adapter->hw, CTRL);
ctrl |= E1000_CTRL_ADVD3WUC;
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext);
}
E1000_WRITE_REG(&adapter->hw, WUC, 0);
E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
pci_enable_wake(pdev, 3, 1);
} else {
E1000_WRITE_REG(&adapter->hw, WUC, 0);
E1000_WRITE_REG(&adapter->hw, WUFC, 0);
pci_enable_wake(pdev, 3, 0);
}
pci_save_state(pdev, adapter->pci_state);
pci_set_power_state(pdev, 3);
return 0;
}
#ifdef CONFIG_PM
static int
e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev->priv;
pci_set_power_state(pdev, 0);
pci_restore_state(pdev, adapter->pci_state);
pci_enable_wake(pdev, 0, 0);
/* Clear the wakeup status bits */
E1000_WRITE_REG(&adapter->hw, WUS, ~0);
if(netif_running(netdev))
e1000_up(adapter);
netif_device_attach(netdev);
return 0;
}
#endif
/* e1000_main.c */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment