Module Name: src Committed By: msaitoh Date: Thu Jan 14 18:56:02 UTC 2010
Modified Files: src/sys/dev/pci: if_wm.c if_wmreg.h if_wmvar.h Added Files: src/sys/dev/mii: inbmphyreg.h Log Message: Fixes the rx stall problem on 82578 by MANY workaround code. We need more work for 82577. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/sys/dev/mii/inbmphyreg.h cvs rdiff -u -r1.191 -r1.192 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.34 -r1.35 src/sys/dev/pci/if_wmreg.h cvs rdiff -u -r1.7 -r1.8 src/sys/dev/pci/if_wmvar.h 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.191 src/sys/dev/pci/if_wm.c:1.192 --- src/sys/dev/pci/if_wm.c:1.191 Tue Jan 12 22:26:30 2010 +++ src/sys/dev/pci/if_wm.c Thu Jan 14 18:56:02 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.191 2010/01/12 22:26:30 msaitoh Exp $ */ +/* $NetBSD: if_wm.c,v 1.192 2010/01/14 18:56:02 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.191 2010/01/12 22:26:30 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.192 2010/01/14 18:56:02 msaitoh Exp $"); #include "bpfilter.h" #include "rnd.h" @@ -124,6 +124,7 @@ #include <dev/mii/mii_bitbang.h> #include <dev/mii/ikphyreg.h> #include <dev/mii/igphyreg.h> +#include <dev/mii/inbmphyreg.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> @@ -249,7 +250,9 @@ pci_chipset_tag_t sc_pc; pcitag_t sc_pcitag; - wm_chip_type sc_type; /* chip type */ + wm_chip_type sc_type; /* MAC type */ + int sc_rev; /* MAC revision */ + wm_phy_type sc_phytype; /* PHY type */ int sc_flags; /* flags; see below */ int sc_if_flags; /* last if_flags */ int sc_bus_speed; /* PCI/PCIX bus speed */ @@ -366,6 +369,7 @@ #endif int sc_ich8_flash_base; int sc_ich8_flash_bank_size; + int sc_nvm_k1_enabled; }; #define WM_RXCHAIN_RESET(sc) \ @@ -520,8 +524,8 @@ static void wm_gmii_i80003_writereg(device_t, int, int, int); 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_kv_readreg(device_t, int, int); -static void wm_gmii_kv_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 void wm_gmii_statchg(device_t); @@ -562,6 +566,9 @@ static int wm_check_reset_block(struct wm_softc *); static void wm_get_hw_control(struct wm_softc *); 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); CFATTACH_DECL_NEW(wm, sizeof(struct wm_softc), wm_match, wm_attach, NULL, NULL); @@ -991,18 +998,18 @@ else sc->sc_dmat = pa->pa_dmat; - preg = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG)); + sc->sc_rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG)); aprint_naive(": Ethernet controller\n"); - aprint_normal(": %s, rev. %d\n", wmp->wmp_name, preg); + aprint_normal(": %s, rev. %d\n", wmp->wmp_name, sc->sc_rev); sc->sc_type = wmp->wmp_type; if (sc->sc_type < WM_T_82543) { - if (preg < 2) { + if (sc->sc_rev < 2) { aprint_error_dev(sc->sc_dev, "i82542 must be at least rev. 2\n"); return; } - if (preg < 3) + if (sc->sc_rev < 3) sc->sc_type = WM_T_82542_2_0; } @@ -1575,6 +1582,18 @@ sc->sc_tdt_reg = WMREG_TDT; } + if (sc->sc_type == WM_T_PCH) { + uint16_t val; + + /* Save the NVM K1 bit setting */ + wm_read_eeprom(sc, EEPROM_OFF_K1_CONFIG, 1, &val); + + if ((val & EEPROM_K1_CONFIG_ENABLE) != 0) + sc->sc_nvm_k1_enabled = 1; + else + sc->sc_nvm_k1_enabled = 0; + } + /* * Determine if we're TBI or GMII mode, and initialize the * media structures accordingly. @@ -2896,74 +2915,101 @@ } /* - * wm_linkintr: + * wm_linkintr_gmii: * - * Helper; handle link interrupts. + * Helper; handle link interrupts for GMII. */ static void -wm_linkintr(struct wm_softc *sc, uint32_t icr) +wm_linkintr_gmii(struct wm_softc *sc, uint32_t icr) { - uint32_t status; DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev), __func__)); - /* - * If we get a link status interrupt on a 1000BASE-T - * device, just fall into the normal MII tick path. - */ - if (sc->sc_flags & WM_F_HAS_MII) { - if (icr & ICR_LSC) { - DPRINTF(WM_DEBUG_LINK, - ("%s: LINK: LSC -> mii_tick\n", - device_xname(sc->sc_dev))); - mii_tick(&sc->sc_mii); - if (sc->sc_type == WM_T_82543) { - int miistatus, active; - /* - * With 82543, we need to force speed and - * duplex on the MAC equal to what the PHY - * speed and duplex configuration is. - */ - miistatus = sc->sc_mii.mii_media_status; + if (icr & ICR_LSC) { + DPRINTF(WM_DEBUG_LINK, + ("%s: LINK: LSC -> mii_tick\n", + device_xname(sc->sc_dev))); + mii_tick(&sc->sc_mii); + if (sc->sc_type == WM_T_82543) { + int miistatus, active; - if (miistatus & IFM_ACTIVE) { - active = sc->sc_mii.mii_media_active; - sc->sc_ctrl &= ~(CTRL_SPEED_MASK - | CTRL_FD); - switch (IFM_SUBTYPE(active)) { - case IFM_10_T: - sc->sc_ctrl |= CTRL_SPEED_10; - break; - case IFM_100_TX: - sc->sc_ctrl |= CTRL_SPEED_100; - break; - case IFM_1000_T: - sc->sc_ctrl |= CTRL_SPEED_1000; - break; - default: - /* - * fiber? - * Shoud not enter here. - */ - printf("unknown media (%x)\n", - active); - break; - } - if (active & IFM_FDX) - sc->sc_ctrl |= CTRL_FD; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + /* + * With 82543, we need to force speed and + * duplex on the MAC equal to what the PHY + * speed and duplex configuration is. + */ + miistatus = sc->sc_mii.mii_media_status; + + if (miistatus & IFM_ACTIVE) { + active = sc->sc_mii.mii_media_active; + sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD); + switch (IFM_SUBTYPE(active)) { + case IFM_10_T: + sc->sc_ctrl |= CTRL_SPEED_10; + break; + case IFM_100_TX: + sc->sc_ctrl |= CTRL_SPEED_100; + break; + case IFM_1000_T: + sc->sc_ctrl |= CTRL_SPEED_1000; + break; + default: + /* + * fiber? + * Shoud not enter here. + */ + printf("unknown media (%x)\n", + active); + break; } + if (active & IFM_FDX) + sc->sc_ctrl |= CTRL_FD; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + } + } else if (sc->sc_type == WM_T_PCH) { + wm_k1_gig_workaround_hv(sc, + ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0)); + } + + if ((sc->sc_phytype == WMPHY_82578) + && (IFM_SUBTYPE(sc->sc_mii.mii_media_active) + == IFM_1000_T)) { + + if ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0) { + printf("XXX link sall wa\n"); + delay(200*1000); /* XXX too big */ + + /* Link stall fix for link up */ + wm_gmii_hv_writereg(sc->sc_dev, 1, + HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC + | HV_MUX_DATA_CTRL_FORCE_SPEED); + wm_gmii_hv_writereg(sc->sc_dev, 1, + HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC); } - } else if (icr & ICR_RXSEQ) { - DPRINTF(WM_DEBUG_LINK, - ("%s: LINK Receive sequence error\n", - device_xname(sc->sc_dev))); } - return; + } else if (icr & ICR_RXSEQ) { + DPRINTF(WM_DEBUG_LINK, + ("%s: LINK Receive sequence error\n", + device_xname(sc->sc_dev))); } +} + +/* + * wm_linkintr_tbi: + * + * Helper; handle link interrupts for TBI mode. + */ +static void +wm_linkintr_tbi(struct wm_softc *sc, uint32_t icr) +{ + uint32_t status; + + DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev), + __func__)); - /* TBI mode */ status = CSR_READ(sc, WMREG_STATUS); if (icr & ICR_LSC) { if (status & STATUS_LU) { @@ -3010,6 +3056,21 @@ } /* + * wm_linkintr: + * + * Helper; handle link interrupts. + */ +static void +wm_linkintr(struct wm_softc *sc, uint32_t icr) +{ + + if (sc->sc_flags & WM_F_HAS_MII) + wm_linkintr_gmii(sc, icr); + else + wm_linkintr_tbi(sc, icr); +} + +/* * wm_tick: * * One second timer, used to check link status, sweep up @@ -3159,10 +3220,6 @@ delay(5000); } - if (sc->sc_type == WM_T_PCH) { - /* Save K1 */ - } - switch (sc->sc_type) { case WM_T_82544: /* XXX check whether WM_F_IOH_VALID is set */ case WM_T_82541: @@ -3303,6 +3360,9 @@ /* reload sc_ctrl */ sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL); + /* dummy read from WUC */ + if (sc->sc_type == WM_T_PCH) + reg = wm_gmii_hv_readreg(sc->sc_dev, 1, BM_WUC); /* * For PCH, this write will make sure that any noise will be detected * as a CRC error and be dropped rather than show up as a bad packet @@ -3390,6 +3450,11 @@ if (sc->sc_flags & WM_F_HAS_MII) wm_gmii_reset(sc); + 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) + CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_PHYPDEN); + /* Initialize the transmit descriptor ring. */ memset(sc->sc_txdescs, 0, WM_TXDESCSIZE(sc)); WM_CDTXSYNC(sc, 0, WM_NTXDESC(sc), @@ -4779,7 +4844,7 @@ case WM_T_82573: case WM_T_82574: case WM_T_82583: - /* XXX sould get sw semaphore, too */ + /* XXX should get sw semaphore, too */ rv = wm_get_swsm_semaphore(sc); break; case WM_T_80003: @@ -4874,11 +4939,6 @@ delay(100); CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); delay(150); - - /* Allow time for h/w to get to a quiescent state afer reset */ - delay(10*1000); - - /* XXX add code to set LED after phy reset */ break; default: panic("%s: %s: unknown type\n", device_xname(sc->sc_dev), @@ -4943,36 +5003,34 @@ case WM_T_ICH9: case WM_T_ICH10: case WM_T_PCH: + /* Allow time for h/w to get to a quiescent state afer reset */ delay(10*1000); if (sc->sc_type == WM_T_PCH) { - /* XXX hv_phy_workaround */ + wm_hv_phy_workaround_ich8lan(sc); - /* dummy read from WUC */ + /* + * dummy read to clear the phy wakeup bit after lcd + * reset + */ + reg = wm_gmii_hv_readreg(sc->sc_dev, 1, BM_WUC); } - /* XXX SW LCD configuration from NVM */ - if (sc->sc_type == WM_T_PCH) { - /* XXX Configure the LCD with the OEM bits in NVM */ + /* + * XXX Configure the LCD with th extended configuration region + * in NVM + */ -#if 1 - /* - * We shlould make the new driver for 8257[78] and - * move these code into it. - */ -#define HV_OEM_BITS ((0 << 5) | 25) -#define HV_OEM_BITS_LPLU (1 << 2) -#define HV_OEM_BITS_A1KDIS (1 << 6) -#define HV_OEM_BITS_ANEGNOW (1 << 10) -#endif + /* Configure the LCD with the OEM bits in NVM */ + if (sc->sc_type == WM_T_PCH) { /* * Disable LPLU. * XXX It seems that 82567 has LPLU, too. */ - reg = wm_gmii_kv_readreg(sc->sc_dev, 1, HV_OEM_BITS); + reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS); reg &= ~(HV_OEM_BITS_A1KDIS| HV_OEM_BITS_LPLU); reg |= HV_OEM_BITS_ANEGNOW; - wm_gmii_kv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg); + wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg); } break; default: @@ -5014,11 +5072,17 @@ switch (prodid) { case PCI_PRODUCT_INTEL_PCH_M_LM: case PCI_PRODUCT_INTEL_PCH_M_LC: + /* 82577 */ + sc->sc_phytype = WMPHY_82577; + sc->sc_mii.mii_readreg = wm_gmii_hv_readreg; + sc->sc_mii.mii_writereg = wm_gmii_hv_writereg; + break; case PCI_PRODUCT_INTEL_PCH_D_DM: case PCI_PRODUCT_INTEL_PCH_D_DC: - /* 82577 or 82578 */ - sc->sc_mii.mii_readreg = wm_gmii_kv_readreg; - sc->sc_mii.mii_writereg = wm_gmii_kv_writereg; + /* 82578 */ + sc->sc_phytype = WMPHY_82578; + 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: @@ -5027,6 +5091,7 @@ case PCI_PRODUCT_INTEL_82801J_D_BM_LF: case PCI_PRODUCT_INTEL_82801J_R_BM_V: /* 82567 */ + sc->sc_phytype = WMPHY_BM; sc->sc_mii.mii_readreg = wm_gmii_bm_readreg; sc->sc_mii.mii_writereg = wm_gmii_bm_writereg; break; @@ -5066,8 +5131,10 @@ if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL); ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE); - } else + sc->sc_phytype = WMPHY_NONE; + } else { ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); + } } /* @@ -5405,7 +5472,7 @@ return 0; } - if (reg > GG82563_MAX_REG_ADDRESS) { + if (reg > BME1000_MAX_MULTI_PAGE_REG) { if (phy == 1) wm_gmii_i82544_writereg(self, phy, 0x1f, reg); @@ -5439,7 +5506,7 @@ return; } - if (reg > GG82563_MAX_REG_ADDRESS) { + if (reg > BME1000_MAX_MULTI_PAGE_REG) { if (phy == 1) wm_gmii_i82544_writereg(self, phy, 0x1f, reg); @@ -5453,17 +5520,61 @@ wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM); } +static void +wm_access_phy_wakeup_reg_bm(device_t self, int offset, int16_t *val, int rd) +{ + struct wm_softc *sc = device_private(self); + uint16_t regnum = BM_PHY_REG_NUM(offset); + uint16_t wuce; + + /* XXX Gig must be disabled for MDIO accesses to page 800 */ + if (sc->sc_type == WM_T_PCH) { + /* XXX e1000 driver do nothing... why? */ + } + + /* Set page 769 */ + wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); + + wuce = wm_gmii_i82544_readreg(self, 1, BM_WUC_ENABLE_REG); + + wuce &= ~BM_WUC_HOST_WU_BIT; + wm_gmii_i82544_writereg(self, 1, BM_WUC_ENABLE_REG, + wuce | BM_WUC_ENABLE_BIT); + + /* Select page 800 */ + wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + BM_WUC_PAGE << BME1000_PAGE_SHIFT); + + /* Write page 800 */ + wm_gmii_i82544_writereg(self, 1, BM_WUC_ADDRESS_OPCODE, regnum); + + if (rd) + *val = wm_gmii_i82544_readreg(self, 1, BM_WUC_DATA_OPCODE); + else + wm_gmii_i82544_writereg(self, 1, BM_WUC_DATA_OPCODE, *val); + + /* Set page 769 */ + wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); + + wm_gmii_i82544_writereg(self, 1, BM_WUC_ENABLE_REG, wuce); +} + /* - * wm_gmii_kv_readreg: [mii interface function] + * 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_gmii_kv_readreg(device_t self, int phy, int reg) +wm_gmii_hv_readreg(device_t self, int phy, int reg) { struct wm_softc *sc = device_private(self); + uint16_t page = BM_PHY_REG_PAGE(reg); + uint16_t regnum = BM_PHY_REG_NUM(reg); + uint16_t val; int rv; if (wm_get_swfw_semaphore(sc, SWFW_PHY0_SM)) { @@ -5472,28 +5583,49 @@ return 0; } - if (reg > GG82563_MAX_REG_ADDRESS) { - printf("XXX rd pagesel\n"); + /* XXX Workaround failure in MDIO access while cable is disconnected */ + if (sc->sc_phytype == WMPHY_82577) { + /* XXX must write */ + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + wm_access_phy_wakeup_reg_bm(self, reg, &val, 1); + return val; + } + + /* + * Lower than page 768 works differently than the rest so it has its + * own func + */ + if ((page > 0) && (page < HV_INTC_FC_PAGE_START)) { + printf("gmii_hv_readreg!!!\n"); + return 0; + } + + if (regnum > BME1000_MAX_MULTI_PAGE_REG) { wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, - reg & IGPHY_PAGEMASK); + page << BME1000_PAGE_SHIFT); } - rv = wm_gmii_i82544_readreg(self, phy, reg & IGPHY_MAXREGADDR); + rv = wm_gmii_i82544_readreg(self, phy, regnum & IGPHY_MAXREGADDR); wm_put_swfw_semaphore(sc, SWFW_PHY0_SM); return (rv); } /* - * wm_gmii_kv_writereg: [mii interface function] + * 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_gmii_kv_writereg(device_t self, int phy, int reg, int val) +wm_gmii_hv_writereg(device_t self, int phy, int reg, int val) { struct wm_softc *sc = device_private(self); + uint16_t page = BM_PHY_REG_PAGE(reg); + uint16_t regnum = BM_PHY_REG_NUM(reg); if (wm_get_swfw_semaphore(sc, SWFW_PHY0_SM)) { aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", @@ -5501,13 +5633,37 @@ return; } - if (reg > GG82563_MAX_REG_ADDRESS) { - printf("XXX wr pagesel\n"); + /* XXX Workaround failure in MDIO access while cable is disconnected */ + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + uint16_t tmp; + + tmp = val; + wm_access_phy_wakeup_reg_bm(self, reg, &tmp, 0); + return; + } + + /* + * Lower than page 768 works differently than the rest so it has its + * own func + */ + if ((page > 0) && (page < HV_INTC_FC_PAGE_START)) { + printf("gmii_hv_writereg!!!\n"); + return; + } + + /* + * XXX Workaround MDIO accesses being disabled after entering IEEE + * Power Down (whenever bit 11 of the PHY control register is set) + */ + + if (regnum > BME1000_MAX_MULTI_PAGE_REG) { wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, - reg & IGPHY_PAGEMASK); + page << BME1000_PAGE_SHIFT); } - wm_gmii_i82544_writereg(self, phy, reg & IGPHY_MAXREGADDR, val); + wm_gmii_i82544_writereg(self, phy, regnum & IGPHY_MAXREGADDR, val); wm_put_swfw_semaphore(sc, SWFW_PHY0_SM); } @@ -6289,3 +6445,96 @@ return 0; } + +/* + * Workaround for pch's PHYs + * XXX should be moved to new PHY driver? + */ +static void +wm_hv_phy_workaround_ich8lan(struct wm_softc *sc) +{ + + /* (PCH rev.2) && (82577 && (phy rev 2 or 3)) */ + + /* (82577 && (phy rev 1 or 2)) || (82578 & phy rev 1)*/ + + /* 82578 */ + if (sc->sc_phytype == WMPHY_82578) { + /* PCH rev. < 3 */ + if (sc->sc_rev < 3) { + /* XXX 6 bit shift? Why? Is it page2? */ + wm_gmii_hv_writereg(sc->sc_dev, 1, ((1 << 6) | 0x29), + 0x66c0); + wm_gmii_hv_writereg(sc->sc_dev, 1, ((1 << 6) | 0x1e), + 0xffff); + } + + /* XXX phy rev. < 2 */ + } + + /* Select page 0 */ + + /* XXX acquire semaphore */ + wm_gmii_i82544_writereg(sc->sc_dev, 1, MII_IGPHY_PAGE_SELECT, 0); + /* XXX release semaphore */ + + /* + * Configure the K1 Si workaround during phy reset assuming there is + * link so that it disables K1 if link is in 1Gbps. + */ + wm_k1_gig_workaround_hv(sc, 1); +} + +static void +wm_k1_gig_workaround_hv(struct wm_softc *sc, int link) +{ + int k1_enable = sc->sc_nvm_k1_enabled; + + /* XXX acquire semaphore */ + + if (link) { + k1_enable = 0; + + /* Link stall fix for link up */ + wm_gmii_hv_writereg(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x0100); + } else { + /* Link stall fix for link down */ + wm_gmii_hv_writereg(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x4100); + } + + wm_configure_k1_ich8lan(sc, k1_enable); + + /* XXX release semaphore */ +} + +static void +wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable) +{ + uint32_t ctrl, ctrl_ext, tmp; + uint16_t kmrn_reg; + + kmrn_reg = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_K1_CONFIG); + + if (k1_enable) + kmrn_reg |= KUMCTRLSTA_K1_ENABLE; + else + kmrn_reg &= ~KUMCTRLSTA_K1_ENABLE; + + wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmrn_reg); + + delay(20); + + ctrl = CSR_READ(sc, WMREG_CTRL); + ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT); + + tmp = ctrl & ~(CTRL_SPEED_1000 | CTRL_SPEED_100); + tmp |= CTRL_FRCSPD; + + CSR_WRITE(sc, WMREG_CTRL, tmp); + CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext | CTRL_EXT_SPD_BYPS); + delay(20); + + CSR_WRITE(sc, WMREG_CTRL, ctrl); + CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext); + delay(20); +} Index: src/sys/dev/pci/if_wmreg.h diff -u src/sys/dev/pci/if_wmreg.h:1.34 src/sys/dev/pci/if_wmreg.h:1.35 --- src/sys/dev/pci/if_wmreg.h:1.34 Tue Jan 12 22:26:30 2010 +++ src/sys/dev/pci/if_wmreg.h Thu Jan 14 18:56:02 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmreg.h,v 1.34 2010/01/12 22:26:30 msaitoh Exp $ */ +/* $NetBSD: if_wmreg.h,v 1.35 2010/01/14 18:56:02 msaitoh Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -276,6 +276,7 @@ #define EEPROM_OFF_CFG1 0x0a /* config word 1 */ #define EEPROM_OFF_CFG2 0x0f /* config word 2 */ #define EEPROM_INIT_3GIO_3 0x1a /* PCIe Initial Configuration Word 3 */ +#define EEPROM_OFF_K1_CONFIG 0x1b /* NVM K1 Config */ #define EEPROM_OFF_SWDPIN 0x20 /* SWD Pins (Cordova) */ #define EEPROM_CFG1_LVDID (1U << 0) @@ -309,6 +310,8 @@ #define EEPROM_CFG2_SWDPIO_MASK (0xf << EEPROM_CFG2_SWDPIO_SHIFT) #define EEPROM_CFG2_MNGM_MASK (3U << 13) /* Manageability Operation mode */ +#define EEPROM_K1_CONFIG_ENABLE 0x01 + #define EEPROM_SWDPIN_MASK 0xdf #define EEPROM_SWDPIN_SWDPIN_SHIFT 0 #define EEPROM_SWDPIN_SWDPIO_SHIFT 8 @@ -340,6 +343,7 @@ #define CTRL_EXT_LINK_MODE_TBI 0x00C00000 #define CTRL_EXT_LINK_MODE_KMRN 0x00000000 #define CTRL_EXT_LINK_MODE_SERDES 0x00C00000 +#define CTRL_EXT_PHYPDEN 0x00100000 #define CTRL_EXT_DRV_LOAD 0x10000000 @@ -657,6 +661,7 @@ #define KUMCTRLSTA_OFFSET_INB_CTRL 0x00000002 #define KUMCTRLSTA_OFFSET_DIAG 0x00000003 #define KUMCTRLSTA_OFFSET_TIMEOUTS 0x00000004 +#define KUMCTRLSTA_OFFSET_K1_CONFIG 0x00000007 #define KUMCTRLSTA_OFFSET_INB_PARAM 0x00000009 #define KUMCTRLSTA_OFFSET_HD_CTRL 0x00000010 #define KUMCTRLSTA_OFFSET_M2P_SERDES 0x0000001E @@ -670,6 +675,9 @@ #define KUMCTRLSTA_INB_CTRL_LINK_TMOUT_DFLT 0x00000500 #define KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010 +/* K1 Config */ +#define KUMCTRLSTA_K1_ENABLE 0x0002 + /* Half-Duplex Control */ #define KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004 #define KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000 Index: src/sys/dev/pci/if_wmvar.h diff -u src/sys/dev/pci/if_wmvar.h:1.7 src/sys/dev/pci/if_wmvar.h:1.8 --- src/sys/dev/pci/if_wmvar.h:1.7 Mon Jan 11 12:29:28 2010 +++ src/sys/dev/pci/if_wmvar.h Thu Jan 14 18:56:02 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmvar.h,v 1.7 2010/01/11 12:29:28 msaitoh Exp $ */ +/* $NetBSD: if_wmvar.h,v 1.8 2010/01/14 18:56:02 msaitoh Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -114,6 +114,21 @@ WM_T_PCH, /* PCH LAN */ } wm_chip_type; +typedef enum { + WMPHY_UNKNOWN = 0, + WMPHY_NONE, + WMPHY_M88, + WMPHY_IGP, + WMPHY_IGP_2, + WMPHY_GG82563, + WMPHY_IGP_3, + WMPHY_IFE, + WMPHY_BM, + WMPHY_82578, + WMPHY_82577 +} wm_phy_type; + + #define WM_PHY_CFG_TIMEOUT 100 #define WM_ICH8_LAN_INIT_TIMEOUT 1500 #define WM_MDIO_OWNERSHIP_TIMEOUT 10 Added files: Index: src/sys/dev/mii/inbmphyreg.h diff -u /dev/null src/sys/dev/mii/inbmphyreg.h:1.1 --- /dev/null Thu Jan 14 18:56:02 2010 +++ src/sys/dev/mii/inbmphyreg.h Thu Jan 14 18:56:01 2010 @@ -0,0 +1,110 @@ +/* $NetBSD: inbmphyreg.h,v 1.1 2010/01/14 18:56:01 msaitoh Exp $ */ +/******************************************************************************* +Copyright (c) 2001-2005, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +/* + * Copied from the Intel code, and then modified to match NetBSD + * style for MII registers more. + */ + +#ifndef _DEV_MII_INBMPHYREG_H_ +#define _DEV_MII_INBMPHYREG_H_ + +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define BME1000_PAGE_SHIFT 5 +#define BME1000_REG(page, reg) \ + (((page) << BME1000_PAGE_SHIFT) | ((reg) & BME1000_MAX_REG_ADDRESS)) + +#define BME1000_MAX_REG_ADDRESS 0x1f /* 5 bit address bus (0-0x1f) */ +#define BME1000_MAX_MULTI_PAGE_REG 0xf /* Registers equal on all pages */ + +#define BM_PHY_REG_PAGE(offset) \ + ((uint16_t)(((offset) >> BME1000_PAGE_SHIFT) & 0xffff)) +#define BM_PHY_REG_NUM(offset) \ + ((uint16_t)((offset) & BME1000_MAX_REG_ADDRESS) \ + | (((offset) >> (21 - BME1000_PAGE_SHIFT)) & ~BME1000_MAX_REG_ADDRESS)) + +/* BME1000 Specific Registers */ +#define BME1000_PHY_SPEC_CTRL BME1000_REG(0, 16) /* PHY Specific Control */ +#define BME1000_PSCR_DISABLE_JABBER 0x0001 /* 1=Disable Jabber */ +#define BME1000_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Polarity Reversal Disabled */ +#define BME1000_PSCR_POWER_DOWN 0x0004 /* 1=Power Down */ +#define BME1000_PSCR_COPPER_TRANSMITER_DISABLE 0x0008 /* 1=Transmitter Disabled */ +#define BME1000_PSCR_CROSSOVER_MODE_MASK 0x0060 +#define BME1000_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI configuration */ +#define BME1000_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX configuration */ +#define BME1000_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Automatic crossover */ +#define BME1000_PSCR_ENALBE_EXTENDED_DISTANCE 0x0080 /* 1=Enable Extended Distance */ +#define BME1000_PSCR_ENERGY_DETECT_MASK 0x0300 +#define BME1000_PSCR_ENERGY_DETECT_OFF 0x0000 /* 00,01=Off */ +#define BME1000_PSCR_ENERGY_DETECT_RX 0x0200 /* 10=Sense on Rx only (Energy Detect) */ +#define BME1000_PSCR_ENERGY_DETECT_RX_TM 0x0300 /* 11=Sense and Tx NLP */ +#define BME1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force Link Good */ +#define BME1000_PSCR_DOWNSHIFT_ENABLE 0x0800 /* 1=Enable Downshift */ +#define BME1000_PSCR_DOWNSHIFT_COUNTER_MASK 0x7000 +#define BME1000_PSCR_DOWNSHIFT_COUNTER_SHIFT 12 + +#define BME1000_PHY_PAGE_SELECT BME1000_REG(0, 22) /* Page Select */ + +#define BME1000_BIAS_SETTING 29 +#define BME1000_BIAS_SETTING2 30 + +#define I82578_ADDR_REG 29 +#define I82577_ADDR_REG 16 +#define I82577_CFG_REG 22 + +#define HV_OEM_BITS BME1000_REG(0, 25) +#define HV_OEM_BITS_LPLU (1 << 2) +#define HV_OEM_BITS_A1KDIS (1 << 6) +#define HV_OEM_BITS_ANEGNOW (1 << 10) + +#define HV_INTC_FC_PAGE_START 768 +#define BM_PORT_CTRL_PAGE 769 + +#define IGP3_KMRN_DIAG BME1000_REG(770, 19) + +#define HV_MUX_DATA_CTRL BME1000_REG(776, 16) +#define HV_MUX_DATA_CTRL_FORCE_SPEED (1 << 2) +#define HV_MUX_DATA_CTRL_GEN_TO_MAC (1 << 10) + +#define BM_WUC_PAGE 800 +#define BM_WUC BME1000_REG(BM_WUC_PAGE, 1) +#define BM_WUC_ADDRESS_OPCODE 0x11 +#define BM_WUC_DATA_OPCODE 0x12 +#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE +#define BM_WUC_ENABLE_REG 17 +#define BM_WUC_ENABLE_BIT (1 << 2) +#define BM_WUC_HOST_WU_BIT (1 << 4) + +#endif /* _DEV_MII_INBMPHYREG_H_ */