Module Name: src
Committed By: msaitoh
Date: Wed Sep 3 14:30:04 UTC 2014
Modified Files:
src/sys/dev/pci: if_wm.c if_wmreg.h
Log Message:
Read SFF SFP ROM and configure driver from the value.
To generate a diff of this commit:
cvs rdiff -u -r1.294 -r1.295 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.62 -r1.63 src/sys/dev/pci/if_wmreg.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.294 src/sys/dev/pci/if_wm.c:1.295
--- src/sys/dev/pci/if_wm.c:1.294 Mon Sep 1 16:42:27 2014
+++ src/sys/dev/pci/if_wm.c Wed Sep 3 14:30:04 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.294 2014/09/01 16:42:27 msaitoh Exp $ */
+/* $NetBSD: if_wm.c,v 1.295 2014/09/03 14:30:04 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -82,7 +82,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.294 2014/09/01 16:42:27 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.295 2014/09/03 14:30:04 msaitoh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -624,7 +624,8 @@ static int wm_tbi_mediachange(struct ifn
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 *);
+static int wm_sfp_read_data_byte(struct wm_softc *, uint16_t, uint8_t *);
+static uint32_t wm_sfp_get_media_type(struct wm_softc *);
/*
* NVM related.
@@ -2075,7 +2076,7 @@ wm_attach(device_t parent, device_t self
aprint_verbose_dev(sc->sc_dev, "SGMII(I2C)\n");
/*FALLTHROUGH*/
case CTRL_EXT_LINK_MODE_PCIE_SERDES:
- sc->sc_mediatype = wm_get_sfp_media_type(sc);
+ sc->sc_mediatype = wm_sfp_get_media_type(sc);
if (sc->sc_mediatype == WMP_F_UNKNOWN) {
if (link_mode
== CTRL_EXT_LINK_MODE_SGMII) {
@@ -2110,6 +2111,7 @@ wm_attach(device_t parent, device_t self
break;
case CTRL_EXT_LINK_MODE_GMII:
default:
+ aprint_verbose_dev(sc->sc_dev, "Copper\n");
sc->sc_mediatype = WMP_F_COPPER;
break;
}
@@ -7578,12 +7580,91 @@ wm_tbi_check_link(struct wm_softc *sc)
}
/* SFP related */
+
+static int
+wm_sfp_read_data_byte(struct wm_softc *sc, uint16_t offset, uint8_t *data)
+{
+ uint32_t i2ccmd;
+ int i;
+
+ i2ccmd = (offset << I2CCMD_REG_ADDR_SHIFT) | I2CCMD_OPCODE_READ;
+ CSR_WRITE(sc, WMREG_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit */
+ for (i = 0; i < I2CCMD_PHY_TIMEOUT; i++) {
+ delay(50);
+ i2ccmd = CSR_READ(sc, WMREG_I2CCMD);
+ if (i2ccmd & I2CCMD_READY)
+ break;
+ }
+ if ((i2ccmd & I2CCMD_READY) == 0)
+ return -1;
+ if ((i2ccmd & I2CCMD_ERROR) != 0)
+ return -1;
+
+ *data = i2ccmd & 0x00ff;
+
+ return 0;
+}
+
static uint32_t
-wm_get_sfp_media_type(struct wm_softc *sc)
+wm_sfp_get_media_type(struct wm_softc *sc)
{
+ uint32_t ctrl_ext;
+ uint8_t val = 0;
+ int timeout = 3;
+ uint32_t mediatype = WMP_F_UNKNOWN;
+ int rv = -1;
- /* XXX */
- return WMP_F_SERDES;
+ ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+ ctrl_ext &= ~CTRL_EXT_SWDPIN(3);
+ CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext | CTRL_EXT_I2C_ENA);
+ CSR_WRITE_FLUSH(sc);
+
+ /* Read SFP module data */
+ while (timeout) {
+ rv = wm_sfp_read_data_byte(sc, SFF_SFP_ID_OFF, &val);
+ if (rv == 0)
+ break;
+ delay(100*1000); /* XXX too big */
+ timeout--;
+ }
+ if (rv != 0)
+ goto out;
+ switch (val) {
+ case SFF_SFP_ID_SFF:
+ aprint_normal_dev(sc->sc_dev,
+ "Module/Connector soldered to board\n");
+ break;
+ case SFF_SFP_ID_SFP:
+ aprint_normal_dev(sc->sc_dev, "SFP\n");
+ break;
+ case SFF_SFP_ID_UNKNOWN:
+ goto out;
+ default:
+ break;
+ }
+
+ rv = wm_sfp_read_data_byte(sc, SFF_SFP_ETH_FLAGS_OFF, &val);
+ if (rv != 0) {
+ goto out;
+ }
+
+ if ((val & (SFF_SFP_ETH_FLAGS_1000SX | SFF_SFP_ETH_FLAGS_1000LX)) != 0)
+ mediatype = WMP_F_SERDES;
+ else if ((val & SFF_SFP_ETH_FLAGS_1000T) != 0){
+ sc->sc_flags |= WM_F_SGMII;
+ mediatype = WMP_F_COPPER;
+ } else if ((val & SFF_SFP_ETH_FLAGS_100FX) != 0){
+ sc->sc_flags |= WM_F_SGMII;
+ mediatype = WMP_F_SERDES;
+ }
+
+out:
+ /* Restore I2C interface setting */
+ CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
+
+ return mediatype;
}
/*
* NVM related.
Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.62 src/sys/dev/pci/if_wmreg.h:1.63
--- src/sys/dev/pci/if_wmreg.h:1.62 Mon Sep 1 16:42:27 2014
+++ src/sys/dev/pci/if_wmreg.h Wed Sep 3 14:30:04 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmreg.h,v 1.62 2014/09/01 16:42:27 msaitoh Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.63 2014/09/03 14:30:04 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -1035,6 +1035,20 @@ struct livengood_tcpip_ctxdesc {
/* for PCI express Capability registers */
#define WM_PCIE_DCSR2_16MS 0x00000005
+/* SFF SFP ROM data */
+#define SFF_SFP_ID_OFF 0x00
+#define SFF_SFP_ID_UNKNOWN 0x00 /* Unknown */
+#define SFF_SFP_ID_SFF 0x02 /* Module soldered to motherboard */
+#define SFF_SFP_ID_SFP 0x03 /* SFP transceiver */
+
+#define SFF_SFP_ETH_FLAGS_OFF 0x06
+#define SFF_SFP_ETH_FLAGS_1000SX 0x01
+#define SFF_SFP_ETH_FLAGS_1000LX 0x02
+#define SFF_SFP_ETH_FLAGS_1000CX 0x04
+#define SFF_SFP_ETH_FLAGS_1000T 0x08
+#define SFF_SFP_ETH_FLAGS_100FX 0x10
+
+
/* advanced TX descriptor for 82575 and newer */
typedef union nq_txdesc {
struct {