summaryrefslogtreecommitdiffstats
path: root/sys/dev/cxgb/common
diff options
context:
space:
mode:
authorgnn <gnn@FreeBSD.org>2008-12-18 14:21:35 +0000
committergnn <gnn@FreeBSD.org>2008-12-18 14:21:35 +0000
commit7e56c10808aeb09cb6993c6beaf3f5e0d82f91e4 (patch)
tree7b949d1fe5033d361addda8f264a7174fa4fa448 /sys/dev/cxgb/common
parent95c5b12c17caea660098332fcad5d02b98688e38 (diff)
downloadFreeBSD-src-7e56c10808aeb09cb6993c6beaf3f5e0d82f91e4.zip
FreeBSD-src-7e56c10808aeb09cb6993c6beaf3f5e0d82f91e4.tar.gz
Check in the actual module recognition code for the Chelsio
driver. Obtained from: Chelsio Inc.
Diffstat (limited to 'sys/dev/cxgb/common')
-rw-r--r--sys/dev/cxgb/common/cxgb_ael1002.c134
1 files changed, 102 insertions, 32 deletions
diff --git a/sys/dev/cxgb/common/cxgb_ael1002.c b/sys/dev/cxgb/common/cxgb_ael1002.c
index 55c6421..97d4419 100644
--- a/sys/dev/cxgb/common/cxgb_ael1002.c
+++ b/sys/dev/cxgb/common/cxgb_ael1002.c
@@ -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;
-
- 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 *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);
}
OpenPOWER on IntegriCloud