summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authormsaitoh <msaitoh@NetBSD.org>2010-02-16 15:17:17 +0000
committermsaitoh <msaitoh@NetBSD.org>2010-02-16 15:17:17 +0000
commitb601f7daf06efdff26253ea70075ffd76afe17bc (patch)
treee4569b42190a09be5704a4a5531d28c646fb8cb8 /sys/dev/pci
parentce91bef2c68eb2ce0f4d06f152175da96324a750 (diff)
Add support for 82575, 82576 and 82580(ER).
- Apply the patch for 82575 from Wolfgang Stukenbrock (PR#42422). We use only one RX ring and with the legacy mode. - Add support for 82576. - Partial support for 82580. - Partial support for the serdes systems.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/if_wm.c583
-rw-r--r--sys/dev/pci/if_wmreg.h128
-rw-r--r--sys/dev/pci/if_wmvar.h8
3 files changed, 606 insertions, 113 deletions
diff --git a/sys/dev/pci/if_wm.c b/sys/dev/pci/if_wm.c
index 11e978f6739..22306ed926b 100644
--- a/sys/dev/pci/if_wm.c
+++ b/sys/dev/pci/if_wm.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.198 2010/02/16 10:06:19 msaitoh Exp $ */
+/* $NetBSD: if_wm.c,v 1.199 2010/02/16 15:17:17 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.198 2010/02/16 10:06:19 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.199 2010/02/16 15:17:17 msaitoh Exp $");
#include "rnd.h"
@@ -231,6 +231,13 @@ struct wm_rxsoft {
#define WM_LINKUP_TIMEOUT 50
+static uint16_t swfwphysem[] = {
+ SWFW_PHY0_SM,
+ SWFW_PHY1_SM,
+ SWFW_PHY2_SM,
+ SWFW_PHY3_SM
+};
+
/*
* Software state per device.
*/
@@ -243,31 +250,33 @@ struct wm_softc {
bus_space_tag_t sc_flasht; /* flash registers space tag */
bus_space_handle_t sc_flashh; /* flash registers space handle */
bus_dma_tag_t sc_dmat; /* bus DMA tag */
+ bus_dmamap_t sc_cddmamap; /* control data DMA map */
+#define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
+
struct ethercom sc_ethercom; /* ethernet common data */
+ struct mii_data sc_mii; /* MII/media information */
+
pci_chipset_tag_t sc_pc;
pcitag_t sc_pcitag;
+ int sc_bus_speed; /* PCI/PCIX bus speed */
+ int sc_pcixe_capoff; /* PCI[Xe] capability register offset */
wm_chip_type sc_type; /* MAC type */
int sc_rev; /* MAC revision */
wm_phy_type sc_phytype; /* PHY type */
+ int sc_funcid; /* unit number of the chip (0 to 3) */
int sc_flags; /* flags; see below */
int sc_if_flags; /* last if_flags */
- int sc_bus_speed; /* PCI/PCIX bus speed */
- int sc_pcix_offset; /* PCIX capability register offset */
int sc_flowflags; /* 802.3x flow control flags */
+ int sc_align_tweak;
void *sc_ih; /* interrupt cookie */
-
- int sc_ee_addrbits; /* EEPROM address bits */
-
- struct mii_data sc_mii; /* MII/media information */
-
callout_t sc_tick_ch; /* tick callout */
- bus_dmamap_t sc_cddmamap; /* control data DMA map */
-#define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
-
- int sc_align_tweak;
+ int sc_ee_addrbits; /* EEPROM address bits */
+ int sc_ich8_flash_base;
+ int sc_ich8_flash_bank_size;
+ int sc_nvm_k1_enabled;
/*
* Software state for the transmit and receive descriptors.
@@ -364,9 +373,6 @@ struct wm_softc {
#if NRND > 0
rndsource_element_t rnd_source; /* random source */
#endif
- int sc_ich8_flash_base;
- int sc_ich8_flash_bank_size;
- int sc_nvm_k1_enabled;
};
#define WM_RXCHAIN_RESET(sc) \
@@ -523,6 +529,8 @@ static int wm_gmii_bm_readreg(device_t, int, int);
static void wm_gmii_bm_writereg(device_t, int, int, int);
static int wm_gmii_hv_readreg(device_t, int, int);
static void wm_gmii_hv_writereg(device_t, int, int, int);
+static int wm_sgmii_readreg(device_t, int, int);
+static void wm_sgmii_writereg(device_t, int, int, int);
static void wm_gmii_statchg(device_t);
@@ -533,7 +541,7 @@ static void wm_gmii_mediastatus(struct ifnet *, struct ifmediareq *);
static int wm_kmrn_readreg(struct wm_softc *, int);
static void wm_kmrn_writereg(struct wm_softc *, int, int);
-static void wm_set_spiaddrsize(struct wm_softc *);
+static void wm_set_spiaddrbits(struct wm_softc *);
static int wm_match(device_t, cfdata_t, void *);
static void wm_attach(device_t, device_t, void *);
static int wm_is_onboard_nvm_eeprom(struct wm_softc *);
@@ -566,6 +574,8 @@ static int wm_check_for_link(struct wm_softc *);
static void wm_hv_phy_workaround_ich8lan(struct wm_softc *);
static void wm_k1_gig_workaround_hv(struct wm_softc *, int);
static void wm_configure_k1_ich8lan(struct wm_softc *, int);
+static void wm_set_pcie_completion_timeout(struct wm_softc *);
+static void wm_reset_init_script_82575(struct wm_softc *);
CFATTACH_DECL_NEW(wm, sizeof(struct wm_softc),
wm_match, wm_attach, NULL, NULL);
@@ -882,6 +892,72 @@ static const struct wm_product {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCH_D_DC,
"PCH LAN (82578DC) Controller",
WM_T_PCH, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575EB_COPPER,
+ "82575EB dual-1000baseT Ethernet",
+ WM_T_82575, WMP_F_1000T },
+#if 0
+ /*
+ * not sure if WMP_F_1000X or WMP_F_SERDES - we do not have it - so
+ * disabled for now ...
+ */
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575EB_FIBER_SERDES,
+ "82575EB dual-1000baseX Ethernet (SERDES)",
+ WM_T_82575, WMP_F_SERDES },
+#endif
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER,
+ "82575GB quad-1000baseT Ethernet",
+ WM_T_82575, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575GB_QUAD_COPPER_PM,
+ "82575GB quad-1000baseT Ethernet (PM)",
+ WM_T_82575, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_COPPER,
+ "82576 1000BaseT Ethernet",
+ WM_T_82576, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_FIBER,
+ "82576 1000BaseX Ethernet",
+ WM_T_82576, WMP_F_1000X },
+#if 0
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_SERDES,
+ "82576 gigabit Ethernet (SERDES)",
+ WM_T_82576, WMP_F_SERDES },
+#endif
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_QUAD_COPPER,
+ "82576 quad-1000BaseT Ethernet",
+ WM_T_82576, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_NS,
+ "82576 gigabit Ethernet",
+ WM_T_82576, WMP_F_1000T },
+#if 0
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_NS_SERDES,
+ "82576 gigabit Ethernet (SERDES)",
+ WM_T_82576, WMP_F_SERDES },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82576_SERDES_QUAD,
+ "82576 quad-gigabit Ethernet (SERDES)",
+ WM_T_82576, WMP_F_SERDES },
+#endif
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_COPPER,
+ "82580 1000BaseT Ethernet",
+ WM_T_82580, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_FIBER,
+ "82580 1000BaseX Ethernet",
+ WM_T_82580, WMP_F_1000X },
+#if 0
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_SERDES,
+ "82580 1000BaseT Ethernet (SERDES)",
+ WM_T_82580, WMP_F_SERDES },
+#endif
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_SGMII,
+ "82580 gigabit Ethernet (SGMII)",
+ WM_T_82580, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_COPPER_DUAL,
+ "82580 dual-1000BaseT Ethernet",
+ WM_T_82580, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_ER,
+ "82580 1000BaseT Ethernet",
+ WM_T_82580ER, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_ER_DUAL,
+ "82580 dual-1000BaseT Ethernet",
+ WM_T_82580ER, WMP_F_1000T },
{ 0, 0,
NULL,
0, 0 },
@@ -910,6 +986,28 @@ wm_io_write(struct wm_softc *sc, int reg, uint32_t val)
}
static inline void
+wm_82575_write_8bit_ctlr_reg(struct wm_softc *sc, uint32_t reg, uint32_t off,
+ uint32_t data)
+{
+ uint32_t regval;
+ int i;
+
+ regval = (data & SCTL_CTL_DATA_MASK) | (off << SCTL_CTL_ADDR_SHIFT);
+
+ CSR_WRITE(sc, reg, regval);
+
+ for (i = 0; i < SCTL_CTL_POLL_TIMEOUT; i++) {
+ delay(5);
+ if (CSR_READ(sc, reg) & SCTL_CTL_READY)
+ break;
+ }
+ if (i == SCTL_CTL_POLL_TIMEOUT) {
+ aprint_error("%s: WARNING: i82575 reg 0x%08x setup did not indicate ready\n",
+ device_xname(sc->sc_dev), reg);
+ }
+}
+
+static inline void
wm_set_dma_addr(volatile wiseman_addr_t *wa, bus_addr_t v)
{
wa->wa_low = htole32(v & 0xffffffffU);
@@ -920,7 +1018,7 @@ wm_set_dma_addr(volatile wiseman_addr_t *wa, bus_addr_t v)
}
static void
-wm_set_spiaddrsize(struct wm_softc *sc)
+wm_set_spiaddrbits(struct wm_softc *sc)
{
uint32_t reg;
@@ -1010,6 +1108,10 @@ wm_attach(device_t parent, device_t self, void *aux)
sc->sc_type = WM_T_82542_2_0;
}
+ if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
+ || (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER))
+ sc->sc_flags |= WM_F_NEWQUEUE;
+
/* Set device properties (mactype) */
dict = device_properties(sc->sc_dev);
prop_dictionary_set_uint32(dict, "mactype", sc->sc_type);
@@ -1110,6 +1212,17 @@ wm_attach(device_t parent, device_t self, void *aux)
aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
/*
+ * Check the function ID (unit number of the chip).
+ */
+ if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3)
+ || (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003)
+ || (sc->sc_type == WM_T_82575))
+ sc->sc_funcid = (CSR_READ(sc, WMREG_STATUS)
+ >> STATUS_FUNCID_SHIFT) & STATUS_FUNCID_MASK;
+ else
+ sc->sc_funcid = 0;
+
+ /*
* Determine a few things about the bus we're connected to.
*/
if (sc->sc_type < WM_T_82543) {
@@ -1135,8 +1248,15 @@ wm_attach(device_t parent, device_t self, void *aux)
sc->sc_flags |= WM_F_PCIE;
if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9)
&& (sc->sc_type != WM_T_ICH10)
- && (sc->sc_type != WM_T_PCH))
+ && (sc->sc_type != WM_T_PCH)) {
sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
+ /* ICH* and PCH have no PCIe capability registers */
+ if (pci_get_capability(pa->pa_pc, pa->pa_tag,
+ PCI_CAP_PCIEXPRESS, &sc->sc_pcixe_capoff,
+ NULL) == 0)
+ aprint_error_dev(sc->sc_dev,
+ "unable to find PCIe capability\n");
+ }
aprint_verbose_dev(sc->sc_dev, "PCI-Express bus\n");
} else {
reg = CSR_READ(sc, WMREG_STATUS);
@@ -1147,7 +1267,7 @@ wm_attach(device_t parent, device_t self, void *aux)
sc->sc_flags |= WM_F_PCIX;
if (pci_get_capability(pa->pa_pc, pa->pa_tag,
- PCI_CAP_PCIX, &sc->sc_pcix_offset, NULL) == 0)
+ PCI_CAP_PCIX, &sc->sc_pcixe_capoff, NULL) == 0)
aprint_error_dev(sc->sc_dev,
"unable to find PCIX capability\n");
else if (sc->sc_type != WM_T_82545_3 &&
@@ -1158,9 +1278,9 @@ wm_attach(device_t parent, device_t self, void *aux)
* incorrectly.
*/
pcix_cmd = pci_conf_read(pa->pa_pc, pa->pa_tag,
- sc->sc_pcix_offset + PCI_PCIX_CMD);
+ sc->sc_pcixe_capoff + PCI_PCIX_CMD);
pcix_sts = pci_conf_read(pa->pa_pc, pa->pa_tag,
- sc->sc_pcix_offset + PCI_PCIX_STATUS);
+ sc->sc_pcixe_capoff + PCI_PCIX_STATUS);
bytecnt =
(pcix_cmd & PCI_PCIX_CMD_BYTECNT_MASK) >>
@@ -1176,7 +1296,7 @@ wm_attach(device_t parent, device_t self, void *aux)
~PCI_PCIX_CMD_BYTECNT_MASK) |
(maxb << PCI_PCIX_CMD_BYTECNT_SHIFT);
pci_conf_write(pa->pa_pc, pa->pa_tag,
- sc->sc_pcix_offset + PCI_PCIX_CMD,
+ sc->sc_pcixe_capoff + PCI_PCIX_CMD,
pcix_cmd);
}
}
@@ -1348,7 +1468,7 @@ wm_attach(device_t parent, device_t self, void *aux)
reg = CSR_READ(sc, WMREG_EECD);
if (reg & EECD_EE_TYPE) {
/* SPI */
- wm_set_spiaddrsize(sc);
+ wm_set_spiaddrbits(sc);
} else
/* Microwire */
sc->sc_ee_addrbits = (reg & EECD_EE_ABITS) ? 8 : 6;
@@ -1357,7 +1477,7 @@ wm_attach(device_t parent, device_t self, void *aux)
case WM_T_82571:
case WM_T_82572:
/* SPI */
- wm_set_spiaddrsize(sc);
+ wm_set_spiaddrbits(sc);
sc->sc_flags |= WM_F_EEPROM_HANDSHAKE;
break;
case WM_T_82573:
@@ -1367,25 +1487,21 @@ wm_attach(device_t parent, device_t self, void *aux)
sc->sc_flags |= WM_F_EEPROM_FLASH;
else {
/* SPI */
- wm_set_spiaddrsize(sc);
+ wm_set_spiaddrbits(sc);
}
sc->sc_flags |= WM_F_EEPROM_EERDEEWR;
break;
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
case WM_T_80003:
/* SPI */
- wm_set_spiaddrsize(sc);
+ wm_set_spiaddrbits(sc);
sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_SWFW_SYNC;
break;
case WM_T_ICH8:
case WM_T_ICH9:
- /* Check whether EEPROM is present or not */
- if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
- /* Not found */
- aprint_error_dev(sc->sc_dev,
- "EEPROM PRESENT bit isn't set\n");
- sc->sc_flags |= WM_F_EEPROM_INVALID;
- }
- /* FALLTHROUGH */
case WM_T_ICH10:
case WM_T_PCH:
/* FLASH */
@@ -1400,10 +1516,10 @@ wm_attach(device_t parent, device_t self, void *aux)
reg = ICH8_FLASH_READ32(sc, ICH_FLASH_GFPREG);
sc->sc_ich8_flash_base = (reg & ICH_GFPREG_BASE_MASK) *
ICH_FLASH_SECTOR_SIZE;
- sc->sc_ich8_flash_bank_size =
- ((reg >> 16) & ICH_GFPREG_BASE_MASK) + 1;
+ sc->sc_ich8_flash_bank_size =
+ ((reg >> 16) & ICH_GFPREG_BASE_MASK) + 1;
sc->sc_ich8_flash_bank_size -=
- (reg & ICH_GFPREG_BASE_MASK);
+ (reg & ICH_GFPREG_BASE_MASK);
sc->sc_ich8_flash_bank_size *= ICH_FLASH_SECTOR_SIZE;
sc->sc_ich8_flash_bank_size /= 2 * sizeof(uint16_t);
break;
@@ -1475,9 +1591,10 @@ wm_attach(device_t parent, device_t self, void *aux)
* Toggle the LSB of the MAC address on the second port
* of the dual port controller.
*/
- if (sc->sc_type == WM_T_82546 || sc->sc_type == WM_T_82546_3
- || sc->sc_type == WM_T_82571 || sc->sc_type == WM_T_80003) {
- if ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1)
+ if ((sc->sc_type == WM_T_82546) || (sc->sc_type == WM_T_82546_3)
+ || (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003)
+ || (sc->sc_type == WM_T_82575)) {
+ if (sc->sc_funcid == 1)
enaddr[5] ^= 1;
}
@@ -1588,7 +1705,7 @@ wm_attach(device_t parent, device_t self, void *aux)
}
/*
- * Determine if we're TBI or GMII mode, and initialize the
+ * Determine if we're TBI,GMII or SGMII mode, and initialize the
* media structures accordingly.
*/
if (sc->sc_type == WM_T_ICH8 || sc->sc_type == WM_T_ICH9
@@ -1604,10 +1721,41 @@ wm_attach(device_t parent, device_t self, void *aux)
"WARNING: TBIMODE set on 1000BASE-T product!\n");
wm_tbi_mediainit(sc);
} else {
- if (wmp->wmp_flags & WMP_F_1000X)
- aprint_error_dev(sc->sc_dev,
- "WARNING: TBIMODE clear on 1000BASE-X product!\n");
- wm_gmii_mediainit(sc, wmp->wmp_product);
+ switch (sc->sc_type) {
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
+ reg = CSR_READ(sc, WMREG_CTRL_EXT);
+ switch (reg & CTRL_EXT_LINK_MODE_MASK) {
+ case CTRL_EXT_LINK_MODE_SGMII:
+ aprint_verbose_dev(sc->sc_dev, "SGMII\n");
+ sc->sc_flags |= WM_F_SGMII;
+ CSR_WRITE(sc, WMREG_CTRL_EXT,
+ reg | CTRL_EXT_I2C_ENA);
+ wm_gmii_mediainit(sc, wmp->wmp_product);
+ break;
+ case CTRL_EXT_LINK_MODE_1000KX:
+ case CTRL_EXT_LINK_MODE_PCIE_SERDES:
+ aprint_verbose_dev(sc->sc_dev, "1000KX or SERDES\n");
+ CSR_WRITE(sc, WMREG_CTRL_EXT,
+ reg | CTRL_EXT_I2C_ENA);
+ panic("not supported yet\n");
+ break;
+ case CTRL_EXT_LINK_MODE_GMII:
+ default:
+ CSR_WRITE(sc, WMREG_CTRL_EXT,
+ reg & ~CTRL_EXT_I2C_ENA);
+ wm_gmii_mediainit(sc, wmp->wmp_product);
+ break;
+ }
+ break;
+ default:
+ if (wmp->wmp_flags & WMP_F_1000X)
+ aprint_error_dev(sc->sc_dev,
+ "WARNING: TBIMODE clear on 1000BASE-X product!\n");
+ wm_gmii_mediainit(sc, wmp->wmp_product);
+ }
}
ifp = &sc->sc_ethercom.ec_if;
@@ -1634,6 +1782,10 @@ wm_attach(device_t parent, device_t self, void *aux)
case WM_T_82571:
case WM_T_82572:
case WM_T_82574:
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
case WM_T_80003:
case WM_T_ICH9:
case WM_T_ICH10:
@@ -3108,7 +3260,7 @@ static void
wm_reset(struct wm_softc *sc)
{
int phy_reset = 0;
- uint32_t reg, func, mask;
+ uint32_t reg, mask;
int i;
/*
@@ -3129,9 +3281,17 @@ wm_reset(struct wm_softc *sc)
break;
case WM_T_82571:
case WM_T_82572:
+ case WM_T_82575: /* XXX need special handing for jumbo frames */
case WM_T_80003:
sc->sc_pba = PBA_32K;
break;
+ case WM_T_82580:
+ case WM_T_82580ER:
+ sc->sc_pba = PBA_35K;
+ break;
+ case WM_T_82576:
+ sc->sc_pba = PBA_64K;
+ break;
case WM_T_82573:
sc->sc_pba = PBA_12K;
break;
@@ -3155,6 +3315,7 @@ wm_reset(struct wm_softc *sc)
}
CSR_WRITE(sc, WMREG_PBA, sc->sc_pba);
+ /* Prevent the PCI-E bus from sticking */
if (sc->sc_flags & WM_F_PCIE) {
int timeout = 800;
@@ -3168,14 +3329,19 @@ wm_reset(struct wm_softc *sc)
}
}
- /* clear interrupt */
+ /* Set the completion timeout for interface */
+ if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576))
+ wm_set_pcie_completion_timeout(sc);
+
+ /* Clear interrupt */
CSR_WRITE(sc, WMREG_IMC, 0xffffffffU);
/* Stop the transmit and receive processes. */
CSR_WRITE(sc, WMREG_RCTL, 0);
CSR_WRITE(sc, WMREG_TCTL, TCTL_PSP);
+ sc->sc_rctl &= ~RCTL_EN;
- /* set_tbi_sbp_82543() */
+ /* XXX set_tbi_sbp_82543() */
delay(10*1000);
@@ -3241,8 +3407,7 @@ wm_reset(struct wm_softc *sc)
CSR_WRITE(sc, WMREG_CTRL_SHADOW, CTRL_RST);
break;
case WM_T_80003:
- func = (CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1;
- mask = func ? SWFW_PHY1_SM : SWFW_PHY0_SM;
+ mask = swfwphysem[sc->sc_funcid];
reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST;
wm_get_swfw_semaphore(sc, mask);
CSR_WRITE(sc, WMREG_CTRL, reg);
@@ -3280,6 +3445,8 @@ wm_reset(struct wm_softc *sc)
case WM_T_82572:
case WM_T_82573:
case WM_T_82574:
+ case WM_T_82575:
+ case WM_T_82576:
case WM_T_82583:
default:
/* Everything else can safely use the documented method. */
@@ -3336,6 +3503,8 @@ wm_reset(struct wm_softc *sc)
|| (sc->sc_type == WM_T_82583))
delay(25*1000);
break;
+ case WM_T_82575:
+ case WM_T_82576:
case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
@@ -3350,6 +3519,28 @@ wm_reset(struct wm_softc *sc)
panic("%s: unknown type\n", __func__);
}
+ /* Check whether EEPROM is present or not */
+ switch (sc->sc_type) {
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_ICH8:
+ case WM_T_ICH9:
+ if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
+ /* Not found */
+ sc->sc_flags |= WM_F_EEPROM_INVALID;
+ if (sc->sc_type == WM_T_82575) /* 82575 only */
+ wm_reset_init_script_82575(sc);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Clear any pending interrupt events. */
+ CSR_WRITE(sc, WMREG_IMC, 0xffffffffU);
+ reg = CSR_READ(sc, WMREG_ICR);
+
/* reload sc_ctrl */
sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
@@ -3364,18 +3555,10 @@ wm_reset(struct wm_softc *sc)
if (sc->sc_type == WM_T_PCH)
CSR_WRITE(sc, WMREG_CRC_OFFSET, 0x65656565);
-#if 0
- for (i = 0; i < 1000; i++) {
- if ((CSR_READ(sc, WMREG_CTRL) & CTRL_RST) == 0) {
- return;
- }
- delay(20);
- }
+ if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
+ CSR_WRITE(sc, WMREG_WUC, 0);
- if (CSR_READ(sc, WMREG_CTRL) & CTRL_RST)
- log(LOG_ERR, "%s: reset failed to complete\n",
- device_xname(sc->sc_dev));
-#endif
+ /* XXX need special handling for 82580 */
}
/*
@@ -3471,10 +3654,16 @@ wm_init(struct ifnet *ifp)
CSR_WRITE(sc, WMREG_TIDV, 375); /* ITR / 4 */
CSR_WRITE(sc, WMREG_TADV, 375); /* should be same */
- CSR_WRITE(sc, WMREG_TXDCTL, TXDCTL_PTHRESH(0) |
- TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
- CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_PTHRESH(0) |
- RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1));
+ if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
+ CSR_WRITE(sc, WMREG_TXDCTL, TXDCTL_QUEUE_ENABLE
+ | TXDCTL_PTHRESH(0) | TXDCTL_HTHRESH(0)
+ | TXDCTL_WTHRESH(0));
+ else {
+ CSR_WRITE(sc, WMREG_TXDCTL, TXDCTL_PTHRESH(0) |
+ TXDCTL_HTHRESH(0) | TXDCTL_WTHRESH(0));
+ CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_PTHRESH(0) |
+ RXDCTL_HTHRESH(0) | RXDCTL_WTHRESH(1));
+ }
}
CSR_WRITE(sc, WMREG_TQSA_LO, 0);
CSR_WRITE(sc, WMREG_TQSA_HI, 0);
@@ -3508,10 +3697,21 @@ wm_init(struct ifnet *ifp)
CSR_WRITE(sc, WMREG_RDBAH, WM_CDRXADDR_HI(sc, 0));
CSR_WRITE(sc, WMREG_RDBAL, WM_CDRXADDR_LO(sc, 0));
CSR_WRITE(sc, WMREG_RDLEN, sizeof(sc->sc_rxdescs));
- CSR_WRITE(sc, WMREG_RDH, 0);
- CSR_WRITE(sc, WMREG_RDT, 0);
- CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD); /* ITR/4 */
- CSR_WRITE(sc, WMREG_RADV, 375); /* MUST be same */
+ if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
+ CSR_WRITE(sc, WMREG_EITR(0), 450);
+ if (MCLBYTES & ((1 << SRRCTL_BSIZEPKT_SHIFT) - 1))
+ panic("%s: MCLBYTES %d unsupported for i2575 or higher\n", __func__, MCLBYTES);
+ CSR_WRITE(sc, WMREG_SRRCTL, SRRCTL_DESCTYPE_LEGACY
+ | (MCLBYTES >> SRRCTL_BSIZEPKT_SHIFT));
+ CSR_WRITE(sc, WMREG_RXDCTL, RXDCTL_QUEUE_ENABLE
+ | RXDCTL_PTHRESH(16) | RXDCTL_HTHRESH(8)
+ | RXDCTL_WTHRESH(1));
+ } else {
+ CSR_WRITE(sc, WMREG_RDH, 0);
+ CSR_WRITE(sc, WMREG_RDT, 0);
+ CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD); /* ITR/4 */
+ CSR_WRITE(sc, WMREG_RADV, 375); /* MUST be same */
+ }
}
for (i = 0; i < WM_NRXDESC; i++) {
rxs = &sc->sc_rxsoft[i];
@@ -3527,8 +3727,10 @@ wm_init(struct ifnet *ifp)
wm_rxdrain(sc);
goto out;
}
- } else
- WM_INIT_RXDESC(sc, i);
+ } else {
+ if ((sc->sc_flags & WM_F_NEWQUEUE) == 0)
+ WM_INIT_RXDESC(sc, i);
+ }
}
sc->sc_rxptr = 0;
sc->sc_rxdiscard = 0;
@@ -3720,8 +3922,11 @@ wm_init(struct ifnet *ifp)
| RCTL_MO(sc->sc_mchash_type);
if (((sc->sc_ethercom.ec_capabilities & ETHERCAP_JUMBO_MTU) != 0)
- && (ifp->if_mtu > ETHERMTU))
- sc->sc_rctl |= RCTL_LPE;
+ && (ifp->if_mtu > ETHERMTU)) {
+ sc->sc_rctl |= RCTL_LPE;
+ if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
+ CSR_WRITE(sc, WMREG_RLPML, ETHER_MAX_LEN_JUMBO);
+ }
if (MCLBYTES == 2048) {
sc->sc_rctl |= RCTL_2k;
@@ -3748,6 +3953,11 @@ wm_init(struct ifnet *ifp)
/* Set the receive filter. */
wm_set_filter(sc);
+ /* On 575 and later set RDT only if RX enabled... */
+ if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
+ for (i = 0; i < WM_NRXDESC; i++)
+ WM_INIT_RXDESC(sc, i);
+
/* Start the one second link check clock. */
callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);
@@ -3815,6 +4025,7 @@ wm_stop(struct ifnet *ifp, int disable)
/* Stop the transmit and receive processes. */
CSR_WRITE(sc, WMREG_TCTL, 0);
CSR_WRITE(sc, WMREG_RCTL, 0);
+ sc->sc_rctl &= ~RCTL_EN;
/*
* Clear the interrupt mask to ensure the device cannot assert its
@@ -3841,6 +4052,11 @@ wm_stop(struct ifnet *ifp, int disable)
if (disable)
wm_rxdrain(sc);
+
+#if 0 /* notyet */
+ if (sc->sc_type >= WM_T_82544)
+ CSR_WRITE(sc, WMREG_WUC, 0);
+#endif
}
void
@@ -3855,6 +4071,8 @@ wm_get_auto_rd_done(struct wm_softc *sc)
case WM_T_82573:
case WM_T_82574:
case WM_T_82583:
+ case WM_T_82575:
+ case WM_T_82576:
case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
@@ -3907,7 +4125,6 @@ wm_lan_init_done(struct wm_softc *sc)
void
wm_get_cfg_done(struct wm_softc *sc)
{
- int func = 0;
int mask;
uint32_t reg;
int i;
@@ -3938,12 +4155,10 @@ wm_get_cfg_done(struct wm_softc *sc)
case WM_T_80003:
case WM_T_82571:
case WM_T_82572:
- if (sc->sc_type == WM_T_80003)
- func = (CSR_READ(sc, WMREG_STATUS)
- >> STATUS_FUNCID_SHIFT) & 1;
- else
- func = 0; /* XXX Is it true for 82571? */
- mask = (func == 1) ? EEMNGCTL_CFGDONE_1 : EEMNGCTL_CFGDONE_0;
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ mask = EEMNGCTL_CFGDONE_0 << sc->sc_funcid;
for (i = 0; i < WM_PHY_CFG_TIMEOUT; i++) {
if (CSR_READ(sc, WMREG_EEMNGCTL) & mask)
break;
@@ -4367,7 +4582,11 @@ wm_add_rxbuf(struct wm_softc *sc, int idx)
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
- WM_INIT_RXDESC(sc, idx);
+ if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
+ if ((sc->sc_rctl & RCTL_EN) != 0)
+ WM_INIT_RXDESC(sc, idx);
+ } else
+ WM_INIT_RXDESC(sc, idx);
return 0;
}
@@ -4826,7 +5045,6 @@ static void
wm_gmii_reset(struct wm_softc *sc)
{
uint32_t reg;
- int func = 0; /* XXX gcc */
int rv;
/* get phy semaphore */
@@ -4839,10 +5057,12 @@ wm_gmii_reset(struct wm_softc *sc)
/* XXX should get sw semaphore, too */
rv = wm_get_swsm_semaphore(sc);
break;
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
case WM_T_80003:
- func = (CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1;
- rv = wm_get_swfw_semaphore(sc,
- func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ rv = wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]);
break;
case WM_T_ICH8:
case WM_T_ICH9:
@@ -4906,6 +5126,10 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_82572:
case WM_T_82573:
case WM_T_82574:
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
case WM_T_82583:
case WM_T_80003:
/* generic reset */
@@ -4948,8 +5172,12 @@ wm_gmii_reset(struct wm_softc *sc)
/* XXX sould put sw semaphore, too */
wm_put_swsm_semaphore(sc);
break;
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
case WM_T_80003:
- wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]);
break;
case WM_T_ICH8:
case WM_T_ICH9:
@@ -4983,6 +5211,10 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_82572:
case WM_T_82573:
case WM_T_82574:
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ case WM_T_82580ER:
case WM_T_82583:
case WM_T_80003:
/* null */
@@ -5088,7 +5320,10 @@ wm_gmii_mediainit(struct wm_softc *sc, pci_product_id_t prodid)
sc->sc_mii.mii_writereg = wm_gmii_bm_writereg;
break;
default:
- if (sc->sc_type >= WM_T_80003) {
+ if ((sc->sc_flags & WM_F_SGMII) != 0) {
+ sc->sc_mii.mii_readreg = wm_sgmii_readreg;
+ sc->sc_mii.mii_writereg = wm_sgmii_writereg;
+ } else if (sc->sc_type >= WM_T_80003) {
sc->sc_mii.mii_readreg = wm_gmii_i80003_readreg;
sc->sc_mii.mii_writereg = wm_gmii_i80003_writereg;
} else if (sc->sc_type >= WM_T_82544) {
@@ -5378,13 +5613,14 @@ static int
wm_gmii_i80003_readreg(device_t self, int phy, int reg)
{
struct wm_softc *sc = device_private(self);
- int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+ int sem;
int rv;
if (phy != 1) /* only one PHY on kumeran bus */
return 0;
- if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+ sem = swfwphysem[sc->sc_funcid];
+ if (wm_get_swfw_semaphore(sc, sem)) {
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
__func__);
return 0;
@@ -5402,7 +5638,7 @@ wm_gmii_i80003_readreg(device_t self, int phy, int reg)
rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
delay(200);
- wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ wm_put_swfw_semaphore(sc, sem);
return rv;
}
@@ -5417,12 +5653,13 @@ static void
wm_gmii_i80003_writereg(device_t self, int phy, int reg, int val)
{
struct wm_softc *sc = device_private(self);
- int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+ int sem;
if (phy != 1) /* only one PHY on kumeran bus */
return;
- if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+ sem = swfwphysem[sc->sc_funcid];
+ if (wm_get_swfw_semaphore(sc, sem)) {
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
__func__);
return;
@@ -5440,7 +5677,7 @@ wm_gmii_i80003_writereg(device_t self, int phy, int reg, int val)
wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
delay(200);
- wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ wm_put_swfw_semaphore(sc, sem);
}
/*
@@ -5454,10 +5691,11 @@ static int
wm_gmii_bm_readreg(device_t self, int phy, int reg)
{
struct wm_softc *sc = device_private(self);
- int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+ int sem;
int rv;
- if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+ sem = swfwphysem[sc->sc_funcid];
+ if (wm_get_swfw_semaphore(sc, sem)) {
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
__func__);
return 0;
@@ -5474,7 +5712,7 @@ wm_gmii_bm_readreg(device_t self, int phy, int reg)
}
rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
- wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ wm_put_swfw_semaphore(sc, sem);
return rv;
}
@@ -5489,9 +5727,10 @@ static void
wm_gmii_bm_writereg(device_t self, int phy, int reg, int val)
{
struct wm_softc *sc = device_private(self);
- int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+ int sem;
- if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+ sem = swfwphysem[sc->sc_funcid];
+ if (wm_get_swfw_semaphore(sc, sem)) {
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
__func__);
return;
@@ -5508,7 +5747,7 @@ wm_gmii_bm_writereg(device_t self, int phy, int reg, int val)
}
wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
- wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ wm_put_swfw_semaphore(sc, sem);
}
static void
@@ -5659,6 +5898,89 @@ wm_gmii_hv_writereg(device_t self, int phy, int reg, int val)
}
/*
+ * wm_gmii_hv_readreg: [mii interface function]
+ *
+ * Read a PHY register on the kumeran
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static int
+wm_sgmii_readreg(device_t self, int phy, int reg)
+{
+ struct wm_softc *sc = device_private(self);
+ uint32_t i2ccmd;
+ int i, rv;
+
+ if (wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid])) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+ __func__);
+ return 0;
+ }
+
+ i2ccmd = (reg << I2CCMD_REG_ADDR_SHIFT)
+ | (phy << I2CCMD_PHY_ADDR_SHIFT)
+ | I2CCMD_OPCODE_READ;
+ CSR_WRITE(sc, WMREG_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit */
+ for (i = 0; i < I2CCMD_PHY_TIMEOUT; i++) {
+ delay(50);
+ i2ccmd = CSR_READ(sc, WMREG_I2CCMD);
+ if (i2ccmd & I2CCMD_READY)
+ break;
+ }
+ if ((i2ccmd & I2CCMD_READY) == 0)
+ aprint_error_dev(sc->sc_dev, "I2CCMD Read did not complete\n");
+ if ((i2ccmd & I2CCMD_ERROR) != 0)
+ aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n");
+
+ rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00);
+
+ wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]);
+ return rv;
+}
+
+/*
+ * wm_gmii_hv_writereg: [mii interface function]
+ *
+ * Write a PHY register on the kumeran.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static void
+wm_sgmii_writereg(device_t self, int phy, int reg, int val)
+{
+ struct wm_softc *sc = device_private(self);
+ uint32_t i2ccmd;
+ int i;
+
+ if (wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid])) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+ __func__);
+ return;
+ }
+
+ i2ccmd = (reg << I2CCMD_REG_ADDR_SHIFT)
+ | (phy << I2CCMD_PHY_ADDR_SHIFT)
+ | I2CCMD_OPCODE_WRITE;
+ CSR_WRITE(sc, WMREG_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit */
+ for (i = 0; i < I2CCMD_PHY_TIMEOUT; i++) {
+ delay(50);
+ i2ccmd = CSR_READ(sc, WMREG_I2CCMD);
+ if (i2ccmd & I2CCMD_READY)
+ break;
+ }
+ if ((i2ccmd & I2CCMD_READY) == 0)
+ aprint_error_dev(sc->sc_dev, "I2CCMD Write did not complete\n");
+ if ((i2ccmd & I2CCMD_ERROR) != 0)
+ aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n");
+
+ wm_put_swfw_semaphore(sc, SWFW_PHY0_SM);
+}
+
+/*
* wm_gmii_statchg: [mii interface function]
*
* Callback from MII layer when media changes.
@@ -6544,3 +6866,64 @@ wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable)
CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
delay(20);
}
+
+static void
+wm_set_pcie_completion_timeout(struct wm_softc *sc)
+{
+ uint32_t gcr;
+ pcireg_t ctrl2;
+
+ gcr = CSR_READ(sc, WMREG_GCR);
+
+ /* Only take action if timeout value is defaulted to 0 */
+ if ((gcr & GCR_CMPL_TMOUT_MASK) != 0)
+ goto out;
+
+ if ((gcr & GCR_CAP_VER2) == 0) {
+ gcr |= GCR_CMPL_TMOUT_10MS;
+ goto out;
+ }
+
+ ctrl2 = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
+ sc->sc_pcixe_capoff + PCI_PCIE_DCSR2);
+ ctrl2 |= WM_PCI_PCIE_DCSR2_16MS;
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+ sc->sc_pcixe_capoff + PCI_PCIE_DCSR2, ctrl2);
+
+out:
+ /* Disable completion timeout resend */
+ gcr &= ~GCR_CMPL_TMOUT_RESEND;
+
+ CSR_WRITE(sc, WMREG_GCR, gcr);
+}
+
+/* special case - for 82575 - need to do manual init ... */
+static void
+wm_reset_init_script_82575(struct wm_softc *sc)
+{
+ /*
+ * remark: this is untested code - we have no board without EEPROM
+ * same setup as mentioned int the freeBSD driver for the i82575
+ */
+
+ /* SerDes configuration via SERDESCTRL */
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x00, 0x0c);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x01, 0x78);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x1b, 0x23);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCTL, 0x23, 0x15);
+
+ /* CCM configuration via CCMCTL register */
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_CCMCTL, 0x14, 0x00);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_CCMCTL, 0x10, 0x00);
+
+ /* PCIe lanes configuration */
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x00, 0xec);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x61, 0xdf);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x34, 0x05);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_GIOCTL, 0x2f, 0x81);
+
+ /* PCIe PLL Configuration */
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x02, 0x47);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x14, 0x00);
+ wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00);
+}
diff --git a/sys/dev/pci/if_wmreg.h b/sys/dev/pci/if_wmreg.h
index d1a8815b91a..5f0d9042171 100644
--- a/sys/dev/pci/if_wmreg.h
+++ b/sys/dev/pci/if_wmreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmreg.h,v 1.37 2010/02/16 10:06:19 msaitoh Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.38 2010/02/16 15:17:17 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -338,12 +338,16 @@ struct livengood_tcpip_ctxdesc {
#define CTRL_EXT_SPD_BYPS (1U << 15) /* speed select bypass */
#define CTRL_EXT_IPS1 (1U << 16) /* invert power state bit 1 */
#define CTRL_EXT_RO_DIS (1U << 17) /* relaxed ordering disabled */
-#define CTRL_EXT_LINK_MODE_MASK 0x00C00000
-#define CTRL_EXT_LINK_MODE_GMII 0x00000000
-#define CTRL_EXT_LINK_MODE_TBI 0x00C00000
-#define CTRL_EXT_LINK_MODE_KMRN 0x00000000
-#define CTRL_EXT_LINK_MODE_SERDES 0x00C00000
+#define CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define CTRL_EXT_LINK_MODE_KMRN 0x00000000
+#define CTRL_EXT_LINK_MODE_1000KX 0x00400000
+#define CTRL_EXT_LINK_MODE_SGMII 0x00800000
+#define CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000
+#define CTRL_EXT_LINK_MODE_TBI 0x00C00000
+#define CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
#define CTRL_EXT_PHYPDEN 0x00100000
+#define CTRL_EXT_I2C_ENA 0x02000000 /* I2C enable */
#define CTRL_EXT_DRV_LOAD 0x10000000
@@ -357,6 +361,16 @@ struct livengood_tcpip_ctxdesc {
#define MDIC_I (1U << 29) /* interrupt on MDI complete */
#define MDIC_E (1U << 30) /* MDI error */
+#define WMREG_SCTL 0x0024 /* SerDes Control - RW */
+/*
+ * These 4 macros are also used for other 8bit control registers on the
+ * 82575
+ */
+#define SCTL_CTL_READY (1U << 31)
+#define SCTL_CTL_DATA_MASK 0x000000ff
+#define SCTL_CTL_ADDR_SHIFT 8
+#define SCTL_CTL_POLL_TIMEOUT 640
+
#define WMREG_FCAL 0x0028 /* Flow Control Address Low */
#define FCAL_CONST 0x00c28001 /* Flow Control MAC addr low */
@@ -447,24 +461,48 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_OLD_RDBAL0 0x0110 /* Receive Descriptor Base Low (ring 0) */
#define WMREG_RDBAL 0x2800
+#define WMREG_RDBAL_2 0x0c00 /* for 82576 ... */
#define WMREG_OLD_RDBAH0 0x0114 /* Receive Descriptor Base High (ring 0) */
#define WMREG_RDBAH 0x2804
+#define WMREG_RDBAH_2 0x0c04 /* for 82576 ... */
#define WMREG_OLD_RDLEN0 0x0118 /* Receive Descriptor Length (ring 0) */
#define WMREG_RDLEN 0x2808
+#define WMREG_RDLEN_2 0x0c08 /* for 82576 ... */
+
+#define WMREG_SRRCTL 0x280c /* additional recieve control used in 82575 ... */
+#define WMREG_SRRCTL_2 0x0c0c /* for 82576 ... */
+#define SRRCTL_BSIZEPKT_MASK 0x0000007f
+#define SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
+#define SRRCTL_BSIZEHDRSIZE_MASK 0x00000f00
+#define SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
+#define SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define SRRCTL_DESCTYPE_ADV_ONEBUF (1U << 25)
+#define SRRCTL_DESCTYPE_HDR_SPLIT (2U << 25)
+#define SRRCTL_DESCTYPE_HDR_REPLICATION (3U << 25)
+#define SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT (4U << 25)
+#define SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS (5U << 25) /* 82575 only */
+#define SRRCTL_DESCTYPE_MASK (7U << 25)
+#define SRRCTL_DROP_EN 0x80000000
#define WMREG_OLD_RDH0 0x0120 /* Receive Descriptor Head (ring 0) */
#define WMREG_RDH 0x2810
+#define WMREG_RDH_2 0x0c10 /* for 82576 ... */
#define WMREG_OLD_RDT0 0x0128 /* Receive Descriptor Tail (ring 0) */
#define WMREG_RDT 0x2818
+#define WMREG_RDT_2 0x0c18 /* for 82576 ... */
#define WMREG_RXDCTL 0x2828 /* Receive Descriptor Control */
+#define WMREG_RXDCTL_2 0x0c28 /* for 82576 ... */
#define RXDCTL_PTHRESH(x) ((x) << 0) /* prefetch threshold */
#define RXDCTL_HTHRESH(x) ((x) << 8) /* host threshold */
#define RXDCTL_WTHRESH(x) ((x) << 16) /* write back threshold */
#define RXDCTL_GRAN (1U << 24) /* 0 = cacheline, 1 = descriptor */
+/* flags used starting with 82575 ... */
+#define RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define RXDCTL_SWFLSH 0x04000000 /* Rx Desc. write-back flushing */
#define WMREG_OLD_RDTR1 0x0130 /* Receive Delay Timer (ring 1) */
@@ -590,6 +628,10 @@ struct livengood_tcpip_ctxdesc {
#define TXDCTL_PTHRESH(x) ((x) << 0) /* prefetch threshold */
#define TXDCTL_HTHRESH(x) ((x) << 8) /* host threshold */
#define TXDCTL_WTHRESH(x) ((x) << 16) /* write back threshold */
+/* flags used starting with 82575 ... */
+#define TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */
+#define TXDCTL_PRIORITY 0x08000000
#define WMREG_TADV 0x382c /* Transmit Absolute Interrupt Delay Timer */
@@ -613,8 +655,10 @@ struct livengood_tcpip_ctxdesc {
#define PBA_24K 0x0018
#define PBA_30K 0x001e
#define PBA_32K 0x0020
+#define PBA_35K 0x0023
#define PBA_40K 0x0028
#define PBA_48K 0x0030 /* 48K, default Rx allocation */
+#define PBA_64K 0x0040
#define WMREG_PBS 0x1008 /* Packet Buffer Size (ICH) */
@@ -622,6 +666,42 @@ struct livengood_tcpip_ctxdesc {
#define EEMNGCTL_CFGDONE_0 0x040000 /* MNG config cycle done */
#define EEMNGCTL_CFGDONE_1 0x080000 /* 2nd port */
+#define WMREG_I2CCMD 0x1028 /* SFPI2C Command Register - RW */
+#define I2CCMD_REG_ADDR_SHIFT 16
+#define I2CCMD_REG_ADDR 0x00ff0000
+#define I2CCMD_PHY_ADDR_SHIFT 24
+#define I2CCMD_PHY_ADDR 0x07000000
+#define I2CCMD_OPCODE_READ 0x08000000
+#define I2CCMD_OPCODE_WRITE 0x00000000
+#define I2CCMD_RESET 0x10000000
+#define I2CCMD_READY 0x20000000
+#define I2CCMD_INTERRUPT_ENA 0x40000000
+#define I2CCMD_ERROR 0x80000000
+#define MAX_SGMII_PHY_REG_ADDR 255
+#define I2CCMD_PHY_TIMEOUT 200
+
+#define WMREG_EICS 0x01520 /* Ext. Interrupt Cause Set - WO */
+#define WMREG_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
+#define WMREG_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
+#define WMREG_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
+#define WMREG_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
+
+#define WMREG_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
+
+#define EITR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */
+#define EITR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */
+#define EITR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */
+#define EITR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */
+#define EITR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */
+#define EITR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */
+#define EITR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */
+#define EITR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */
+#define EITR_TCP_TIMER 0x40000000 /* TCP Timer */
+#define EITR_OTHER 0x80000000 /* Interrupt Cause Active */
+
+#define WMREG_EITR(x) (0x01680 + (0x4 * (x)))
+#define EITR_ITR_INT_MASK 0x0000ffff
+
#define WMREG_TXDMAC 0x3000 /* Transfer DMA Control */
#define TXDMAC_DPP (1U << 0) /* disable packet prefetch */
@@ -636,12 +716,6 @@ struct livengood_tcpip_ctxdesc {
#define TSPMT_TSMT(x) (x) /* TCP seg min transfer */
#define TSPMT_TSPBP(x) ((x) << 16) /* TCP seg pkt buf padding */
-#define WMREG_RXCSUM 0x5000 /* Receive Checksum register */
-#define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */
-#define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */
-#define RXCSUM_TUOFL (1U << 9) /* TCP/UDP checksum offload */
-#define RXCSUM_IPV6OFL (1U << 10) /* IPv6 checksum offload */
-
#define WMREG_CRCERRS 0x4000 /* CRC Error Count */
#define WMREG_ALGNERRC 0x4004 /* Alignment Error Count */
#define WMREG_SYMERRC 0x4008 /* Symbol Error Count */
@@ -692,11 +766,36 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_MDPHYA 0x003C /* PHY address - RW */
+#define WMREG_RXCSUM 0x5000 /* Receive Checksum register */
+#define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */
+#define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */
+#define RXCSUM_TUOFL (1U << 9) /* TCP/UDP checksum offload */
+#define RXCSUM_IPV6OFL (1U << 10) /* IPv6 checksum offload */
+
+#define WMREG_RLPML 0x5004 /* Rx Long Packet Max Length */
+
+#define WMREG_WUC 0x5800 /* Wakeup Control */
+
#define WMREG_MANC 0x5820 /* Management Control */
#define MANC_BLK_PHY_RST_ON_IDE 0x00040000
#define WMREG_MANC2H 0x5860 /* Manaegment Control To Host - RW */
+#define WMREG_GCR 0x5b00 /* PCIe Control */
+#define GCR_RXD_NO_SNOOP 0x00000001
+#define GCR_RXDSCW_NO_SNOOP 0x00000002
+#define GCR_RXDSCR_NO_SNOOP 0x00000004
+#define GCR_TXD_NO_SNOOP 0x00000008
+#define GCR_TXDSCW_NO_SNOOP 0x00000010
+#define GCR_TXDSCR_NO_SNOOP 0x00000020
+#define GCR_CMPL_TMOUT_MASK 0x0000f000
+#define GCR_CMPL_TMOUT_10MS 0x00001000
+#define GCR_CMPL_TMOUT_RESEND 0x00010000
+#define GCR_CAP_VER2 0x00040000
+#define WMREG_GIOCTL 0x5b44 /* GIO Analog Control Register */
+#define WMREG_CCMCTL 0x5b48 /* CCM Control Register */
+#define WMREG_SCCTL 0x5b4c /* PCIc PLL Configuration Register */
+
#define WMREG_SWSM 0x5b50 /* SW Semaphore */
#define SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
#define SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
@@ -715,6 +814,8 @@ struct livengood_tcpip_ctxdesc {
#define SWFW_PHY0_SM 0x0002 /* first ctrl phy access */
#define SWFW_PHY1_SM 0x0004 /* second ctrl phy access */
#define SWFW_MAC_CSR_SM 0x0008
+#define SWFW_PHY2_SM 0x0020 /* first ctrl phy access */
+#define SWFW_PHY3_SM 0x0040 /* first ctrl phy access */
#define SWFW_SOFT_SHIFT 0 /* software semaphores */
#define SWFW_FIRM_SHIFT 16 /* firmware semaphores */
@@ -784,3 +885,6 @@ struct livengood_tcpip_ctxdesc {
#define ICH_NVM_SIG_WORD 0x13
#define ICH_NVM_SIG_MASK 0xc000
+
+/* for PCI express Capability registers */
+#define WM_PCI_PCIE_DCSR2_16MS 0x00000005
diff --git a/sys/dev/pci/if_wmvar.h b/sys/dev/pci/if_wmvar.h
index c454ac2e6c8..192263f2eab 100644
--- a/sys/dev/pci/if_wmvar.h
+++ b/sys/dev/pci/if_wmvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmvar.h,v 1.8 2010/01/14 18:56:02 msaitoh Exp $ */
+/* $NetBSD: if_wmvar.h,v 1.9 2010/02/16 15:17:17 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -86,6 +86,8 @@
#define WM_F_PCIE 0x0800 /* bus is PCI-Express */
#define WM_F_SWFW_SYNC 0x1000 /* Software-Firmware synchronisation */
#define WM_F_SWFWHW_SYNC 0x2000 /* Software-Firmware synchronisation */
+#define WM_F_SGMII 0x4000 /* use SGMII */
+#define WM_F_NEWQUEUE 0x8000 /* chips which has the new queue system */
typedef enum {
WM_T_unknown = 0,
@@ -107,6 +109,10 @@ typedef enum {
WM_T_82573, /* i82573 */
WM_T_82574, /* i82574 */
WM_T_82583, /* i82583 */
+ WM_T_82575, /* i82575 */
+ WM_T_82576, /* i82576 */
+ WM_T_82580, /* i82580 */
+ WM_T_82580ER, /* i82580ER */
WM_T_80003, /* i80003 */
WM_T_ICH8, /* ICH8 LAN */
WM_T_ICH9, /* ICH9 LAN */