Check in the actual module recognition code for the Chelsio
driver. Obtained from: Chelsio Inc.
This commit is contained in:
parent
95c5b12c17
commit
7e56c10808
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user