Skip to content

Commit

Permalink
e1000e: add support for 82577/82578 GbE LOM parts
Browse files Browse the repository at this point in the history
This patch provides support for the next generation Intel desktop
and mobile gigabit ethernet LOM adapters.  These adapters are the
follow-on parts to the LOMs tied to the prior ICH chipsets and are
comprised of a MAC in the PCH chipset and an external PHY (82577 for
mobile and 82578 for desktop versions).  New features consist of PHY
wakeup to save power by completely turning off the MAC while in Sx
state, and 4K jumbo frames.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bruce Allan authored and David S. Miller committed Jun 3, 2009
1 parent 2adc55c commit a4f58f5
Show file tree
Hide file tree
Showing 10 changed files with 1,441 additions and 68 deletions.
2 changes: 2 additions & 0 deletions drivers/net/e1000e/82571.c
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,7 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
static struct e1000_mac_operations e82571_mac_ops = {
/* .check_mng_mode: mac type dependent */
/* .check_for_link: media type dependent */
.id_led_init = e1000e_id_led_init,
.cleanup_led = e1000e_cleanup_led_generic,
.clear_hw_cntrs = e1000_clear_hw_cntrs_82571,
.get_bus_info = e1000e_get_bus_info_pcie,
Expand All @@ -1598,6 +1599,7 @@ static struct e1000_mac_operations e82571_mac_ops = {
.init_hw = e1000_init_hw_82571,
.setup_link = e1000_setup_link_82571,
/* .setup_physical_interface: media type dependent */
.setup_led = e1000e_setup_led_generic,
};

static struct e1000_phy_operations e82_phy_ops_igp = {
Expand Down
21 changes: 21 additions & 0 deletions drivers/net/e1000e/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
/* Wake Up Control */
#define E1000_WUC_APME 0x00000001 /* APM Enable */
#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */

/* Wake Up Filter Control */
#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
Expand All @@ -65,6 +66,13 @@
#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */

/* Wake Up Status */
#define E1000_WUS_LNKC E1000_WUFC_LNKC
#define E1000_WUS_MAG E1000_WUFC_MAG
#define E1000_WUS_EX E1000_WUFC_EX
#define E1000_WUS_MC E1000_WUFC_MC
#define E1000_WUS_BC E1000_WUFC_BC

/* Extended Device Control */
#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
Expand All @@ -77,6 +85,7 @@
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
#define E1000_CTRL_EXT_PHYPDEN 0x00100000

/* Receive Descriptor bit definitions */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
Expand Down Expand Up @@ -140,6 +149,7 @@
#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
#define E1000_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min threshold size */
#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
#define E1000_RCTL_SZ_2048 0x00000000 /* Rx buffer size 2048 */
Expand All @@ -153,6 +163,7 @@
#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */

Expand Down Expand Up @@ -255,11 +266,16 @@
#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX

/* LED Control */
#define E1000_PHY_LED0_MODE_MASK 0x00000007
#define E1000_PHY_LED0_IVRT 0x00000008
#define E1000_PHY_LED0_MASK 0x0000001F

#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
#define E1000_LEDCTL_LED0_MODE_SHIFT 0
#define E1000_LEDCTL_LED0_IVRT 0x00000040
#define E1000_LEDCTL_LED0_BLINK 0x00000080

#define E1000_LEDCTL_MODE_LINK_UP 0x2
#define E1000_LEDCTL_MODE_LED_ON 0xE
#define E1000_LEDCTL_MODE_LED_OFF 0xF

Expand Down Expand Up @@ -676,6 +692,8 @@
#define IFE_C_E_PHY_ID 0x02A80310
#define BME1000_E_PHY_ID 0x01410CB0
#define BME1000_E_PHY_ID_R2 0x01410CB1
#define I82577_E_PHY_ID 0x01540050
#define I82578_E_PHY_ID 0x004DD040

/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
Expand Down Expand Up @@ -729,6 +747,9 @@
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800

#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020
#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C

/* BME1000 PHY Specific Control Register */
#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */

Expand Down
57 changes: 57 additions & 0 deletions drivers/net/e1000e/e1000.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,49 @@ struct e1000_info;

#define DEFAULT_JUMBO 9234

/* BM/HV Specific Registers */
#define BM_PORT_CTRL_PAGE 769

#define PHY_UPPER_SHIFT 21
#define BM_PHY_REG(page, reg) \
(((reg) & MAX_PHY_REG_ADDRESS) |\
(((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
(((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))

/* PHY Wakeup Registers and defines */
#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0)
#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))

#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */
#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */
#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */
#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */
#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */
#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */
#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */

#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */
#define HV_SCC_LOWER PHY_REG(778, 17)
#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */
#define HV_ECOL_LOWER PHY_REG(778, 19)
#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */
#define HV_MCC_LOWER PHY_REG(778, 21)
#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */
#define HV_LATECOL_LOWER PHY_REG(778, 24)
#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */
#define HV_COLC_LOWER PHY_REG(778, 26)
#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */
#define HV_DC_LOWER PHY_REG(778, 28)
#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */
#define HV_TNCRS_LOWER PHY_REG(778, 30)

enum e1000_boards {
board_82571,
board_82572,
Expand All @@ -108,6 +151,7 @@ enum e1000_boards {
board_ich8lan,
board_ich9lan,
board_ich10lan,
board_pchlan,
};

struct e1000_queue_stats {
Expand Down Expand Up @@ -305,6 +349,7 @@ struct e1000_adapter {
unsigned int flags2;
struct work_struct downshift_task;
struct work_struct update_phy_task;
struct work_struct led_blink_task;
};

struct e1000_info {
Expand Down Expand Up @@ -355,6 +400,7 @@ struct e1000_info {

/* CRC Stripping defines */
#define FLAG2_CRC_STRIPPING (1 << 0)
#define FLAG2_HAS_PHY_WAKEUP (1 << 1)

#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
Expand Down Expand Up @@ -408,6 +454,7 @@ extern struct e1000_info e1000_82583_info;
extern struct e1000_info e1000_ich8_info;
extern struct e1000_info e1000_ich9_info;
extern struct e1000_info e1000_ich10_info;
extern struct e1000_info e1000_pch_info;
extern struct e1000_info e1000_es2_info;

extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
Expand All @@ -429,6 +476,7 @@ extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
extern s32 e1000e_setup_led_generic(struct e1000_hw *hw);
extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
Expand Down Expand Up @@ -497,6 +545,15 @@ extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
extern s32 e1000e_check_downshift(struct e1000_hw *hw);
extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
extern s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow);
extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
extern s32 e1000_check_polarity_82577(struct e1000_hw *hw);
extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw);

static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
{
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/e1000e/es2lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
}

static struct e1000_mac_operations es2_mac_ops = {
.id_led_init = e1000e_id_led_init,
.check_mng_mode = e1000e_check_mng_mode_generic,
/* check_for_link dependent on media type */
.cleanup_led = e1000e_cleanup_led_generic,
Expand All @@ -1379,6 +1380,7 @@ static struct e1000_mac_operations es2_mac_ops = {
.init_hw = e1000_init_hw_80003es2lan,
.setup_link = e1000e_setup_link,
/* setup_physical_interface dependent on media type */
.setup_led = e1000e_setup_led_generic,
};

static struct e1000_phy_operations es2_phy_ops = {
Expand Down
37 changes: 23 additions & 14 deletions drivers/net/e1000e/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
u32 after;
u32 i;
u32 toggle;
u32 mask;

/*
* The status register is Read Only, so a write should fail.
Expand All @@ -788,17 +789,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
case e1000_80003es2lan:
toggle = 0x7FFFF3FF;
break;
case e1000_82573:
case e1000_82574:
case e1000_82583:
case e1000_ich8lan:
case e1000_ich9lan:
case e1000_ich10lan:
default:
toggle = 0x7FFFF033;
break;
default:
toggle = 0xFFFFF833;
break;
}

before = er32(STATUS);
Expand Down Expand Up @@ -844,11 +837,18 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
mask = 0x8003FFFF;
switch (mac->type) {
case e1000_ich10lan:
case e1000_pchlan:
mask |= (1 << 18);
break;
default:
break;
}
for (i = 0; i < mac->rar_entry_count; i++)
REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
((mac->type == e1000_ich10lan) ?
0x8007FFFF : 0x8003FFFF),
0xFFFFFFFF);
mask, 0xFFFFFFFF);

for (i = 0; i < mac->mta_reg_count; i++)
REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
Expand Down Expand Up @@ -1786,15 +1786,22 @@ static int e1000_set_wol(struct net_device *netdev,
/* bit defines for adapter->led_status */
#define E1000_LED_ON 0

static void e1000_led_blink_callback(unsigned long data)
static void e1000e_led_blink_task(struct work_struct *work)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
struct e1000_adapter *adapter = container_of(work,
struct e1000_adapter, led_blink_task);

if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
adapter->hw.mac.ops.led_off(&adapter->hw);
else
adapter->hw.mac.ops.led_on(&adapter->hw);
}

static void e1000_led_blink_callback(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;

schedule_work(&adapter->led_blink_task);
mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
}

Expand All @@ -1807,7 +1814,9 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
data = INT_MAX;

if ((hw->phy.type == e1000_phy_ife) ||
(hw->mac.type == e1000_pchlan) ||
(hw->mac.type == e1000_82574)) {
INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
if (!adapter->blink_timer.function) {
init_timer(&adapter->blink_timer);
adapter->blink_timer.function =
Expand Down
16 changes: 15 additions & 1 deletion drivers/net/e1000e/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,11 @@ enum e1e_registers {
E1000_RXCSUM = 0x05000, /* Rx Checksum Control - RW */
E1000_RFCTL = 0x05008, /* Receive Filter Control */
E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */
E1000_RA = 0x05400, /* Receive Address - RW Array */
E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */
#define E1000_RAL(_n) (E1000_RAL_BASE + ((_n) * 8))
#define E1000_RA (E1000_RAL(0))
E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */
#define E1000_RAH(_n) (E1000_RAH_BASE + ((_n) * 8))
E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */
E1000_WUC = 0x05800, /* Wakeup Control - RW */
E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */
Expand Down Expand Up @@ -368,6 +372,10 @@ enum e1e_registers {
#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE
#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF
#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA
#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB
#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF
#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0

#define E1000_REVISION_4 4

Expand All @@ -383,6 +391,7 @@ enum e1000_mac_type {
e1000_ich8lan,
e1000_ich9lan,
e1000_ich10lan,
e1000_pchlan,
};

enum e1000_media_type {
Expand Down Expand Up @@ -417,6 +426,8 @@ enum e1000_phy_type {
e1000_phy_igp_3,
e1000_phy_ife,
e1000_phy_bm,
e1000_phy_82578,
e1000_phy_82577,
};

enum e1000_bus_width {
Expand Down Expand Up @@ -720,6 +731,7 @@ struct e1000_host_mng_command_info {

/* Function pointers and static data for the MAC. */
struct e1000_mac_operations {
s32 (*id_led_init)(struct e1000_hw *);
bool (*check_mng_mode)(struct e1000_hw *);
s32 (*check_for_link)(struct e1000_hw *);
s32 (*cleanup_led)(struct e1000_hw *);
Expand All @@ -733,11 +745,13 @@ struct e1000_mac_operations {
s32 (*init_hw)(struct e1000_hw *);
s32 (*setup_link)(struct e1000_hw *);
s32 (*setup_physical_interface)(struct e1000_hw *);
s32 (*setup_led)(struct e1000_hw *);
};

/* Function pointers for the PHY. */
struct e1000_phy_operations {
s32 (*acquire_phy)(struct e1000_hw *);
s32 (*check_polarity)(struct e1000_hw *);
s32 (*check_reset_block)(struct e1000_hw *);
s32 (*commit_phy)(struct e1000_hw *);
s32 (*force_speed_duplex)(struct e1000_hw *);
Expand Down
Loading

0 comments on commit a4f58f5

Please sign in to comment.