Check in the actual module recognition code for the Chelsio

driver.

Obtained from:	Chelsio Inc.
This commit is contained in:
gnn 2008-12-18 14:21:35 +00:00
parent 95c5b12c17
commit 7e56c10808
2 changed files with 175 additions and 36 deletions

View File

@ -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 cphy *phy, int enable)
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 *phy, int wait)
(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 *phy, int dev_addr, int word_addr)
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 *phy, int delay_ms)
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;
return get_module_type(phy, 0);
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;
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 *phy, int wait)
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 cphy *phy)
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);
}

View File

@ -90,6 +90,7 @@ static void cxgb_stop_locked(struct port_info *);
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 long command, caddr_t data)
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, struct ifmediareq *ifmr)
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);
}
}