summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authormsaitoh <msaitoh@NetBSD.org>2013-12-29 21:28:41 +0000
committermsaitoh <msaitoh@NetBSD.org>2013-12-29 21:28:41 +0000
commit0e28c724e08d4431a6b97c082ebcc4cea93152ad (patch)
tree096de44e785243aa151e1e6affd62c46f5126d6c /sys/dev
parenta4658b140dc12241245abb92d8fac75dd5f764a4 (diff)
Add support For I354(C2000 interna Ethernet controller):
- Add I354 support. - Fix SGMII+MDIO case. SGMII+I2C is not supported yet. - Not tested well. - Sprinkle "XXX" to check later.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_wm.c187
-rw-r--r--sys/dev/pci/if_wmreg.h11
-rw-r--r--sys/dev/pci/if_wmvar.h3
3 files changed, 164 insertions, 37 deletions
diff --git a/sys/dev/pci/if_wm.c b/sys/dev/pci/if_wm.c
index 7ce73fdb603..5bb652f7e4a 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.264 2013/09/13 21:22:10 martin Exp $ */
+/* $NetBSD: if_wm.c,v 1.265 2013/12/29 21:28:41 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.264 2013/09/13 21:22:10 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.265 2013/12/29 21:28:41 msaitoh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -543,11 +543,13 @@ static int wm_gmii_hv_readreg(device_t, int, int);
static void wm_gmii_hv_writereg(device_t, int, int, int);
static int wm_gmii_82580_readreg(device_t, int, int);
static void wm_gmii_82580_writereg(device_t, int, int, int);
+static bool wm_sgmii_uses_mdio(struct wm_softc *);
static int wm_sgmii_readreg(device_t, int, int);
static void wm_sgmii_writereg(device_t, int, int, int);
static void wm_gmii_statchg(struct ifnet *);
+static int wm_get_phy_id_82575(struct wm_softc *);
static void wm_gmii_mediainit(struct wm_softc *, pci_product_id_t);
static int wm_gmii_mediachange(struct ifnet *);
static void wm_gmii_mediastatus(struct ifnet *, struct ifmediareq *);
@@ -1024,6 +1026,9 @@ static const struct wm_product {
"I350 Gigabit Connection",
WM_T_I350, WMP_F_1000T },
#endif
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C2000_SGMII,
+ "I354 Gigabit Connection",
+ WM_T_I354, WMP_F_1000T },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I210_T1,
"I210-T1 Ethernet Server Adapter",
WM_T_I210, WMP_F_1000T },
@@ -1210,8 +1215,8 @@ wm_attach(device_t parent, device_t self, void *aux)
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_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
- || (sc->sc_type == WM_T_I211))
+ || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)
+ || (sc->sc_type == WM_T_I210) || (sc->sc_type == WM_T_I211))
sc->sc_flags |= WM_F_NEWQUEUE;
/* Set device properties (mactype) */
@@ -1326,7 +1331,7 @@ wm_attach(device_t parent, device_t self, void *aux)
|| (sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_80003)
|| (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_type == WM_T_I350))
+ || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
sc->sc_funcid = (CSR_READ(sc, WMREG_STATUS)
>> STATUS_FUNCID_SHIFT) & STATUS_FUNCID_MASK;
else
@@ -1597,6 +1602,7 @@ wm_attach(device_t parent, device_t self, void *aux)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354: /* XXXX ok? */
case WM_T_80003:
/* SPI */
wm_set_spiaddrbits(sc);
@@ -1771,6 +1777,7 @@ wm_attach(device_t parent, device_t self, void *aux)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354: /* XXX ok? */
case WM_T_ICH8:
case WM_T_ICH9:
case WM_T_ICH10:
@@ -1897,20 +1904,30 @@ wm_attach(device_t parent, device_t self, void *aux)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
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;
+ 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);
- wm_gmii_mediainit(sc, wmp->wmp_product);
+ panic("not supported yet\n");
break;
- case CTRL_EXT_LINK_MODE_1000KX:
+ 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);
+ break;
+ }
+ aprint_verbose_dev(sc->sc_dev, "SGMII(I2C)\n");
+ /*FALLTHROUGH*/
case CTRL_EXT_LINK_MODE_PCIE_SERDES:
- aprint_verbose_dev(sc->sc_dev, "1000KX or SERDES\n");
+ aprint_verbose_dev(sc->sc_dev, "SERDES\n");
CSR_WRITE(sc, WMREG_CTRL_EXT,
reg | CTRL_EXT_I2C_ENA);
panic("not supported yet\n");
@@ -1963,6 +1980,7 @@ wm_attach(device_t parent, device_t self, void *aux)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354: /* XXXX ok? */
case WM_T_I210:
case WM_T_I211:
case WM_T_80003:
@@ -3706,7 +3724,8 @@ wm_rxintr(struct wm_softc *sc)
* For an eratta, the RCTL_SECRC bit in RCTL register
* is always set in I350, so we don't trim it.
*/
- if ((sc->sc_type != WM_T_I350) && (sc->sc_type != WM_T_I210)
+ if ((sc->sc_type != WM_T_I350) && (sc->sc_type != WM_T_I354)
+ && (sc->sc_type != WM_T_I210)
&& (sc->sc_type != WM_T_I211)) {
if (m->m_len < ETHER_CRC_LEN) {
sc->sc_rxtail->m_len
@@ -3757,6 +3776,7 @@ wm_rxintr(struct wm_softc *sc)
* If VLANs are enabled, VLAN packets have been unwrapped
* for us. Associate the tag with the packet.
*/
+ /* XXXX should check for i350 and i354 */
if ((status & WRX_ST_VP) != 0) {
VLAN_INPUT_TAG(ifp, m,
le16toh(vlantag),
@@ -4039,6 +4059,7 @@ wm_reset(struct wm_softc *sc)
case WM_T_82572:
case WM_T_82575: /* XXX need special handing for jumbo frames */
case WM_T_I350:
+ case WM_T_I354:
case WM_T_80003:
sc->sc_pba = PBA_32K;
break;
@@ -4097,7 +4118,7 @@ wm_reset(struct wm_softc *sc)
/* Set the completion timeout for interface */
if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
- || (sc->sc_type == WM_T_I350))
+ || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
wm_set_pcie_completion_timeout(sc);
/* Clear interrupt */
@@ -4210,6 +4231,7 @@ wm_reset(struct wm_softc *sc)
case WM_T_82580ER:
case WM_T_82583:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
default:
@@ -4282,6 +4304,7 @@ wm_reset(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
case WM_T_80003:
@@ -4308,6 +4331,7 @@ wm_reset(struct wm_softc *sc)
case WM_T_82580ER:
#endif
case WM_T_I350:
+ case WM_T_I354:
case WM_T_ICH8:
case WM_T_ICH9:
if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) {
@@ -4317,7 +4341,8 @@ wm_reset(struct wm_softc *sc)
|| (sc->sc_type == WM_T_82576)
|| (sc->sc_type == WM_T_82580)
|| (sc->sc_type == WM_T_82580ER)
- || (sc->sc_type == WM_T_I350))
+ || (sc->sc_type == WM_T_I350)
+ || (sc->sc_type == WM_T_I354))
wm_reset_init_script_82575(sc);
}
break;
@@ -4326,7 +4351,7 @@ wm_reset(struct wm_softc *sc)
}
if ((sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)
- || (sc->sc_type == WM_T_I350)) {
+ || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) {
/* clear global device reset status bit */
CSR_WRITE(sc, WMREG_STATUS, STATUS_DEV_RST_SET);
}
@@ -4562,7 +4587,7 @@ wm_init(struct ifnet *ifp)
* Clear out the VLAN table -- we don't use it (yet).
*/
CSR_WRITE(sc, WMREG_VET, 0);
- if (sc->sc_type == WM_T_I350)
+ if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
trynum = 10; /* Due to hw errata */
else
trynum = 1;
@@ -4761,7 +4786,8 @@ wm_init(struct ifnet *ifp)
* The I350 has a bug where it always strips the CRC whether
* asked to or not. So ask for stripped CRC here and cope in rxeof
*/
- if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210))
+ if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)
+ || (sc->sc_type == WM_T_I210))
sc->sc_rctl |= RCTL_SECRC;
if (((sc->sc_ethercom.ec_capabilities & ETHERCAP_JUMBO_MTU) != 0)
@@ -4940,6 +4966,7 @@ wm_get_auto_rd_done(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
case WM_T_80003:
@@ -5031,6 +5058,7 @@ wm_get_cfg_done(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
if (sc->sc_type == WM_T_82571) {
@@ -5532,6 +5560,7 @@ wm_read_mac_addr(struct wm_softc *sc, uint8_t *enaddr)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
switch (sc->sc_funcid) {
case 0:
/* default value (== EEPROM_OFF_MACADDR) */
@@ -5773,7 +5802,7 @@ wm_set_filter(struct wm_softc *sc)
size = WM_RAL_TABSIZE_82575;
else if ((sc->sc_type == WM_T_82576) || (sc->sc_type == WM_T_82580))
size = WM_RAL_TABSIZE_82576;
- else if (sc->sc_type == WM_T_I350)
+ else if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354))
size = WM_RAL_TABSIZE_I350;
else
size = WM_RAL_TABSIZE;
@@ -6155,6 +6184,7 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
case WM_T_80003:
@@ -6229,6 +6259,7 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
case WM_T_82583:
@@ -6280,6 +6311,7 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
case WM_T_80003:
@@ -6324,6 +6356,7 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
case WM_T_I210:
case WM_T_I211:
case WM_T_82583:
@@ -6382,6 +6415,45 @@ wm_gmii_reset(struct wm_softc *sc)
}
/*
+ * wm_get_phy_id_82575:
+ *
+ * Return PHY ID. Return -1 if it failed.
+ */
+static int
+wm_get_phy_id_82575(struct wm_softc *sc)
+{
+ uint32_t reg;
+ int phyid = -1;
+
+ /* XXX */
+ if ((sc->sc_flags & WM_F_SGMII) == 0)
+ return -1;
+
+ if (wm_sgmii_uses_mdio(sc)) {
+ switch (sc->sc_type) {
+ case WM_T_82575:
+ case WM_T_82576:
+ reg = CSR_READ(sc, WMREG_MDIC);
+ phyid = (reg & MDIC_PHY_MASK) >> MDIC_PHY_SHIFT;
+ break;
+ case WM_T_82580:
+ case WM_T_I350:
+ case WM_T_I354:
+ case WM_T_I210:
+ case WM_T_I211:
+ reg = CSR_READ(sc, WMREG_MDICNFG);
+ phyid = (reg & MDICNFG_PHY_MASK) >> MDICNFG_PHY_SHIFT;
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ return phyid;
+}
+
+
+/*
* wm_gmii_mediainit:
*
* Initialize media for use on 1000BASE-T devices.
@@ -6467,7 +6539,8 @@ wm_gmii_mediainit(struct wm_softc *sc, pci_product_id_t prodid)
mii->mii_writereg = wm_gmii_bm_writereg;
break;
default:
- if ((sc->sc_flags & WM_F_SGMII) != 0) {
+ if (((sc->sc_flags & WM_F_SGMII) != 0)
+ && !wm_sgmii_uses_mdio(sc)){
mii->mii_readreg = wm_sgmii_readreg;
mii->mii_writereg = wm_sgmii_writereg;
} else if (sc->sc_type >= WM_T_80003) {
@@ -6499,30 +6572,39 @@ wm_gmii_mediainit(struct wm_softc *sc, pci_product_id_t prodid)
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_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
- || (sc->sc_type == WM_T_I211)) {
+ || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)
+ || (sc->sc_type == WM_T_I210) || (sc->sc_type == WM_T_I211)) {
if ((sc->sc_flags & WM_F_SGMII) == 0) {
/* Attach only one port */
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, 1,
MII_OFFSET_ANY, MIIF_DOPAUSE);
} else {
- int i;
+ int i, id;
uint32_t ctrl_ext;
- /* Power on sgmii phy if it is disabled */
- ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
- CSR_WRITE(sc, WMREG_CTRL_EXT,
- ctrl_ext &~ CTRL_EXT_SWDPIN(3));
- CSR_WRITE_FLUSH(sc);
- delay(300*1000); /* XXX too long */
-
- /* from 1 to 8 */
- for (i = 1; i < 8; i++)
+ id = wm_get_phy_id_82575(sc);
+ if (id != -1) {
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff,
- i, MII_OFFSET_ANY, MIIF_DOPAUSE);
-
- /* restore previous sfp cage power state */
- CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
+ id, MII_OFFSET_ANY, MIIF_DOPAUSE);
+ }
+ if ((id == -1)
+ || (LIST_FIRST(&mii->mii_phys) == NULL)) {
+ /* Power on sgmii phy if it is disabled */
+ ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+ CSR_WRITE(sc, WMREG_CTRL_EXT,
+ ctrl_ext &~ CTRL_EXT_SWDPIN(3));
+ CSR_WRITE_FLUSH(sc);
+ delay(300*1000); /* XXX too long */
+
+ /* from 1 to 8 */
+ for (i = 1; i < 8; i++)
+ mii_attach(sc->sc_dev, &sc->sc_mii,
+ 0xffffffff, i, MII_OFFSET_ANY,
+ MIIF_DOPAUSE);
+
+ /* restore previous sfp cage power state */
+ CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
+ }
}
} else {
mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
@@ -7114,6 +7196,40 @@ wm_gmii_hv_writereg(device_t self, int phy, int reg, int val)
}
/*
+ * wm_sgmii_uses_mdio
+ *
+ * Check whether the transaction is to the internal PHY or the external
+ * MDIO interface. Return true if it's MDIO.
+ */
+static bool
+wm_sgmii_uses_mdio(struct wm_softc *sc)
+{
+ uint32_t reg;
+ bool ismdio = false;
+
+ switch (sc->sc_type) {
+ case WM_T_82575:
+ case WM_T_82576:
+ reg = CSR_READ(sc, WMREG_MDIC);
+ ismdio = ((reg & MDIC_DEST) != 0);
+ break;
+ case WM_T_82580:
+ case WM_T_82580ER:
+ case WM_T_I350:
+ case WM_T_I354:
+ case WM_T_I210:
+ case WM_T_I211:
+ reg = CSR_READ(sc, WMREG_MDICNFG);
+ ismdio = ((reg & MDICNFG_DEST) != 0);
+ break;
+ default:
+ break;
+ }
+
+ return ismdio;
+}
+
+/*
* wm_sgmii_readreg: [mii interface function]
*
* Read a PHY register on the SGMII
@@ -8512,6 +8628,7 @@ wm_get_wakeup(struct wm_softc *sc)
case WM_T_82580:
case WM_T_82580ER:
case WM_T_I350:
+ case WM_T_I354:
if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE_MASK) != 0)
sc->sc_flags |= WM_F_ARC_SUBSYS_VALID;
sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;
diff --git a/sys/dev/pci/if_wmreg.h b/sys/dev/pci/if_wmreg.h
index 1bf9fc64055..14d402389d3 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.54 2013/06/25 17:38:38 msaitoh Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.55 2013/12/29 21:28:41 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -417,12 +417,15 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_MDIC 0x0020 /* MDI Control Register */
#define MDIC_DATA(x) ((x) & 0xffff)
#define MDIC_REGADD(x) ((x) << 16)
+#define MDIC_PHY_SHIFT 21
+#define MDIC_PHY_MASK __BITS(25, 21)
#define MDIC_PHYADD(x) ((x) << 21)
#define MDIC_OP_WRITE (1U << 26)
#define MDIC_OP_READ (2U << 26)
#define MDIC_READY (1U << 28)
#define MDIC_I (1U << 29) /* interrupt on MDI complete */
#define MDIC_E (1U << 30) /* MDI error */
+#define MDIC_DEST (1U << 31) /* Destination */
#define WMREG_SCTL 0x0024 /* SerDes Control - RW */
/*
@@ -705,6 +708,12 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_VFTA 0x0600
+#define WMREG_MDICNFG 0x0e04 /* MDC/MDIO Configuration Register */
+#define MDICNFG_PHY_SHIFT 21
+#define MDICNFG_PHY_MASK __BITS(25, 21)
+#define MDICNFG_COM_MDIO __BIT(30)
+#define MDICNFG_DEST __BIT(31)
+
#define WM_MC_TABSIZE 128
#define WM_ICH8_MC_TABSIZE 32
#define WM_VLAN_TABSIZE 128
diff --git a/sys/dev/pci/if_wmvar.h b/sys/dev/pci/if_wmvar.h
index ca2c7cff881..2f18361f973 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.16 2013/06/02 09:36:22 msaitoh Exp $ */
+/* $NetBSD: if_wmvar.h,v 1.17 2013/12/29 21:28:41 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -121,6 +121,7 @@ typedef enum {
WM_T_82580, /* i82580 */
WM_T_82580ER, /* i82580ER */
WM_T_I350, /* I350 */
+ WM_T_I354, /* I354 */
WM_T_I210, /* I210 */
WM_T_I211, /* I211 */
WM_T_80003, /* i80003 */