Module Name: src Committed By: msaitoh Date: Fri May 20 00:57:43 UTC 2011
Modified Files: src/sys/dev/pci: if_wm.c Log Message: - Add PCH2 support. - Add 82579 support. - Change PBA size for PCH from 10K to 26K as FreeBSD's em-7.1.7 - Add yet another 82567V support. - Add ICH10+HANKSVILL support. - Add 82580 quad-1000BaseX support. To generate a diff of this commit: cvs rdiff -u -r1.220 -r1.221 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.220 src/sys/dev/pci/if_wm.c:1.221 --- src/sys/dev/pci/if_wm.c:1.220 Tue Feb 22 21:19:30 2011 +++ src/sys/dev/pci/if_wm.c Fri May 20 00:57:42 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.220 2011/02/22 21:19:30 dyoung Exp $ */ +/* $NetBSD: if_wm.c,v 1.221 2011/05/20 00:57:42 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.220 2011/02/22 21:19:30 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.221 2011/05/20 00:57:42 msaitoh Exp $"); #include "rnd.h" @@ -579,6 +579,7 @@ static int32_t wm_read_ich8_byte(struct wm_softc *, uint32_t, uint8_t *); static int32_t wm_read_ich8_word(struct wm_softc *, uint32_t, uint16_t *); static void wm_82547_txfifo_stall(void *); +static void wm_gate_hw_phy_config_ich8lan(struct wm_softc *, int); static int wm_check_mng_mode(struct wm_softc *); static int wm_check_mng_mode_ich8lan(struct wm_softc *); static int wm_check_mng_mode_82574(struct wm_softc *); @@ -593,8 +594,11 @@ static void wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *); #endif static void wm_hv_phy_workaround_ich8lan(struct wm_softc *); +static void wm_lv_phy_workaround_ich8lan(struct wm_softc *); static void wm_k1_gig_workaround_hv(struct wm_softc *, int); +static void wm_set_mdio_slow_mode_hv(struct wm_softc *); static void wm_configure_k1_ich8lan(struct wm_softc *, int); +static void wm_smbustopci(struct wm_softc *); static void wm_set_pcie_completion_timeout(struct wm_softc *); static void wm_reset_init_script_82575(struct wm_softc *); static void wm_release_manageability(struct wm_softc *); @@ -910,6 +914,12 @@ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801J_R_BM_V, "82567V-2 LAN Controller", WM_T_ICH10, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801J_D_BM_V, + "82567V-3? LAN Controller", + WM_T_ICH10, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_HANKSVILLE, + "HANKSVILLE LAN Controller", + WM_T_ICH10, WMP_F_1000T }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCH_M_LM, "PCH LAN (82577LM) Controller", WM_T_PCH, WMP_F_1000T }, @@ -921,6 +931,12 @@ WM_T_PCH, WMP_F_1000T }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCH_D_DC, "PCH LAN (82578DC) Controller", + WM_T_PCH2, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCH2_LV_LM, + "PCH2 LAN (82579LM) Controller", + WM_T_PCH2, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCH2_LV_V, + "PCH2 LAN (82579V) Controller", WM_T_PCH, WMP_F_1000T }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82575EB_COPPER, "82575EB dual-1000baseT Ethernet", @@ -988,6 +1004,9 @@ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_ER_DUAL, "82580 dual-1000BaseT Ethernet", WM_T_82580ER, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_QUAD_FIBER, + "82580 quad-1000BaseX Ethernet", + WM_T_82580, WMP_F_1000X }, { 0, 0, NULL, 0, 0 }, @@ -1284,9 +1303,10 @@ 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_type != WM_T_PCH2)) { sc->sc_flags |= WM_F_EEPROM_SEMAPHORE; - /* ICH* and PCH have no PCIe capability registers */ + /* 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) @@ -1452,6 +1472,10 @@ CSR_READ(sc, WMREG_COLC); CSR_READ(sc, WMREG_RXERRC); + /* get PHY control from SMBus to PCIe */ + if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)) + wm_smbustopci(sc); + /* * Reset the chip to a known state. */ @@ -1468,6 +1492,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: if (wm_check_mng_mode(sc) != 0) wm_get_hw_control(sc); break; @@ -1542,6 +1567,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: /* FLASH */ sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_SWFWHW_SYNC; memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH); @@ -1681,6 +1707,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: apme_mask = WUC_APME; eeprom_data = CSR_READ(sc, WMREG_WUC); break; @@ -1782,7 +1809,7 @@ */ 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_82573 + || sc->sc_type == WM_T_PCH2 || sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574 || sc->sc_type == WM_T_82583) { /* STATUS_TBIMODE reserved/reused, can't rely on it */ wm_gmii_mediainit(sc, wmp->wmp_product); @@ -1861,6 +1888,7 @@ case WM_T_80003: case WM_T_ICH9: case WM_T_ICH10: + case WM_T_PCH2: /* PCH2 supports 9K frame size */ /* XXX limited to 9234 */ sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU; break; @@ -2351,6 +2379,21 @@ splx(s); } +static void +wm_gate_hw_phy_config_ich8lan(struct wm_softc *sc, int on) +{ + uint32_t reg; + + reg = CSR_READ(sc, WMREG_EXTCNFCTR); + + if (on != 0) + reg |= EXTCNFCTR_GATE_PHY_CFG; + else + reg &= ~EXTCNFCTR_GATE_PHY_CFG; + + CSR_WRITE(sc, WMREG_EXTCNFCTR, reg); +} + /* * wm_82547_txfifo_bugchk: * @@ -3438,8 +3481,10 @@ break; case WM_T_ICH9: case WM_T_ICH10: - case WM_T_PCH: sc->sc_pba = PBA_10K; + case WM_T_PCH: + case WM_T_PCH2: + sc->sc_pba = PBA_26K; break; default: sc->sc_pba = sc->sc_ethercom.ec_if.if_mtu > 8192 ? @@ -3550,15 +3595,18 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST; if (wm_check_reset_block(sc) == 0) { - if (sc->sc_type >= WM_T_PCH) { - uint32_t status; + /* + * Gate automatic PHY configuration by hardware on + * manaed 82579 + */ + if ((sc->sc_type == WM_T_PCH2) + && ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) + != 0)) + wm_gate_hw_phy_config_ich8lan(sc, 1); - status = CSR_READ(sc, WMREG_STATUS); - CSR_WRITE(sc, WMREG_STATUS, - status & ~STATUS_PHYRA); - } reg |= CTRL_PHY_RESET; phy_reset = 1; @@ -3650,6 +3698,7 @@ break; case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: wm_lan_init_done(sc); break; default: @@ -3776,6 +3825,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: if (wm_check_mng_mode(sc) != 0) wm_get_hw_control(sc); break; @@ -3789,7 +3839,7 @@ reg = CSR_READ(sc, WMREG_CTRL_EXT); /* Enable PHY low-power state when MAC is at D3 w/o WoL */ - if (sc->sc_type == WM_T_PCH) + if ((sc->sc_type == WM_T_PCH) && (sc->sc_type == WM_T_PCH2)) CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_PHYPDEN); /* Initialize the transmit descriptor ring. */ @@ -3919,7 +3969,8 @@ * XXX Values could probably stand some tuning. */ 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_ICH10) && (sc->sc_type != WM_T_PCH) + && (sc->sc_type != WM_T_PCH2)) { CSR_WRITE(sc, WMREG_FCAL, FCAL_CONST); CSR_WRITE(sc, WMREG_FCAH, FCAH_CONST); CSR_WRITE(sc, WMREG_FCT, ETHERTYPE_FLOWCONTROL); @@ -3951,6 +4002,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: /* * Set the mac to wait the maximum time between each * iteration and increase the max iterations when @@ -4014,7 +4066,8 @@ CSR_WRITE(sc, WMREG_IMS, sc->sc_icr); 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) { reg = CSR_READ(sc, WMREG_KABGTXD); reg |= KABGTXD_BGSQLBIAS; CSR_WRITE(sc, WMREG_KABGTXD, reg); @@ -4279,6 +4332,7 @@ switch (sc->sc_type) { case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: for (i = 0; i < WM_ICH8_LAN_INIT_TIMEOUT; i++) { reg = CSR_READ(sc, WMREG_STATUS); if ((reg & STATUS_LAN_INIT_DONE) != 0) @@ -4356,6 +4410,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: if (sc->sc_type >= WM_T_PCH) { reg = CSR_READ(sc, WMREG_STATUS); if ((reg & STATUS_PHYRA) != 0) @@ -4670,7 +4725,8 @@ return 1; 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) rv = wm_read_eeprom_ich8(sc, word, wordcnt, data); else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR) rv = wm_read_eeprom_eerd(sc, word, wordcnt, data); @@ -4946,7 +5002,8 @@ uint32_t hash; 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) { hash = (enaddr[4] >> ich8_lo_shift[sc->sc_mchash_type]) | (((uint16_t) enaddr[5]) << ich8_hi_shift[sc->sc_mchash_type]); return (hash & 0x3ff); @@ -4992,7 +5049,8 @@ * clear the remaining slots. */ 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) size = WM_ICH8_RAL_TABSIZE; else size = WM_RAL_TABSIZE; @@ -5001,7 +5059,8 @@ wm_set_ral(sc, NULL, i); 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) size = WM_ICH8_MC_TABSIZE; else size = WM_MC_TABSIZE; @@ -5027,7 +5086,8 @@ reg = (hash >> 5); 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) reg &= 0x1f; else reg &= 0x7f; @@ -5376,6 +5436,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: rv = wm_get_swfwhw_semaphore(sc); break; default: @@ -5458,6 +5519,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: /* generic reset */ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl | CTRL_PHY_RESET); delay(100); @@ -5491,6 +5553,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: wm_put_swfwhw_semaphore(sc); break; default: @@ -5535,12 +5598,17 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: /* Allow time for h/w to get to a quiescent state afer reset */ delay(10*1000); - if (sc->sc_type == WM_T_PCH) { + if (sc->sc_type == WM_T_PCH) wm_hv_phy_workaround_ich8lan(sc); + if (sc->sc_type == WM_T_PCH2) + wm_lv_phy_workaround_ich8lan(sc); + + if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)) { /* * dummy read to clear the phy wakeup bit after lcd * reset @@ -5554,7 +5622,7 @@ */ /* Configure the LCD with the OEM bits in NVM */ - if (sc->sc_type == WM_T_PCH) { + if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)) { /* * Disable LPLU. * XXX It seems that 82567 has LPLU, too. @@ -5616,6 +5684,13 @@ sc->sc_mii.mii_readreg = wm_gmii_hv_readreg; sc->sc_mii.mii_writereg = wm_gmii_hv_writereg; break; + case PCI_PRODUCT_INTEL_PCH2_LV_LM: + case PCI_PRODUCT_INTEL_PCH2_LV_V: + /* 82578 */ + sc->sc_phytype = WMPHY_82579; + sc->sc_mii.mii_readreg = wm_gmii_hv_readreg; + sc->sc_mii.mii_writereg = wm_gmii_hv_writereg; + break; case PCI_PRODUCT_INTEL_82801I_BM: case PCI_PRODUCT_INTEL_82801J_R_BM_LM: case PCI_PRODUCT_INTEL_82801J_R_BM_LF: @@ -5681,6 +5756,13 @@ MII_OFFSET_ANY, MIIF_DOPAUSE); } + if ((sc->sc_type == WM_T_PCH2) && + (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL)) { + wm_set_mdio_slow_mode_hv(sc); + mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, + MII_OFFSET_ANY, MIIF_DOPAUSE); + } + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { /* if failed, retry with *_bm_* */ sc->sc_mii.mii_readreg = wm_gmii_bm_readreg; @@ -6922,6 +7004,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: rv = wm_check_mng_mode_ich8lan(sc); break; case WM_T_82574: @@ -7022,6 +7105,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: reg = CSR_READ(sc, WMREG_FWSM); if ((reg & FWSM_RSPCIPHY) != 0) return 0; @@ -7067,6 +7151,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: reg = CSR_READ(sc, WMREG_CTRL_EXT); CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_DRV_LOAD); break; @@ -7272,6 +7357,8 @@ static void wm_hv_phy_workaround_ich8lan(struct wm_softc *sc) { + if (sc->sc_phytype == WMPHY_82577) + wm_set_mdio_slow_mode_hv(sc); /* (PCH rev.2) && (82577 && (phy rev 2 or 3)) */ @@ -7305,6 +7392,13 @@ } static void +wm_lv_phy_workaround_ich8lan(struct wm_softc *sc) +{ + + wm_set_mdio_slow_mode_hv(sc); +} + +static void wm_k1_gig_workaround_hv(struct wm_softc *sc, int link) { int k1_enable = sc->sc_nvm_k1_enabled; @@ -7327,6 +7421,16 @@ } static void +wm_set_mdio_slow_mode_hv(struct wm_softc *sc) +{ + uint32_t reg; + + reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_KMRN_MODE_CTRL); + wm_gmii_hv_writereg(sc->sc_dev, 1, HV_KMRN_MODE_CTRL, + reg | HV_KMRN_MDIO_SLOW); +} + +static void wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable) { uint32_t ctrl, ctrl_ext, tmp; @@ -7359,6 +7463,31 @@ } static void +wm_smbustopci(struct wm_softc *sc) +{ + uint32_t fwsm; + + fwsm = CSR_READ(sc, WMREG_FWSM); + if (((fwsm & FWSM_FW_VALID) == 0) + && ((wm_check_reset_block(sc) == 0))) { + sc->sc_ctrl |= CTRL_LANPHYPC_OVERRIDE; + sc->sc_ctrl &= ~CTRL_LANPHYPC_VALUE; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + delay(10); + sc->sc_ctrl &= ~CTRL_LANPHYPC_OVERRIDE; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + delay(50*1000); + + /* + * Gate automatic PHY configuration by hardware on non-managed + * 82579 + */ + if (sc->sc_type == WM_T_PCH2) + wm_gate_hw_phy_config_ich8lan(sc, 1); + } +} + +static void wm_set_pcie_completion_timeout(struct wm_softc *sc) { uint32_t gcr; @@ -7486,6 +7615,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: sc->sc_flags |= WM_F_HAS_AMT; sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES; break; @@ -7560,6 +7690,7 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + case WM_T_PCH2: /* Disable gig during WOL */ reg = CSR_READ(sc, WMREG_PHY_CTRL); reg |= PHY_CTRL_D0A_LPLU | PHY_CTRL_GBE_DIS; @@ -7604,7 +7735,8 @@ } 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_ICH10) || (sc->sc_type == WM_T_PCH) + || (sc->sc_type == WM_T_PCH2)) && (sc->sc_phytype == WMPHY_IGP_3)) wm_igp3_phy_powerdown_workaround_ich8lan(sc);