Author: gnn
Date: Thu Dec 18 14:21:35 2008
New Revision: 186282
URL: http://svn.freebsd.org/changeset/base/186282

Log:
  Check in the actual module recognition code for the Chelsio
  driver.
  
  Obtained from:        Chelsio Inc.

Modified:
  head/sys/dev/cxgb/common/cxgb_ael1002.c
  head/sys/dev/cxgb/cxgb_main.c

Modified: head/sys/dev/cxgb/common/cxgb_ael1002.c
==============================================================================
--- head/sys/dev/cxgb/common/cxgb_ael1002.c     Thu Dec 18 14:21:06 2008        
(r186281)
+++ head/sys/dev/cxgb/common/cxgb_ael1002.c     Thu Dec 18 14:21:35 2008        
(r186282)
@@ -71,6 +71,74 @@ struct reg_val {
        unsigned short set_bits;
 };
 
+static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr);
+
+static int get_module_type (struct cphy *phy, int hint)
+{
+       int v;
+
+       v = hint ? hint : ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0);
+       if (v < 0)
+               return v;
+
+       if (v == 0x3) {
+               /* SFP: see SFF-8472 for below */
+               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3);
+               if (v < 0)
+                       return v;
+
+               if (v == 0x1)
+                       return phy_modtype_twinax;
+               if (v == 0x10)
+                       return phy_modtype_sr;
+               if (v == 0x20)
+                       return phy_modtype_lr;
+               if (v == 0x40)
+                       return phy_modtype_lrm;
+
+               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6);
+               if (v < 0)
+                       return v;
+               if (v != 4)
+                       return phy_modtype_unknown;
+
+               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10);
+               if (v < 0)
+                       return v;
+
+               if (v & 0x80) {
+                       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
+                       if (v < 0)
+                               return v;
+                       return v > 10 ? phy_modtype_twinax_long :
+                           phy_modtype_twinax;
+               }
+       } else if (v == 0x6) {
+               /* XFP: See INF-8077i for details. */
+
+               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 127);
+               if (v < 0)
+                       return v;
+
+               if (v != 1) {
+                       /* XXX: set page select to table 1 yourself */
+                       return phy_modtype_unknown;
+               }
+
+               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 131);
+               if (v < 0)
+                       return v;
+               if (v == 0x10)
+                       return phy_modtype_lrm;
+               if (v == 0x40)
+                       return phy_modtype_lr;
+               if (v == 0x80)
+                       return phy_modtype_sr;
+       }
+
+       return phy_modtype_unknown;
+}
+
 static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
 {
        int err;
@@ -107,6 +175,18 @@ static int ael1002_power_down(struct cph
        return err;
 }
 
+static int ael1002_get_module_type(struct cphy *phy, int delay_ms)
+{
+       int v;
+
+       if (delay_ms)
+               msleep(delay_ms);
+
+       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0);
+
+       return v == -ETIMEDOUT ? phy_modtype_none : get_module_type(phy, v);
+}
+
 static int ael1002_reset(struct cphy *phy, int wait)
 {
        int err;
@@ -119,6 +199,11 @@ static int ael1002_reset(struct cphy *ph
            (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
                                       0, 1 << 5)))
                return err;
+
+       err = ael1002_get_module_type(phy, 300);
+       if (err >= 0)
+               phy->modtype = err;
+
        return 0;
 }
 
@@ -182,10 +267,17 @@ static struct cphy_ops ael1002_ops = {
 int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
                        const struct mdio_ops *mdio_ops)
 {
+       int err;
+
        cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
                  "10GBASE-R");
        ael100x_txon(phy);
+
+       err = ael1002_get_module_type(phy, 0);
+       if (err >= 0)
+               phy->modtype = err;
+
        return 0;
 }
 
@@ -983,7 +1075,7 @@ static int ael2005_i2c_rd(struct cphy *p
        return -ETIMEDOUT;
 }
 
-static int get_module_type(struct cphy *phy, int delay_ms)
+static int ael2005_get_module_type(struct cphy *phy, int delay_ms)
 {
        int v;
        unsigned int stat;
@@ -998,36 +1090,8 @@ static int get_module_type(struct cphy *
        if (delay_ms)
                msleep(delay_ms);
 
-       /* see SFF-8472 for below */
-       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3);
-       if (v < 0)
-               return v;
-
-       if (v == 0x10)
-               return phy_modtype_sr;
-       if (v == 0x20)
-               return phy_modtype_lr;
-       if (v == 0x40)
-               return phy_modtype_lrm;
-
-       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6);
-       if (v < 0)
-               return v;
-       if (v != 4)
-               goto unknown;
-
-       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10);
-       if (v < 0)
-               return v;
+       return get_module_type(phy, 0);
 
-       if (v & 0x80) {
-               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
-               if (v < 0)
-                       return v;
-               return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
-       }
-unknown:
-       return phy_modtype_unknown;
 }
 
 static int ael2005_intr_enable(struct cphy *phy)
@@ -1084,7 +1148,7 @@ static int ael2005_reset(struct cphy *ph
 
        msleep(50);
 
-       err = get_module_type(phy, 0);
+       err = ael2005_get_module_type(phy, 0);
        if (err < 0)
                return err;
        phy->modtype = (u8)err;
@@ -1122,7 +1186,7 @@ static int ael2005_intr_handler(struct c
                        return ret;
 
                /* modules have max 300 ms init time after hot plug */
-               ret = get_module_type(phy, 300);
+               ret = ael2005_get_module_type(phy, 300);
                if (ret < 0)
                        return ret;
 
@@ -1176,10 +1240,16 @@ static struct cphy_ops ael2005_ops = {
 int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
                        const struct mdio_ops *mdio_ops)
 {
+       int err;
        cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
                  SUPPORTED_IRQ, "10GBASE-R");
        msleep(125);
+
+       err = ael2005_get_module_type(phy, 0);
+       if (err >= 0)
+               phy->modtype = err;
+
        return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0,
                                   1 << 5);
 }

Modified: head/sys/dev/cxgb/cxgb_main.c
==============================================================================
--- head/sys/dev/cxgb/cxgb_main.c       Thu Dec 18 14:21:06 2008        
(r186281)
+++ head/sys/dev/cxgb/cxgb_main.c       Thu Dec 18 14:21:35 2008        
(r186282)
@@ -90,6 +90,7 @@ static void cxgb_stop_locked(struct port
 static void cxgb_set_rxmode(struct port_info *);
 static int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t);
 static int cxgb_media_change(struct ifnet *);
+static int cxgb_ifm_type(int);
 static void cxgb_media_status(struct ifnet *, struct ifmediareq *);
 static int setup_sge_qsets(adapter_t *);
 static void cxgb_async_intr(void *);
@@ -976,7 +977,7 @@ cxgb_port_attach(device_t dev)
        } else if (!strcmp(p->phy.desc, "10GBASE-SR")) {
                media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
        } else if (!strcmp(p->phy.desc, "10GBASE-R")) {
-               media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX;
+               media_flags = cxgb_ifm_type(p->phy.modtype);
        } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) {
                ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
                ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
@@ -992,6 +993,9 @@ cxgb_port_attach(device_t dev)
                /*
                 * XXX: This is not very accurate.  Fix when common code
                 * returns more specific value - eg 1000BASE-SX, LX, etc.
+                *
+                * XXX: In the meantime, don't lie. Consider setting IFM_AUTO
+                * instead of SX.
                 */
                media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX;
        } else {
@@ -999,7 +1003,13 @@ cxgb_port_attach(device_t dev)
                return (ENXIO);
        }
        if (media_flags) {
-               ifmedia_add(&p->media, media_flags, 0, NULL);
+               /*
+                * Note the modtype on which we based our flags.  If modtype
+                * changes, we'll redo the ifmedia for this ifp.  modtype may
+                * change when transceivers are plugged in/out, and in other
+                * situations.
+                */
+               ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL);
                ifmedia_set(&p->media, media_flags);
        } else {
                ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
@@ -1827,7 +1837,7 @@ cxgb_init_locked(struct port_info *p)
        cxgb_link_start(p);
        t3_link_changed(sc, p->port_id);
 #endif
-       ifp->if_baudrate = p->link_config.speed * 1000000;
+       ifp->if_baudrate = IF_Mbps(p->link_config.speed);
 
        device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
        t3_port_intr_enable(sc, p->port_id);
@@ -1990,7 +2000,9 @@ cxgb_ioctl(struct ifnet *ifp, unsigned l
                break;
        case SIOCSIFMEDIA:
        case SIOCGIFMEDIA:
+               PORT_LOCK(p);
                error = ifmedia_ioctl(ifp, ifr, &p->media, command);
+               PORT_UNLOCK(p);
                break;
        case SIOCSIFCAP:
                PORT_LOCK(p);
@@ -2066,10 +2078,64 @@ cxgb_media_change(struct ifnet *ifp)
        return (ENXIO);
 }
 
+/*
+ * Translates from phy->modtype to IFM_TYPE.
+ */
+static int
+cxgb_ifm_type(int phymod)
+{
+       int rc = IFM_ETHER | IFM_FDX;
+
+       switch (phymod) {
+       case phy_modtype_sr:
+               rc |= IFM_10G_SR;
+               break;
+       case phy_modtype_lr:
+               rc |= IFM_10G_LR;
+               break;
+       case phy_modtype_lrm:
+#ifdef IFM_10G_LRM
+               rc |= IFM_10G_LRM;
+#endif
+               break;
+       case phy_modtype_twinax:
+#ifdef IFM_10G_TWINAX
+               rc |= IFM_10G_TWINAX;
+#endif
+               break;
+       case phy_modtype_twinax_long:
+#ifdef IFM_10G_TWINAX_LONG
+               rc |= IFM_10G_TWINAX_LONG;
+#endif
+               break;
+       case phy_modtype_none:
+               rc = IFM_ETHER | IFM_NONE;
+               break;
+       case phy_modtype_unknown:
+               break;
+       }
+
+       return (rc);
+}
+
 static void
 cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
        struct port_info *p = ifp->if_softc;
+       struct ifmedia_entry *cur = p->media.ifm_cur;
+       int m;
+
+       if (cur->ifm_data != p->phy.modtype) { 
+               /* p->media about to be rebuilt, must hold lock */
+               PORT_LOCK_ASSERT_OWNED(p);
+
+               m = cxgb_ifm_type(p->phy.modtype);
+               ifmedia_removeall(&p->media);
+               ifmedia_add(&p->media, m, p->phy.modtype, NULL); 
+               ifmedia_set(&p->media, m);
+               cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */
+               ifmr->ifm_current = m;
+       }
 
        ifmr->ifm_status = IFM_AVALID;
        ifmr->ifm_active = IFM_ETHER;
@@ -2089,6 +2155,9 @@ cxgb_media_status(struct ifnet *ifp, str
        case 1000:
                ifmr->ifm_active |= IFM_1000_T;
                break;
+       case 10000:
+               ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media);
+               break;
        }
        
        if (p->link_config.duplex)
@@ -2140,7 +2209,7 @@ check_link_status(adapter_t *sc)
 
                if (!(p->phy.caps & SUPPORTED_IRQ)) 
                        t3_link_changed(sc, i);
-               p->ifp->if_baudrate = p->link_config.speed * 1000000;
+               p->ifp->if_baudrate = IF_Mbps(p->link_config.speed);
        }
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to