svn commit: r193410 - in stable/7/sys: . dev/cxgb dev/cxgb/common

George V. Neville-Neil gnn at FreeBSD.org
Wed Jun 3 23:01:14 UTC 2009


Author: gnn
Date: Wed Jun  3 23:01:13 2009
New Revision: 193410
URL: http://svn.freebsd.org/changeset/base/193410

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

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/dev/cxgb/common/cxgb_ael1002.c
  stable/7/sys/dev/cxgb/cxgb_main.c

Modified: stable/7/sys/dev/cxgb/common/cxgb_ael1002.c
==============================================================================
--- stable/7/sys/dev/cxgb/common/cxgb_ael1002.c	Wed Jun  3 22:54:27 2009	(r193409)
+++ stable/7/sys/dev/cxgb/common/cxgb_ael1002.c	Wed Jun  3 23:01:13 2009	(r193410)
@@ -75,6 +75,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;
@@ -111,6 +179,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;
@@ -123,6 +203,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;
 }
 
@@ -186,10 +271,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;
 }
 
@@ -987,7 +1079,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;
@@ -1002,36 +1094,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)
@@ -1088,7 +1152,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;
@@ -1126,7 +1190,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;
 
@@ -1180,10 +1244,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: stable/7/sys/dev/cxgb/cxgb_main.c
==============================================================================
--- stable/7/sys/dev/cxgb/cxgb_main.c	Wed Jun  3 22:54:27 2009	(r193409)
+++ stable/7/sys/dev/cxgb/cxgb_main.c	Wed Jun  3 23:01:13 2009	(r193410)
@@ -98,6 +98,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 *);
@@ -1011,7 +1012,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,
@@ -1027,6 +1028,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 {
@@ -1034,7 +1038,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);
@@ -1875,7 +1885,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);
@@ -2033,7 +2043,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);
@@ -2107,10 +2119,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;
@@ -2130,6 +2196,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)
@@ -2181,7 +2250,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);
 	}
 }
 


More information about the svn-src-stable-7 mailing list