Module Name: src Committed By: msaitoh Date: Thu Aug 28 16:22:59 UTC 2014
Modified Files: src/sys/dev/pci: if_wm.c Log Message: Add Internal SERDES mode support newer than or equal to 82575. Currently, it supports fiber device only. If you use 1000BaseT SFP module, it won't work. We have to write code to read SFP ROM and set SGMII mode if the module is copper. To generate a diff of this commit: cvs rdiff -u -r1.291 -r1.292 src/sys/dev/pci/if_wm.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.291 src/sys/dev/pci/if_wm.c:1.292 --- src/sys/dev/pci/if_wm.c:1.291 Tue Aug 26 14:44:00 2014 +++ src/sys/dev/pci/if_wm.c Thu Aug 28 16:22:59 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.291 2014/08/26 14:44:00 msaitoh Exp $ */ +/* $NetBSD: if_wm.c,v 1.292 2014/08/28 16:22:59 msaitoh Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -73,7 +73,7 @@ * TODO (in order of importance): * * - Check XXX'ed comments - * - Internal SERDES mode newer than or equal to 82575. + * - Read SFP ROM and set media type correctly on 82575 and newer devices * - EEE (Energy Efficiency Ethernet) * - MSI/MSI-X * - Virtual Function @@ -82,7 +82,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.291 2014/08/26 14:44:00 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.292 2014/08/28 16:22:59 msaitoh Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -273,10 +273,10 @@ struct wm_softc { int sc_bus_speed; /* PCI/PCIX bus speed */ int sc_pcixe_capoff; /* PCI[Xe] capability reg offset */ - const struct wm_product *sc_wmp; /* Pointer to the wm_product entry */ wm_chip_type sc_type; /* MAC type */ int sc_rev; /* MAC revision */ wm_phy_type sc_phytype; /* PHY type */ + uint32_t sc_mediatype; /* Media type (Copper, Fiber, SERDES)*/ int sc_funcid; /* unit number of the chip (0 to 3) */ int sc_flags; /* flags; see below */ int sc_if_flags; /* last if_flags */ @@ -585,7 +585,7 @@ static int wm_intr(void *); /* * Media related. - * GMII, SGMII, TBI (and SERDES) + * GMII, SGMII, TBI, SERDES and SFP. */ /* GMII related */ static void wm_gmii_reset(struct wm_softc *); @@ -622,6 +622,8 @@ static void wm_tbi_mediastatus(struct if static int wm_tbi_mediachange(struct ifnet *); static void wm_tbi_set_linkled(struct wm_softc *); static void wm_tbi_check_link(struct wm_softc *); +/* SFP related */ +static uint32_t wm_get_sfp_media_type(struct wm_softc *); /* * NVM related. @@ -718,10 +720,12 @@ static const struct wm_product { pci_product_id_t wmp_product; const char *wmp_name; wm_chip_type wmp_type; - int wmp_flags; + uint32_t wmp_flags; +#define WMP_F_UNKNOWN 0x00 #define WMP_F_FIBER 0x01 #define WMP_F_COPPER 0x02 -#define WMP_F_SERDES 0x04 +#define WMP_F_SERDES 0x03 /* Internal SERDES */ +#define WMP_MEDIATYPE(x) ((x) & 0x03) } wm_products[] = { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82542, "Intel i82542 1000BASE-X Ethernet", @@ -1036,15 +1040,9 @@ static const struct wm_product { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575EB_COPPER, "82575EB dual-1000baseT Ethernet", WM_T_82575, WMP_F_COPPER }, -#if 0 - /* - * not sure if WMP_F_FIBER 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_COPPER }, @@ -1112,11 +1110,11 @@ static const struct wm_product { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I350_SERDES, "I350 Gigabit Backplane Connection", WM_T_I350, WMP_F_SERDES }, -#if 0 + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I350_SGMII, "I350 Gigabit Connection", WM_T_I350, WMP_F_COPPER }, -#endif + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C2000_SGMII, "I354 Gigabit Connection", WM_T_I354, WMP_F_COPPER }, @@ -1136,11 +1134,11 @@ static const struct wm_product { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I210_SERDES, "I210 Gigabit Ethernet (SERDES)", WM_T_I210, WMP_F_SERDES }, -#if 0 + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I210_SGMII, "I210 Gigabit Ethernet (SGMII)", - WM_T_I210, WMP_F_SERDES }, -#endif + WM_T_I210, WMP_F_COPPER }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I211_COPPER, "I211 Ethernet (COPPER)", WM_T_I211, WMP_F_COPPER }, @@ -1278,6 +1276,7 @@ wm_attach(device_t parent, device_t self pcireg_t preg, memtype; uint16_t eeprom_data, apme_mask; bool force_clear_smbi; + uint32_t link_mode; uint32_t reg; char intrbuf[PCI_INTRSTR_LEN]; @@ -1285,11 +1284,14 @@ wm_attach(device_t parent, device_t self callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS); sc->sc_stopping = false; - sc->sc_wmp = wmp = wm_lookup(pa); + wmp = wm_lookup(pa); +#ifdef DIAGNOSTIC if (wmp == NULL) { printf("\n"); panic("wm_attach: impossible"); } +#endif + sc->sc_mediatype = WMP_MEDIATYPE(wmp->wmp_flags); sc->sc_pc = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; @@ -2018,9 +2020,11 @@ wm_attach(device_t parent, device_t self wm_gmii_mediainit(sc, wmp->wmp_product); } else if (sc->sc_type < WM_T_82543 || (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) { - if (wmp->wmp_flags & WMP_F_COPPER) + if (sc->sc_mediatype & WMP_F_COPPER) { aprint_error_dev(sc->sc_dev, "WARNING: TBIMODE set on 1000BASE-T product!\n"); + sc->sc_mediatype = WMP_F_FIBER; + } wm_tbi_mediainit(sc); } else { switch (sc->sc_type) { @@ -2033,42 +2037,79 @@ wm_attach(device_t parent, device_t self case WM_T_I210: case WM_T_I211: reg = CSR_READ(sc, WMREG_CTRL_EXT); - switch (reg & CTRL_EXT_LINK_MODE_MASK) { + link_mode = reg & CTRL_EXT_LINK_MODE_MASK; + switch (link_mode) { case CTRL_EXT_LINK_MODE_1000KX: aprint_verbose_dev(sc->sc_dev, "1000KX\n"); - CSR_WRITE(sc, WMREG_CTRL_EXT, - reg | CTRL_EXT_I2C_ENA); - panic("not supported yet\n"); + sc->sc_mediatype = WMP_F_SERDES; break; case CTRL_EXT_LINK_MODE_SGMII: if (wm_sgmii_uses_mdio(sc)) { aprint_verbose_dev(sc->sc_dev, "SGMII(MDIO)\n"); sc->sc_flags |= WM_F_SGMII; - wm_gmii_mediainit(sc, - wmp->wmp_product); + sc->sc_mediatype = WMP_F_COPPER; break; } aprint_verbose_dev(sc->sc_dev, "SGMII(I2C)\n"); /*FALLTHROUGH*/ case CTRL_EXT_LINK_MODE_PCIE_SERDES: - aprint_verbose_dev(sc->sc_dev, "SERDES\n"); - CSR_WRITE(sc, WMREG_CTRL_EXT, - reg | CTRL_EXT_I2C_ENA); - panic("not supported yet\n"); + sc->sc_mediatype = wm_get_sfp_media_type(sc); + if (sc->sc_mediatype == WMP_F_UNKNOWN) { + if (link_mode + == CTRL_EXT_LINK_MODE_SGMII) { + sc->sc_mediatype + = WMP_F_COPPER; + sc->sc_flags |= WM_F_SGMII; + } else { + sc->sc_mediatype + = WMP_F_SERDES; + aprint_verbose_dev(sc->sc_dev, + "SERDES\n"); + } + break; + } + if (sc->sc_mediatype == WMP_F_SERDES) + aprint_verbose_dev(sc->sc_dev, + "SERDES\n"); + + /* Change current link mode setting */ + reg &= ~CTRL_EXT_LINK_MODE_MASK; + switch (sc->sc_mediatype) { + case WMP_F_COPPER: + reg |= CTRL_EXT_LINK_MODE_SGMII; + break; + case WMP_F_SERDES: + reg |= CTRL_EXT_LINK_MODE_PCIE_SERDES; + break; + default: + break; + } + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); 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); + sc->sc_mediatype = WMP_F_COPPER; break; } + + reg &= ~CTRL_EXT_I2C_ENA; + if ((sc->sc_flags & WM_F_SGMII) != 0) + reg |= CTRL_EXT_I2C_ENA; + else + reg &= ~CTRL_EXT_I2C_ENA; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + + if (sc->sc_mediatype == WMP_F_COPPER) + wm_gmii_mediainit(sc, wmp->wmp_product); + else + wm_tbi_mediainit(sc); break; default: - if (wmp->wmp_flags & WMP_F_FIBER) + if (sc->sc_mediatype & WMP_F_FIBER) aprint_error_dev(sc->sc_dev, "WARNING: TBIMODE clear on 1000BASE-X product!\n"); + sc->sc_mediatype = WMP_F_COPPER; wm_gmii_mediainit(sc, wmp->wmp_product); } } @@ -6081,7 +6122,7 @@ wm_gmii_mediainit(struct wm_softc *sc, p struct mii_data *mii = &sc->sc_mii; uint32_t reg; - /* We have MII. */ + /* We have GMII. */ sc->sc_flags |= WM_F_HAS_MII; if (sc->sc_type == WM_T_80003) @@ -7151,7 +7192,7 @@ wm_check_for_link(struct wm_softc *sc) uint32_t status; uint32_t sig; - if (sc->sc_wmp->wmp_flags & WMP_F_SERDES) { + if (sc->sc_mediatype & WMP_F_SERDES) { sc->sc_tbi_linkup = 1; return 0; } @@ -7250,7 +7291,7 @@ wm_tbi_mediainit(struct wm_softc *sc) */ sc->sc_ctrl |= CTRL_SWDPIO(0); sc->sc_ctrl &= ~CTRL_SWDPIO(1); - if (sc->sc_wmp->wmp_flags & WMP_F_SERDES) + if (sc->sc_mediatype & WMP_F_SERDES) sc->sc_ctrl &= ~CTRL_LRST; CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); @@ -7330,7 +7371,7 @@ wm_tbi_mediachange(struct ifnet *ifp) uint32_t status; int i; - if (sc->sc_wmp->wmp_flags & WMP_F_SERDES) + if (sc->sc_mediatype & WMP_F_SERDES) return 0; if ((sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_82572) @@ -7460,7 +7501,7 @@ wm_tbi_check_link(struct wm_softc *sc) KASSERT(WM_TX_LOCKED(sc)); - if (sc->sc_wmp->wmp_flags & WMP_F_SERDES) { + if (sc->sc_mediatype & WMP_F_SERDES) { sc->sc_tbi_linkup = 1; return; } @@ -7515,6 +7556,14 @@ wm_tbi_check_link(struct wm_softc *sc) wm_tbi_set_linkled(sc); } +/* SFP related */ +static uint32_t +wm_get_sfp_media_type(struct wm_softc *sc) +{ + + /* XXX */ + return WMP_F_SERDES; +} /* * NVM related. * Microwire, SPI (w/wo EERD) and Flash. @@ -8954,8 +9003,8 @@ wm_enable_wakeup(struct wm_softc *sc) } /* Keep the laser running on fiber adapters */ - if (((sc->sc_wmp->wmp_flags & WMP_F_FIBER) != 0) - || (sc->sc_wmp->wmp_flags & WMP_F_SERDES) != 0) { + if (((sc->sc_mediatype & WMP_F_FIBER) != 0) + || (sc->sc_mediatype & WMP_F_SERDES) != 0) { reg = CSR_READ(sc, WMREG_CTRL_EXT); reg |= CTRL_EXT_SWDPIN(3); CSR_WRITE(sc, WMREG_CTRL_EXT, reg);