summaryrefslogtreecommitdiffstats
path: root/sys/dev/mxge/if_mxge.c
diff options
context:
space:
mode:
authorgallatin <gallatin@FreeBSD.org>2010-04-15 13:50:55 +0000
committergallatin <gallatin@FreeBSD.org>2010-04-15 13:50:55 +0000
commita73efa73a4b812a828e3e15634abc1fd2137314b (patch)
tree480e0dbf9c01812f9f0cb58b12b18c860d857a01 /sys/dev/mxge/if_mxge.c
parent1f00f9ada8a046ee4db4a1aa486a9d5b6fc39998 (diff)
downloadFreeBSD-src-a73efa73a4b812a828e3e15634abc1fd2137314b.zip
FreeBSD-src-a73efa73a4b812a828e3e15634abc1fd2137314b.tar.gz
Cleanup if_media handling in mxge(4)
- Re-probe xfp / sfp+ socket on link events, in case user has changed transceiver - correctly report current media to avoid confusing lagg (reported by Panasas) - Report link speed (submitted by yongari) Reviewed by: yongari (earlier version) MFC after: 7 days
Diffstat (limited to 'sys/dev/mxge/if_mxge.c')
-rw-r--r--sys/dev/mxge/if_mxge.c115
1 files changed, 71 insertions, 44 deletions
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index d7f5825..50c9af6 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -883,6 +883,9 @@ mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data)
case MXGEFW_CMD_ERROR_BUSY:
err = EBUSY;
break;
+ case MXGEFW_CMD_ERROR_I2C_ABSENT:
+ err = ENXIO;
+ break;
default:
device_printf(sc->dev,
"mxge: command %d "
@@ -2782,37 +2785,25 @@ static struct mxge_media_type mxge_sfp_media_types[] =
};
static void
-mxge_set_media(mxge_softc_t *sc, int type)
+mxge_media_set(mxge_softc_t *sc, int media_type)
{
- sc->media_flags |= type;
- ifmedia_add(&sc->media, sc->media_flags, 0, NULL);
- ifmedia_set(&sc->media, sc->media_flags);
-}
+
+ ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | media_type,
+ 0, NULL);
+ ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | media_type);
+ sc->current_media = media_type;
+ sc->media.ifm_media = sc->media.ifm_cur->ifm_media;
+}
-/*
- * Determine the media type for a NIC. Some XFPs will identify
- * themselves only when their link is up, so this is initiated via a
- * link up interrupt. However, this can potentially take up to
- * several milliseconds, so it is run via the watchdog routine, rather
- * than in the interrupt handler itself. This need only be done
- * once, not each time the link is up.
- */
static void
-mxge_media_probe(mxge_softc_t *sc)
+mxge_media_init(mxge_softc_t *sc)
{
- mxge_cmd_t cmd;
- char *cage_type;
char *ptr;
- struct mxge_media_type *mxge_media_types = NULL;
- int i, err, ms, mxge_media_type_entries;
- uint32_t byte;
-
- sc->need_media_probe = 0;
+ int i;
- /* if we've already set a media type, we're done */
- if (sc->media_flags != (IFM_ETHER | IFM_AUTO))
- return;
+ ifmedia_removeall(&sc->media);
+ mxge_media_set(sc, IFM_AUTO);
/*
* parse the product code to deterimine the interface type
@@ -2823,6 +2814,7 @@ mxge_media_probe(mxge_softc_t *sc)
ptr = sc->product_code_string;
if (ptr == NULL) {
device_printf(sc->dev, "Missing product code\n");
+ return;
}
for (i = 0; i < 3; i++, ptr++) {
@@ -2835,17 +2827,44 @@ mxge_media_probe(mxge_softc_t *sc)
}
if (*ptr == 'C') {
/* -C is CX4 */
- mxge_set_media(sc, IFM_10G_CX4);
- return;
- }
- else if (*ptr == 'Q') {
+ sc->connector = MXGE_CX4;
+ mxge_media_set(sc, IFM_10G_CX4);
+ } else if (*ptr == 'Q') {
/* -Q is Quad Ribbon Fiber */
+ sc->connector = MXGE_QRF;
device_printf(sc->dev, "Quad Ribbon Fiber Media\n");
/* FreeBSD has no media type for Quad ribbon fiber */
- return;
+ } else if (*ptr == 'R') {
+ /* -R is XFP */
+ sc->connector = MXGE_XFP;
+ } else if (*ptr == 'S' || *(ptr +1) == 'S') {
+ /* -S or -2S is SFP+ */
+ sc->connector = MXGE_SFP;
+ } else {
+ device_printf(sc->dev, "Unknown media type: %c\n", *ptr);
}
+}
- if (*ptr == 'R') {
+/*
+ * Determine the media type for a NIC. Some XFPs will identify
+ * themselves only when their link is up, so this is initiated via a
+ * link up interrupt. However, this can potentially take up to
+ * several milliseconds, so it is run via the watchdog routine, rather
+ * than in the interrupt handler itself.
+ */
+static void
+mxge_media_probe(mxge_softc_t *sc)
+{
+ mxge_cmd_t cmd;
+ char *cage_type;
+
+ struct mxge_media_type *mxge_media_types = NULL;
+ int i, err, ms, mxge_media_type_entries;
+ uint32_t byte;
+
+ sc->need_media_probe = 0;
+
+ if (sc->connector == MXGE_XFP) {
/* -R is XFP */
mxge_media_types = mxge_xfp_media_types;
mxge_media_type_entries =
@@ -2853,9 +2872,7 @@ mxge_media_probe(mxge_softc_t *sc)
sizeof (mxge_xfp_media_types[0]);
byte = MXGE_XFP_COMPLIANCE_BYTE;
cage_type = "XFP";
- }
-
- if (*ptr == 'S' || *(ptr +1) == 'S') {
+ } else if (sc->connector == MXGE_SFP) {
/* -S or -2S is SFP+ */
mxge_media_types = mxge_sfp_media_types;
mxge_media_type_entries =
@@ -2863,10 +2880,8 @@ mxge_media_probe(mxge_softc_t *sc)
sizeof (mxge_sfp_media_types[0]);
cage_type = "SFP+";
byte = 3;
- }
-
- if (mxge_media_types == NULL) {
- device_printf(sc->dev, "Unknown media type: %c\n", *ptr);
+ } else {
+ /* nothing to do; media type cannot change */
return;
}
@@ -2909,7 +2924,10 @@ mxge_media_probe(mxge_softc_t *sc)
if (mxge_verbose)
device_printf(sc->dev, "%s:%s\n", cage_type,
mxge_media_types[0].name);
- mxge_set_media(sc, mxge_media_types[0].flag);
+ if (sc->current_media != mxge_media_types[0].flag) {
+ mxge_media_init(sc);
+ mxge_media_set(sc, mxge_media_types[0].flag);
+ }
return;
}
for (i = 1; i < mxge_media_type_entries; i++) {
@@ -2919,12 +2937,16 @@ mxge_media_probe(mxge_softc_t *sc)
cage_type,
mxge_media_types[i].name);
- mxge_set_media(sc, mxge_media_types[i].flag);
+ if (sc->current_media != mxge_media_types[i].flag) {
+ mxge_media_init(sc);
+ mxge_media_set(sc, mxge_media_types[i].flag);
+ }
return;
}
}
- device_printf(sc->dev, "%s media 0x%x unknown\n", cage_type,
- cmd.data0);
+ if (mxge_verbose)
+ device_printf(sc->dev, "%s media 0x%x unknown\n",
+ cage_type, cmd.data0);
return;
}
@@ -2988,10 +3010,12 @@ mxge_intr(void *arg)
sc->link_state = stats->link_up;
if (sc->link_state) {
if_link_state_change(sc->ifp, LINK_STATE_UP);
+ sc->ifp->if_baudrate = IF_Gbps(10UL);
if (mxge_verbose)
device_printf(sc->dev, "link up\n");
} else {
if_link_state_change(sc->ifp, LINK_STATE_DOWN);
+ sc->ifp->if_baudrate = 0;
if (mxge_verbose)
device_printf(sc->dev, "link down\n");
}
@@ -4026,9 +4050,9 @@ mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
if (sc == NULL)
return;
ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER | IFM_FDX;
ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0;
- ifmr->ifm_active = IFM_AUTO | IFM_ETHER;
- ifmr->ifm_active |= sc->link_state ? IFM_FDX : 0;
+ ifmr->ifm_active |= sc->current_media;
}
static int
@@ -4135,6 +4159,9 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
case SIOCGIFMEDIA:
+ mtx_lock(&sc->driver_mtx);
+ mxge_media_probe(sc);
+ mtx_unlock(&sc->driver_mtx);
err = ifmedia_ioctl(ifp, (struct ifreq *)data,
&sc->media, command);
break;
@@ -4766,7 +4793,7 @@ mxge_attach(device_t dev)
/* Initialise the ifmedia structure */
ifmedia_init(&sc->media, 0, mxge_media_change,
mxge_media_status);
- mxge_set_media(sc, IFM_ETHER | IFM_AUTO);
+ mxge_media_init(sc);
mxge_media_probe(sc);
sc->dying = 0;
ether_ifattach(ifp, sc->mac_addr);
OpenPOWER on IntegriCloud