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_ */