The following adds support for Intel 82580 based cards like
the Intel i340 and HP NC365T. Please test to make sure
it does not break your existing em, especially with multiport
setups.
Index: if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.260
diff -u -p -r1.260 if_em.c
--- if_em.c 30 Aug 2011 02:51:19 -0000 1.260
+++ if_em.c 19 Sep 2011 20:22:40 -0000
@@ -465,6 +465,30 @@ em_attach(struct device *parent, struct
}
}
+ if (sc->hw.mac_type == em_80003es2lan || sc->hw.mac_type == em_82575 ||
+ sc->hw.mac_type == em_82580) {
+ uint32_t reg = EM_READ_REG(&sc->hw, E1000_STATUS);
+ sc->hw.bus_func = (reg & E1000_STATUS_FUNC_MASK) >>
+ E1000_STATUS_FUNC_SHIFT;
+
+ switch (sc->hw.bus_func) {
+ case 0:
+ sc->hw.swfw = E1000_SWFW_PHY0_SM;
+ break;
+ case 1:
+ sc->hw.swfw = E1000_SWFW_PHY1_SM;
+ break;
+ case 2:
+ sc->hw.swfw = E1000_SWFW_PHY2_SM;
+ break;
+ case 3:
+ sc->hw.swfw = E1000_SWFW_PHY3_SM;
+ break;
+ }
+ } else {
+ sc->hw.bus_func = 0;
+ }
+
/* Copy the permanent MAC address out of the EEPROM */
if (em_read_mac_addr(&sc->hw) < 0) {
printf("%s: EEPROM read error while reading mac address\n",
@@ -1814,7 +1838,7 @@ em_setup_interface(struct em_softc *sc)
ifp->if_capabilities = IFCAP_VLAN_MTU;
#if NVLAN > 0
- if (sc->hw.mac_type != em_82575)
+ if (sc->hw.mac_type != em_82575 && sc->hw.mac_type != em_82580)
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
#endif
@@ -2175,7 +2199,7 @@ em_initialize_transmit_unit(struct em_so
/* Setup Transmit Descriptor Base Settings */
sc->txd_cmd = E1000_TXD_CMD_IFCS;
- if (sc->hw.mac_type == em_82575) {
+ if (sc->hw.mac_type == em_82575 || sc->hw.mac_type == em_82580) {
/* 82575/6 need to enable the TX queue and lack the IDE bit */
reg_tctl = E1000_READ_REG(&sc->hw, TXDCTL);
reg_tctl |= E1000_TXDCTL_QUEUE_ENABLE;
@@ -2629,6 +2653,14 @@ em_initialize_receive_unit(struct em_sof
*/
if (sc->hw.mac_type == em_82573)
E1000_WRITE_REG(&sc->hw, RDTR, 0x20);
+
+ if (sc->hw.mac_type == em_82575 || sc->hw.mac_type == em_82580) {
+ /* 82575/6 need to enable the RX queue */
+ uint32_t reg;
+ reg = E1000_READ_REG(&sc->hw, RXDCTL);
+ reg |= E1000_RXDCTL_QUEUE_ENABLE;
+ E1000_WRITE_REG(&sc->hw, RXDCTL, reg);
+ }
/* Enable Receives */
E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
Index: if_em_hw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.65
diff -u -p -r1.65 if_em_hw.c
--- if_em_hw.c 2 May 2011 18:16:58 -0000 1.65
+++ if_em_hw.c 19 Sep 2011 20:22:41 -0000
@@ -955,6 +955,26 @@ em_reset_hw(struct em_hw *hw)
kab |= E1000_KABGTXD_BGSQLBIAS;
E1000_WRITE_REG(hw, KABGTXD, kab);
}
+
+ if (hw->mac_type == em_82580) {
+ uint32_t mdicnfg;
+ uint16_t nvm_data;
+
+ /* clear global device reset status bit */
+ EM_WRITE_REG(hw, E1000_STATUS, E1000_STATUS_DEV_RST_SET);
+
+ em_read_eeprom(hw, EEPROM_INIT_CONTROL3_PORT_A +
+ NVM_82580_LAN_FUNC_OFFSET(hw->bus_func), 1,
+ &nvm_data);
+
+ mdicnfg = EM_READ_REG(hw, E1000_MDICNFG);
+ if (nvm_data & NVM_WORD24_EXT_MDIO)
+ mdicnfg |= E1000_MDICNFG_EXT_MDIO;
+ if (nvm_data & NVM_WORD24_COM_MDIO)
+ mdicnfg |= E1000_MDICNFG_COM_MDIO;
+ EM_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
+ }
+
return E1000_SUCCESS;
}
@@ -4575,20 +4595,13 @@ int32_t
em_write_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t phy_data)
{
uint32_t ret_val;
- uint16_t swfw;
DEBUGFUNC("em_write_phy_reg");
if (hw->mac_type == em_pchlan ||
hw->mac_type == em_pch2lan)
return (em_access_phy_reg_hv(hw, reg_addr, &phy_data, FALSE));
- if (((hw->mac_type == em_80003es2lan) || (hw->mac_type == em_82575)) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
- swfw = E1000_SWFW_PHY1_SM;
- } else {
- swfw = E1000_SWFW_PHY0_SM;
- }
- if (em_swfw_sync_acquire(hw, swfw))
+ if (em_swfw_sync_acquire(hw, hw->swfw))
return -E1000_ERR_SWFW_SYNC;
if ((hw->phy_type == em_phy_igp ||
@@ -4598,7 +4611,7 @@ em_write_phy_reg(struct em_hw *hw, uint3
ret_val = em_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(uint16_t) reg_addr);
if (ret_val) {
- em_swfw_sync_release(hw, swfw);
+ em_swfw_sync_release(hw, hw->swfw);
return ret_val;
}
} else if (hw->phy_type == em_phy_gg82563) {
@@ -4623,7 +4636,7 @@ em_write_phy_reg(struct em_hw *hw, uint3
}
if (ret_val) {
- em_swfw_sync_release(hw, swfw);
+ em_swfw_sync_release(hw, hw->swfw);
return ret_val;
}
}
@@ -4639,7 +4652,7 @@ em_write_phy_reg(struct em_hw *hw, uint3
ret_val = em_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
phy_data);
- em_swfw_sync_release(hw, swfw);
+ em_swfw_sync_release(hw, hw->swfw);
return ret_val;
}
@@ -4719,16 +4732,9 @@ STATIC int32_t
em_read_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *data)
{
uint32_t reg_val;
- uint16_t swfw;
DEBUGFUNC("em_read_kmrn_reg");
- if ((hw->mac_type == em_80003es2lan) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
- swfw = E1000_SWFW_PHY1_SM;
- } else {
- swfw = E1000_SWFW_PHY0_SM;
- }
- if (em_swfw_sync_acquire(hw, swfw))
+ if (em_swfw_sync_acquire(hw, hw->swfw))
return -E1000_ERR_SWFW_SYNC;
/* Write register address */
@@ -4743,7 +4749,7 @@ em_read_kmrn_reg(struct em_hw *hw, uint3
reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
*data = (uint16_t) reg_val;
- em_swfw_sync_release(hw, swfw);
+ em_swfw_sync_release(hw, hw->swfw);
return E1000_SUCCESS;
}
@@ -4751,17 +4757,9 @@ STATIC int32_t
em_write_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data)
{
uint32_t reg_val;
- uint16_t swfw;
DEBUGFUNC("em_write_kmrn_reg");
- if ((hw->mac_type == em_80003es2lan) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
- swfw = E1000_SWFW_PHY1_SM;
- } else {
- swfw = E1000_SWFW_PHY0_SM;
- }
-
- if (em_swfw_sync_acquire(hw, swfw))
+ if (em_swfw_sync_acquire(hw, hw->swfw))
return -E1000_ERR_SWFW_SYNC;
reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) &
@@ -4770,7 +4768,7 @@ em_write_kmrn_reg(struct em_hw *hw, uint
E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
usec_delay(2);
- em_swfw_sync_release(hw, swfw);
+ em_swfw_sync_release(hw, hw->swfw);
return E1000_SUCCESS;
}
@@ -4785,7 +4783,6 @@ em_phy_hw_reset(struct em_hw *hw)
uint32_t ctrl, ctrl_ext;
uint32_t led_ctrl;
int32_t ret_val;
- uint16_t swfw;
DEBUGFUNC("em_phy_hw_reset");
/*
* In the case of the phy reset being blocked, it's not an error, we
@@ -4798,14 +4795,7 @@ em_phy_hw_reset(struct em_hw *hw)
DEBUGOUT("Resetting Phy...\n");
if (hw->mac_type > em_82543 && hw->mac_type != em_icp_xxxx) {
- if (((hw->mac_type == em_80003es2lan) ||
- (hw->mac_type == em_82575)) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
- swfw = E1000_SWFW_PHY1_SM;
- } else {
- swfw = E1000_SWFW_PHY0_SM;
- }
- if (em_swfw_sync_acquire(hw, swfw)) {
+ if (em_swfw_sync_acquire(hw, hw->swfw)) {
DEBUGOUT("Unable to acquire swfw sync\n");
return -E1000_ERR_SWFW_SYNC;
}
@@ -4831,7 +4821,7 @@ em_phy_hw_reset(struct em_hw *hw)
if (hw->mac_type >= em_82571)
msec_delay_irq(10);
- em_swfw_sync_release(hw, swfw);
+ em_swfw_sync_release(hw, hw->swfw);
/*
* the M88E1141_E_PHY_ID might need reset here, but nothing
* proves it
@@ -5130,8 +5120,16 @@ em_match_gig_phy(struct em_hw *hw)
match = TRUE;
break;
case em_82580:
- if (hw->phy_id == I82580_I_PHY_ID)
+ if (hw->phy_id == I82580_I_PHY_ID) {
+ uint32_t mdic;
+
+ mdic = EM_READ_REG(hw, E1000_MDICNFG);
+ mdic &= E1000_MDICNFG_PHY_MASK;
+ hw->phy_addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
+ DEBUGOUT1("MDICNFG PHY ADDR %d",
+ mdic >> E1000_MDICNFG_PHY_SHIFT);
match = TRUE;
+ }
break;
case em_80003es2lan:
if (hw->phy_id == GG82563_E_PHY_ID)
@@ -5252,6 +5250,14 @@ em_detect_gig_phy(struct em_hw *hw)
if (hw->mac_type == em_80003es2lan)
hw->phy_type = em_phy_gg82563;
+ /* Power on SGMII phy if it is disabled */
+ if (hw->mac_type == em_82580) {
+ uint32_t ctrl_ext = EM_READ_REG(hw, E1000_CTRL_EXT);
+ EM_WRITE_REG(hw, E1000_CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
+ delay(300);
+ }
+
/* Read the PHY ID Registers to identify which PHY is onboard. */
for (hw->phy_addr = 1; (hw->phy_addr < 4); hw->phy_addr++) {
ret_val = em_match_gig_phy(hw);
@@ -6641,6 +6647,8 @@ em_read_mac_addr(struct em_hw *hw)
if (hw->mac_type == em_icp_xxxx) {
ia_base_addr = (uint16_t)
EEPROM_IA_START_ICP_xxxx(hw->icp_xxxx_port_num);
+ } else if (hw->mac_type == em_82580) {
+ ia_base_addr = NVM_82580_LAN_FUNC_OFFSET(hw->bus_func);
}
for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
offset = i >> 1;
@@ -6660,7 +6668,6 @@ em_read_mac_addr(struct em_hw *hw)
case em_82546_rev_3:
case em_82571:
case em_82575:
- case em_82580:
case em_80003es2lan:
if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
hw->perm_mac_addr[5] ^= 0x01;
@@ -8674,7 +8681,7 @@ STATIC int32_t
em_get_phy_cfg_done(struct em_hw *hw)
{
int32_t timeout = PHY_CFG_TIMEOUT;
- uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+ uint32_t cfg_mask = E1000_NVM_CFG_DONE_PORT_0;
DEBUGFUNC("em_get_phy_cfg_done");
switch (hw->mac_type) {
@@ -8683,9 +8690,18 @@ em_get_phy_cfg_done(struct em_hw *hw)
break;
case em_80003es2lan:
case em_82575:
- /* Separate *_CFG_DONE_* bit for each port */
- if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
- cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1;
+ case em_82580:
+ switch (hw->bus_func) {
+ case 1:
+ cfg_mask = E1000_NVM_CFG_DONE_PORT_1;
+ break;
+ case 2:
+ cfg_mask = E1000_NVM_CFG_DONE_PORT_2;
+ break;
+ case 3:
+ cfg_mask = E1000_NVM_CFG_DONE_PORT_3;
+ break;
+ }
/* FALLTHROUGH */
case em_82571:
case em_82572:
Index: if_em_hw.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.51
diff -u -p -r1.51 if_em_hw.h
--- if_em_hw.h 2 May 2011 12:25:42 -0000 1.51
+++ if_em_hw.h 19 Sep 2011 20:22:41 -0000
@@ -949,6 +949,7 @@ struct em_ffvt_entry {
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#define E1000_MDICNFG 0x00E04 /* MDI Config - RW */
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */
@@ -1543,6 +1544,8 @@ struct em_hw {
boolean_t icp_xxxx_is_link_up;
uint32_t icp_xxxx_port_num;
struct gcu_softc * gcu;
+ uint8_t bus_func;
+ uint16_t swfw;
};
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
@@ -1590,6 +1593,7 @@ struct em_hw {
#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
+#define E1000_CTRL_DEV_RST 0x20000000 /* Device Reset */
#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to
manageability engine */
@@ -1632,6 +1636,7 @@ struct em_hw {
#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */
#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */
#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_DEV_RST_SET 0x00100000
#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */
#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */
#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
@@ -1750,6 +1755,7 @@ struct em_hw {
#define E1000_MDIC_READY 0x10000000
#define E1000_MDIC_INT_EN 0x20000000
#define E1000_MDIC_ERROR 0x40000000
+#define E1000_MDIC_DEST 0x80000000
#define E1000_KUMCTRLSTA_MASK 0x0000FFFF
#define E1000_KUMCTRLSTA_OFFSET 0x001F0000
@@ -1869,6 +1875,7 @@ struct em_hw {
#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW
bit in the FWSM */
#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates
an interrupt */
#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */
+#define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */
/* Interrupt Cause Set */
#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back
*/
@@ -1898,6 +1905,7 @@ struct em_hw {
#define E1000_ICS_DSW E1000_ICR_DSW
#define E1000_ICS_PHYINT E1000_ICR_PHYINT
#define E1000_ICS_EPRST E1000_ICR_EPRST
+#define E1000_ICS_DRSTA E1000_ICR_DRSTA
/* Interrupt Mask Set */
#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back
*/
@@ -1927,6 +1935,7 @@ struct em_hw {
#define E1000_IMS_DSW E1000_ICR_DSW
#define E1000_IMS_PHYINT E1000_ICR_PHYINT
#define E1000_IMS_EPRST E1000_ICR_EPRST
+#define E1000_IMS_DRSTA E1000_ICR_DRSTA
/* Interrupt Mask Clear */
#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back
*/
@@ -1956,6 +1965,7 @@ struct em_hw {
#define E1000_IMC_DSW E1000_ICR_DSW
#define E1000_IMC_PHYINT E1000_ICR_PHYINT
#define E1000_IMC_EPRST E1000_ICR_EPRST
+#define E1000_IMC_DRSTA E1000_ICR_DRSTA
/* Receive Control */
#define E1000_RCTL_RST 0x00000001 /* Software reset */
@@ -2030,6 +2040,8 @@ struct em_hw {
#define E1000_SWFW_PHY0_SM 0x0002
#define E1000_SWFW_PHY1_SM 0x0004
#define E1000_SWFW_MAC_CSR_SM 0x0008
+#define E1000_SWFW_PHY2_SM 0x0020
+#define E1000_SWFW_PHY3_SM 0x0040
/* Receive Descriptor */
#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */
@@ -2073,6 +2085,7 @@ struct em_hw {
#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */
+#define E1000_RXDCTL_QUEUE_ENABLE 0x2000000
/* Transmit Descriptor Control */
#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
@@ -2296,6 +2309,11 @@ struct em_host_command_info {
#define E1000_MDALIGN 4096
+#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination
*/
+#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
+#define E1000_MDICNFG_PHY_MASK 0x03E00000
+#define E1000_MDICNFG_PHY_SHIFT 21
+
/* PCI-Ex registers*/
/* PCI-Ex Control Register */
@@ -2396,8 +2414,16 @@ struct em_host_command_info {
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
-#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
-#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
+#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */
+#define E1000_NVM_CFG_DONE_PORT_2 0x100000 /* ...for third port */
+#define E1000_NVM_CFG_DONE_PORT_3 0x200000 /* ...for fourth port */
+
+#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
+
+/* Mask bits for fields in Word 0x24 of the NVM */
+#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */
+#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed external */
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_0000 0x0000
Index: if_em_osdep.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_osdep.h,v
retrieving revision 1.11
diff -u -p -r1.11 if_em_osdep.h
--- if_em_osdep.h 26 Jul 2011 14:57:57 -0000 1.11
+++ if_em_osdep.h 19 Sep 2011 20:22:41 -0000
@@ -111,6 +111,17 @@ struct em_osdep
((hw)->mac_type >= em_82543 ? E1000_##reg :
E1000_82542_##reg), \
value)
+#define EM_READ_REG(hw, reg) \
+ bus_space_read_4(((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(hw)->back)->mem_bus_space_handle,
\
+ reg)
+
+#define EM_WRITE_REG(hw, reg, value) \
+ bus_space_write_4(((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
+ ((struct em_osdep
*)(hw)->back)->mem_bus_space_handle, \
+ reg, value)
+
+
#define E1000_READ_REG_ARRAY(hw, reg, index) \
bus_space_read_4(((struct em_osdep *)(hw)->back)->mem_bus_space_tag, \
((struct em_osdep *)(hw)->back)->mem_bus_space_handle,
\