Author: gallatin
Date: Thu Apr 15 13:50:55 2010
New Revision: 206662
URL: http://svn.freebsd.org/changeset/base/206662

Log:
  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

Modified:
  head/sys/dev/mxge/if_mxge.c
  head/sys/dev/mxge/if_mxge_var.h

Modified: head/sys/dev/mxge/if_mxge.c
==============================================================================
--- head/sys/dev/mxge/if_mxge.c Thu Apr 15 12:46:16 2010        (r206661)
+++ head/sys/dev/mxge/if_mxge.c Thu Apr 15 13:50:55 2010        (r206662)
@@ -883,6 +883,9 @@ mxge_send_cmd(mxge_softc_t *sc, uint32_t
                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_m
 };
 
 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, str
        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 com
                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);

Modified: head/sys/dev/mxge/if_mxge_var.h
==============================================================================
--- head/sys/dev/mxge/if_mxge_var.h     Thu Apr 15 12:46:16 2010        
(r206661)
+++ head/sys/dev/mxge/if_mxge_var.h     Thu Apr 15 13:50:55 2010        
(r206662)
@@ -268,6 +268,8 @@ struct mxge_softc {
        int num_slices;
        int rx_ring_size;
        int dying;
+       int connector;
+       int current_media;
        mxge_dma_t dmabench_dma;
        struct callout co_hdl;
        struct taskqueue *tq;
@@ -293,6 +295,12 @@ struct mxge_softc {
 #define MXGE_MIN_THROTTLE      416
 #define MXGE_MAX_THROTTLE      4096
 
+/* Types of connectors on NICs supported by this driver */
+#define MXGE_CX4 0
+#define MXGE_XFP 1
+#define MXGE_SFP 2
+#define MXGE_QRF 3
+
 #define MXGE_HIGHPART_TO_U32(X) \
 (sizeof (X) == 8) ? ((uint32_t)((uint64_t)(X) >> 32)) : (0)
 #define MXGE_LOWPART_TO_U32(X) ((uint32_t)(X))
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to