support for Intel i340/82580 in em(4)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

support for Intel i340/82580 in em(4)

Jonathan Gray
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, \