summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2012-05-17 10:45:18 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2012-05-17 10:45:18 +0000
commit2370fb952324eea256e65516082cb696c21090e1 (patch)
tree255de9a963d2e206b5793bf43d753652b3119bbd
parent827480cfbcdf0d4e90435b34906b30126a4c744b (diff)
Add support for i350 based devices, based in part on Intel code
in FreeBSD. Workaround the apparently undocumented errata where the CRC is always stripped whether asked to or not, and take the FreeBSD workaround for a known errata when clearing the vlan filter. Thanks to Jens A. Griepentrog for donating a card. ok dlg@ mikeb@
-rw-r--r--sys/dev/pci/if_em.c34
-rw-r--r--sys/dev/pci/if_em_hw.c92
-rw-r--r--sys/dev/pci/if_em_hw.h31
3 files changed, 141 insertions, 16 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
index b3b2f4bc48b..15c11cb439e 100644
--- a/sys/dev/pci/if_em.c
+++ b/sys/dev/pci/if_em.c
@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
-/* $OpenBSD: if_em.c,v 1.263 2012/05/14 10:14:44 mikeb Exp $ */
+/* $OpenBSD: if_em.c,v 1.264 2012/05/17 10:45:17 jsg Exp $ */
/* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
#include <dev/pci/if_em.h>
@@ -136,6 +136,10 @@ const struct pci_matchid em_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_SGMII },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_COPPER_DUAL },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82583V },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I350_COPPER },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I350_FIBER },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I350_SERDES },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I350_SGMII },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH8_82567V_3 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH8_IFE },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH8_IFE_G },
@@ -402,6 +406,7 @@ em_attach(struct device *parent, struct device *self, void *aux)
case em_82574:
case em_82575:
case em_82580:
+ case em_i350:
case em_ich9lan:
case em_ich10lan:
case em_80003es2lan:
@@ -469,7 +474,7 @@ em_attach(struct device *parent, struct device *self, void *aux)
}
if (sc->hw.mac_type == em_80003es2lan || sc->hw.mac_type == em_82575 ||
- sc->hw.mac_type == em_82580) {
+ sc->hw.mac_type == em_82580 || sc->hw.mac_type == em_i350) {
uint32_t reg = EM_READ_REG(&sc->hw, E1000_STATUS);
sc->hw.bus_func = (reg & E1000_STATUS_FUNC_MASK) >>
E1000_STATUS_FUNC_SHIFT;
@@ -772,6 +777,7 @@ em_init(void *arg)
case em_82575:
case em_82580:
case em_80003es2lan:
+ case em_i350:
pba = E1000_PBA_32K; /* 32K for Rx, 16K for Tx */
break;
case em_82573: /* 82573: Total Packet Buffer is 32K */
@@ -1761,7 +1767,8 @@ em_hardware_init(struct em_softc *sc)
(sc->hw.mac_type == em_82571 ||
sc->hw.mac_type == em_82572 ||
sc->hw.mac_type == em_82575 ||
- sc->hw.mac_type == em_82580)) {
+ sc->hw.mac_type == em_82580 ||
+ sc->hw.mac_type == em_i350)) {
uint16_t phy_tmp = 0;
/* Speed up time to link by disabling smart power down */
@@ -1841,7 +1848,8 @@ em_setup_interface(struct em_softc *sc)
ifp->if_capabilities = IFCAP_VLAN_MTU;
#if NVLAN > 0
- if (sc->hw.mac_type != em_82575 && sc->hw.mac_type != em_82580)
+ if (sc->hw.mac_type != em_82575 && sc->hw.mac_type != em_82580 &&
+ sc->hw.mac_type != em_i350)
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
#endif
@@ -2202,7 +2210,8 @@ em_initialize_transmit_unit(struct em_softc *sc)
/* Setup Transmit Descriptor Base Settings */
sc->txd_cmd = E1000_TXD_CMD_IFCS;
- if (sc->hw.mac_type == em_82575 || sc->hw.mac_type == em_82580) {
+ if (sc->hw.mac_type == em_82575 || sc->hw.mac_type == em_82580 ||
+ sc->hw.mac_type == em_i350) {
/* 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;
@@ -2624,6 +2633,14 @@ em_initialize_receive_unit(struct em_softc *sc)
if (sc->hw.tbi_compatibility_on == TRUE)
reg_rctl |= E1000_RCTL_SBP;
+ /*
+ * The i350 has a bug where it always strips the CRC whether
+ * asked to or not. So ask for stripped CRC here and
+ * cope in rxeof
+ */
+ if (sc->hw.mac_type == em_i350)
+ reg_rctl |= E1000_RCTL_SECRC;
+
switch (sc->rx_buffer_len) {
default:
case EM_RXBUFFER_2048:
@@ -2657,7 +2674,8 @@ em_initialize_receive_unit(struct em_softc *sc)
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) {
+ if (sc->hw.mac_type == em_82575 || sc->hw.mac_type == em_82580 ||
+ sc->hw.mac_type == em_i350) {
/* 82575/6 need to enable the RX queue */
uint32_t reg;
reg = E1000_READ_REG(&sc->hw, RXDCTL);
@@ -2859,7 +2877,9 @@ em_rxeof(struct em_softc *sc, int count)
if (desc_len < ETHER_CRC_LEN) {
len = 0;
prev_len_adj = ETHER_CRC_LEN - desc_len;
- } else
+ } else if (sc->hw.mac_type == em_i350)
+ len = desc_len;
+ else
len = desc_len - ETHER_CRC_LEN;
} else {
eop = 0;
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c
index dc45856ddef..1c6f662c5d2 100644
--- a/sys/dev/pci/if_em_hw.c
+++ b/sys/dev/pci/if_em_hw.c
@@ -31,7 +31,7 @@
*******************************************************************************/
-/* $OpenBSD: if_em_hw.c,v 1.68 2011/11/29 04:10:59 jsg Exp $ */
+/* $OpenBSD: if_em_hw.c,v 1.69 2012/05/17 10:45:17 jsg Exp $ */
/*
* if_em_hw.c Shared functions for accessing and configuring the MAC
*/
@@ -82,6 +82,7 @@ static void em_release_software_semaphore(struct em_hw *);
static int32_t em_check_downshift(struct em_hw *);
static void em_clear_vfta(struct em_hw *);
+void em_clear_vfta_i350(struct em_hw *);
static int32_t em_commit_shadow_ram(struct em_hw *);
static int32_t em_config_dsp_after_link_change(struct em_hw *, boolean_t);
static int32_t em_config_fc_after_link_up(struct em_hw *);
@@ -181,6 +182,7 @@ int32_t em_oem_bits_config_pchlan(struct em_hw *, boolean_t);
void em_power_up_serdes_link_82575(struct em_hw *);
int32_t em_get_pcs_speed_and_duplex_82575(struct em_hw *, uint16_t *,
uint16_t *);
+int32_t em_set_eee_i350(struct em_hw *);
/* IGP cable length table */
static const uint16_t
@@ -257,6 +259,7 @@ em_set_phy_type(struct em_hw *hw)
hw->phy_type = em_phy_82579;
break;
case I82580_I_PHY_ID:
+ case I350_I_PHY_ID:
hw->phy_type = em_phy_82580;
break;
case BME1000_E_PHY_ID:
@@ -514,6 +517,15 @@ em_set_mac_type(struct em_hw *hw)
hw->mac_type = em_82580;
hw->initialize_hw_bits_disable = 1;
break;
+ case E1000_DEV_ID_I350_COPPER:
+ case E1000_DEV_ID_I350_FIBER:
+ case E1000_DEV_ID_I350_SERDES:
+ case E1000_DEV_ID_I350_SGMII:
+ case E1000_DEV_ID_I350_DA4:
+ hw->mac_type = em_i350;
+ hw->initialize_hw_bits_disable = 1;
+ hw->eee_enable = 1;
+ break;
case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
@@ -587,6 +599,7 @@ em_set_mac_type(struct em_hw *hw)
case em_80003es2lan:
case em_82575:
case em_82580:
+ case em_i350:
hw->swfw_sync_present = TRUE;
/* FALLTHROUGH */
case em_82571:
@@ -623,7 +636,8 @@ em_set_media_type(struct em_hw *hw)
hw->tbi_compatibility_en = FALSE;
}
- if (hw->mac_type == em_82575 || hw->mac_type == em_82580) {
+ if (hw->mac_type == em_82575 || hw->mac_type == em_82580 ||
+ hw->mac_type == em_i350) {
hw->media_type = em_media_type_copper;
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
@@ -726,7 +740,8 @@ em_reset_hw(struct em_hw *hw)
}
/* Set the completion timeout for 82575 chips */
- if (hw->mac_type == em_82575 || hw->mac_type == em_82580) {
+ if (hw->mac_type == em_82575 || hw->mac_type == em_82580 ||
+ hw->mac_type == em_i350) {
ret_val = em_set_pciex_completion_timeout(hw);
if (ret_val) {
DEBUGOUT("PCI-E Set completion timeout has failed.\n");
@@ -956,7 +971,7 @@ em_reset_hw(struct em_hw *hw)
E1000_WRITE_REG(hw, KABGTXD, kab);
}
- if (hw->mac_type == em_82580) {
+ if (hw->mac_type == em_82580 || hw->mac_type == em_i350) {
uint32_t mdicnfg;
uint16_t nvm_data;
@@ -975,6 +990,9 @@ em_reset_hw(struct em_hw *hw)
EM_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
}
+ if (hw->mac_type == em_i350)
+ em_set_eee_i350(hw);
+
return E1000_SUCCESS;
}
@@ -1199,7 +1217,10 @@ em_init_hw(struct em_hw *hw)
hw->mac_type != em_pch2lan) {
if (hw->mac_type < em_82545_rev_3)
E1000_WRITE_REG(hw, VET, 0);
- em_clear_vfta(hw);
+ if (hw->mac_type == em_i350)
+ em_clear_vfta_i350(hw);
+ else
+ em_clear_vfta(hw);
}
/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
if (hw->mac_type == em_82542_rev2_0) {
@@ -1346,6 +1367,7 @@ em_init_hw(struct em_hw *hw)
case em_82572:
case em_82575:
case em_82580:
+ case em_i350:
case em_ich8lan:
case em_ich9lan:
case em_ich10lan:
@@ -5122,7 +5144,8 @@ em_match_gig_phy(struct em_hw *hw)
match = TRUE;
break;
case em_82580:
- if (hw->phy_id == I82580_I_PHY_ID) {
+ case em_i350:
+ if (hw->phy_id == I82580_I_PHY_ID || hw->phy_id == I350_I_PHY_ID) {
uint32_t mdic;
mdic = EM_READ_REG(hw, E1000_MDICNFG);
@@ -5253,7 +5276,7 @@ em_detect_gig_phy(struct em_hw *hw)
hw->phy_type = em_phy_gg82563;
/* Power on SGMII phy if it is disabled */
- if (hw->mac_type == em_82580) {
+ if (hw->mac_type == em_82580 || hw->mac_type == em_i350) {
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);
@@ -5395,6 +5418,7 @@ em_init_eeprom_params(struct em_hw *hw)
case em_82574:
case em_82575:
case em_82580:
+ case em_i350:
eeprom->type = em_eeprom_spi;
eeprom->opcode_bits = 8;
eeprom->delay_usec = 1;
@@ -6649,7 +6673,7 @@ 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) {
+ } else if (hw->mac_type == em_82580 || hw->mac_type == em_i350) {
ia_base_addr = NVM_82580_LAN_FUNC_OFFSET(hw->bus_func);
}
for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
@@ -6720,6 +6744,8 @@ em_init_rx_addrs(struct em_hw *hw)
rar_num -= 1;
if (hw->mac_type == em_82580)
rar_num = E1000_RAR_ENTRIES_82580;
+ if (hw->mac_type == em_i350)
+ rar_num = E1000_RAR_ENTRIES_I350;
/* Zero out the other 15 receive addresses. */
DEBUGOUT("Clearing RAR[1-15]\n");
@@ -7076,6 +7102,24 @@ em_clear_vfta(struct em_hw *hw)
}
}
+/*
+ * Due to hw errata, if the host tries to configure the VFTA register
+ * while performing queries from the BMC or DMA, then the VFTA in some
+ * cases won't be written.
+ */
+void
+em_clear_vfta_i350(struct em_hw *hw)
+{
+ uint32_t offset;
+ int i;
+
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ for (i = 0; i < 10; i++)
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+ E1000_WRITE_FLUSH(hw);
+ }
+}
+
STATIC int32_t
em_id_led_init(struct em_hw *hw)
{
@@ -7398,6 +7442,7 @@ em_get_bus_info(struct em_hw *hw)
case em_82575:
case em_82580:
case em_80003es2lan:
+ case em_i350:
hw->bus_type = em_bus_type_pci_express;
hw->bus_speed = em_bus_speed_2500;
ret_val = em_read_pcie_cap_reg(hw, PCI_EX_LINK_STATUS,
@@ -8639,6 +8684,7 @@ em_get_auto_rd_done(struct em_hw *hw)
case em_82575:
case em_82580:
case em_80003es2lan:
+ case em_i350:
case em_ich8lan:
case em_ich9lan:
case em_ich10lan:
@@ -8693,6 +8739,7 @@ em_get_phy_cfg_done(struct em_hw *hw)
case em_80003es2lan:
case em_82575:
case em_82580:
+ case em_i350:
switch (hw->bus_func) {
case 1:
cfg_mask = E1000_NVM_CFG_DONE_PORT_1;
@@ -10141,3 +10188,32 @@ em_configure_k1_ich8lan(struct em_hw *hw, boolean_t k1_enable)
out:
return ret_val;
}
+
+int32_t
+em_set_eee_i350(struct em_hw *hw)
+{
+ int32_t ret_val = E1000_SUCCESS;
+ uint32_t ipcnfg, eeer;
+
+ if ((hw->mac_type < em_i350) ||
+ (hw->media_type != em_media_type_copper))
+ goto out;
+ ipcnfg = EM_READ_REG(hw, E1000_IPCNFG);
+ eeer = EM_READ_REG(hw, E1000_EEER);
+
+ if (hw->eee_enable) {
+ ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+ eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
+ E1000_EEER_LPI_FC);
+ } else {
+ ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+ eeer &= ~(E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
+ E1000_EEER_LPI_FC);
+ }
+ EM_WRITE_REG(hw, E1000_IPCNFG, ipcnfg);
+ EM_WRITE_REG(hw, E1000_EEER, eeer);
+ EM_READ_REG(hw, E1000_IPCNFG);
+ EM_READ_REG(hw, E1000_EEER);
+out:
+ return ret_val;
+}
diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h
index bce466b9895..286dcea4840 100644
--- a/sys/dev/pci/if_em_hw.h
+++ b/sys/dev/pci/if_em_hw.h
@@ -31,7 +31,7 @@
*******************************************************************************/
-/* $OpenBSD: if_em_hw.h,v 1.52 2011/10/05 02:52:10 jsg Exp $ */
+/* $OpenBSD: if_em_hw.h,v 1.53 2012/05/17 10:45:17 jsg Exp $ */
/* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */
/* if_em_hw.h
@@ -71,6 +71,7 @@ typedef enum {
em_82574,
em_82575,
em_82580,
+ em_i350,
em_80003es2lan,
em_ich8lan,
em_ich9lan,
@@ -554,7 +555,12 @@ int32_t em_check_phy_reset_block(struct em_hw *hw);
#define E1000_DEV_ID_82580_SERDES 0x1510
#define E1000_DEV_ID_82580_SGMII 0x1511
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_I350_COPPER 0x1521
+#define E1000_DEV_ID_I350_FIBER 0x1522
+#define E1000_DEV_ID_I350_SERDES 0x1523
+#define E1000_DEV_ID_I350_SGMII 0x1524
#define E1000_DEV_ID_82576_QUAD_CU_ET2 0x1526
+#define E1000_DEV_ID_I350_DA4 0x1546
#define E1000_DEV_ID_82574L 0x10D3
#define E1000_DEV_ID_EP80579_LAN_1 0x5040
#define E1000_DEV_ID_EP80579_LAN_2 0x5044
@@ -731,6 +737,7 @@ union em_rx_desc_packet_split {
#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */
#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define E1000_RXD_STAT_STRIPCRC 0x1000 /* CRC has been stripped */
#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
@@ -1155,6 +1162,15 @@ struct em_ffvt_entry {
#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */
#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
+
+/* Energy Efficient Ethernet "EEE" registers */
+#define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */
+#define E1000_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
+#define E1000_EEER 0x0E30 /* Energy Efficient Ethernet "EEE" */
+#define E1000_EEE_SU 0x0E34 /* EEE Setup */
+#define E1000_TLPIC 0x4148 /* EEE Tx LPI Count - TLPIC */
+#define E1000_RLPIC 0x414C /* EEE Rx LPI Count - RLPIC */
+
/* Register Set (82542)
*
* Some of the 82542 registers are located at different offsets than they are
@@ -1546,6 +1562,7 @@ struct em_hw {
struct gcu_softc * gcu;
uint8_t bus_func;
uint16_t swfw;
+ boolean_t eee_enable;
};
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
@@ -1737,6 +1754,7 @@ struct em_hw {
#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+#define E1000_CTRL_EXT_EXT_VLAN 0x04000000
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
@@ -2314,6 +2332,17 @@ struct em_host_command_info {
#define E1000_MDICNFG_PHY_MASK 0x03E00000
#define E1000_MDICNFG_PHY_SHIFT 21
+/* I350 EEE defines */
+#define E1000_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */
+#define E1000_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */
+#define E1000_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */
+#define E1000_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */
+#define E1000_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */
+/* EEE status */
+#define E1000_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
+#define E1000_EEER_RX_LPI_STATUS 0x40000000 /* Rx in LPI state */
+#define E1000_EEER_TX_LPI_STATUS 0x80000000 /* Tx in LPI state */
+
/* PCI-Ex registers*/
/* PCI-Ex Control Register */