Date: Wed, 3 Jun 2009 23:01:13 +0000 (UTC) From: "George V. Neville-Neil" <gnn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r193410 - in stable/7/sys: . dev/cxgb dev/cxgb/common Message-ID: <200906032301.n53N1D6t069743@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906032301.n53N1D6t069743>