freebsd-dev/sys/dev/cxgb/common/cxgb_ael1002.c
George V. Neville-Neil 2a1b9f07fc Several small additions to the Chelsio 10G driver.
1) Fix a bug in dealing with the Alerus 1006 PHY which prevented the
device from ever coming back up once it had been set to down.

2) Add a kernel tunable (hw.cxgb.snd_queue_len) which makes it possible
to give the device more than IFQ_MAXLEN entries in its send queue.  The
default remains 50.

3) Add code to place the card'd identification and serial number into
its description (%desc) so that users can tell which card they have
installed.
2008-11-21 19:22:25 +00:00

1316 lines
28 KiB
C

/**************************************************************************
Copyright (c) 2007-2008, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <cxgb_include.h>
#undef msleep
#define msleep t3_os_sleep
enum {
PMD_RSD = 10, /* PMA/PMD receive signal detect register */
PCS_STAT1_X = 24, /* 10GBASE-X PCS status 1 register */
PCS_STAT1_R = 32, /* 10GBASE-R PCS status 1 register */
XS_LN_STAT = 24 /* XS lane status register */
};
enum {
AEL100X_TX_DISABLE = 9,
AEL100X_TX_CONFIG1 = 0xc002,
AEL1002_PWR_DOWN_HI = 0xc011,
AEL1002_PWR_DOWN_LO = 0xc012,
AEL1002_XFI_EQL = 0xc015,
AEL1002_LB_EN = 0xc017,
AEL_OPT_SETTINGS = 0xc017,
AEL_I2C_CTRL = 0xc30a,
AEL_I2C_DATA = 0xc30b,
AEL_I2C_STAT = 0xc30c,
AEL2005_GPIO_CTRL = 0xc214,
AEL2005_GPIO_STAT = 0xc215,
};
enum { edc_none, edc_sr, edc_twinax };
/* PHY module I2C device address */
#define MODULE_DEV_ADDR 0xa0
#define AEL2005_MODDET_IRQ 4
struct reg_val {
unsigned short mmd_addr;
unsigned short reg_addr;
unsigned short clear_bits;
unsigned short set_bits;
};
static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
{
int err;
for (err = 0; rv->mmd_addr && !err; rv++) {
if (rv->clear_bits == 0xffff)
err = mdio_write(phy, rv->mmd_addr, rv->reg_addr,
rv->set_bits);
else
err = t3_mdio_change_bits(phy, rv->mmd_addr,
rv->reg_addr, rv->clear_bits,
rv->set_bits);
}
return err;
}
static void ael100x_txon(struct cphy *phy)
{
int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
msleep(100);
t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
msleep(30);
}
static int ael1002_power_down(struct cphy *phy, int enable)
{
int err;
err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
if (!err)
err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
return err;
}
static int ael1002_reset(struct cphy *phy, int wait)
{
int err;
if ((err = ael1002_power_down(phy, 0)) ||
(err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
(err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
(err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
(err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
(err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
0, 1 << 5)))
return err;
return 0;
}
static int ael1002_intr_noop(struct cphy *phy)
{
return 0;
}
/*
* Get link status for a 10GBASE-R device.
*/
static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
int *duplex, int *fc)
{
if (link_ok) {
unsigned int stat0, stat1, stat2;
int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0);
if (!err)
err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1);
if (!err)
err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2);
if (err)
return err;
*link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
}
if (speed)
*speed = SPEED_10000;
if (duplex)
*duplex = DUPLEX_FULL;
return 0;
}
#ifdef C99_NOT_SUPPORTED
static struct cphy_ops ael1002_ops = {
ael1002_reset,
ael1002_intr_noop,
ael1002_intr_noop,
ael1002_intr_noop,
ael1002_intr_noop,
NULL,
NULL,
NULL,
NULL,
NULL,
get_link_status_r,
ael1002_power_down,
};
#else
static struct cphy_ops ael1002_ops = {
.reset = ael1002_reset,
.intr_enable = ael1002_intr_noop,
.intr_disable = ael1002_intr_noop,
.intr_clear = ael1002_intr_noop,
.intr_handler = ael1002_intr_noop,
.get_link_status = get_link_status_r,
.power_down = ael1002_power_down,
};
#endif
int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
"10GBASE-R");
ael100x_txon(phy);
return 0;
}
static int ael1006_reset(struct cphy *phy, int wait)
{
u32 gpio_out;
t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
/* Hack to reset the phy correctly */
/* Read out the current value */
gpio_out = t3_read_reg(phy->adapter, A_T3DBG_GPIO_EN);
/* Reset the phy */
gpio_out &= ~F_GPIO6_OUT_VAL;
t3_write_reg(phy->adapter, A_T3DBG_GPIO_EN, gpio_out);
msleep(125);
/* Take the phy out of reset */
gpio_out |= F_GPIO6_OUT_VAL;
t3_write_reg(phy->adapter, A_T3DBG_GPIO_EN, gpio_out);
msleep(125);
t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
return 0;
}
static int ael1006_power_down(struct cphy *phy, int enable)
{
return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
}
#ifdef C99_NOT_SUPPORTED
static struct cphy_ops ael1006_ops = {
ael1006_reset,
t3_phy_lasi_intr_enable,
t3_phy_lasi_intr_disable,
t3_phy_lasi_intr_clear,
t3_phy_lasi_intr_handler,
NULL,
NULL,
NULL,
NULL,
NULL,
get_link_status_r,
ael1006_power_down,
};
#else
static struct cphy_ops ael1006_ops = {
.reset = ael1006_reset,
.intr_enable = t3_phy_lasi_intr_enable,
.intr_disable = t3_phy_lasi_intr_disable,
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_r,
.power_down = ael1006_power_down,
};
#endif
int t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
"10GBASE-SR");
ael100x_txon(phy);
return 0;
}
static int ael2005_setup_sr_edc(struct cphy *phy)
{
static struct reg_val regs[] = {
{ MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x181 },
{ MDIO_DEV_PMA_PMD, 0xc010, 0xffff, 0x448a },
{ MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5200 },
{ 0, 0, 0, 0 }
};
static u16 sr_edc[] = {
0xcc00, 0x2ff4,
0xcc01, 0x3cd4,
0xcc02, 0x2015,
0xcc03, 0x3105,
0xcc04, 0x6524,
0xcc05, 0x27ff,
0xcc06, 0x300f,
0xcc07, 0x2c8b,
0xcc08, 0x300b,
0xcc09, 0x4009,
0xcc0a, 0x400e,
0xcc0b, 0x2f72,
0xcc0c, 0x3002,
0xcc0d, 0x1002,
0xcc0e, 0x2172,
0xcc0f, 0x3012,
0xcc10, 0x1002,
0xcc11, 0x25d2,
0xcc12, 0x3012,
0xcc13, 0x1002,
0xcc14, 0xd01e,
0xcc15, 0x27d2,
0xcc16, 0x3012,
0xcc17, 0x1002,
0xcc18, 0x2004,
0xcc19, 0x3c84,
0xcc1a, 0x6436,
0xcc1b, 0x2007,
0xcc1c, 0x3f87,
0xcc1d, 0x8676,
0xcc1e, 0x40b7,
0xcc1f, 0xa746,
0xcc20, 0x4047,
0xcc21, 0x5673,
0xcc22, 0x2982,
0xcc23, 0x3002,
0xcc24, 0x13d2,
0xcc25, 0x8bbd,
0xcc26, 0x2862,
0xcc27, 0x3012,
0xcc28, 0x1002,
0xcc29, 0x2092,
0xcc2a, 0x3012,
0xcc2b, 0x1002,
0xcc2c, 0x5cc3,
0xcc2d, 0x314,
0xcc2e, 0x2942,
0xcc2f, 0x3002,
0xcc30, 0x1002,
0xcc31, 0xd019,
0xcc32, 0x2032,
0xcc33, 0x3012,
0xcc34, 0x1002,
0xcc35, 0x2a04,
0xcc36, 0x3c74,
0xcc37, 0x6435,
0xcc38, 0x2fa4,
0xcc39, 0x3cd4,
0xcc3a, 0x6624,
0xcc3b, 0x5563,
0xcc3c, 0x2d42,
0xcc3d, 0x3002,
0xcc3e, 0x13d2,
0xcc3f, 0x464d,
0xcc40, 0x2862,
0xcc41, 0x3012,
0xcc42, 0x1002,
0xcc43, 0x2032,
0xcc44, 0x3012,
0xcc45, 0x1002,
0xcc46, 0x2fb4,
0xcc47, 0x3cd4,
0xcc48, 0x6624,
0xcc49, 0x5563,
0xcc4a, 0x2d42,
0xcc4b, 0x3002,
0xcc4c, 0x13d2,
0xcc4d, 0x2ed2,
0xcc4e, 0x3002,
0xcc4f, 0x1002,
0xcc50, 0x2fd2,
0xcc51, 0x3002,
0xcc52, 0x1002,
0xcc53, 0x004,
0xcc54, 0x2942,
0xcc55, 0x3002,
0xcc56, 0x1002,
0xcc57, 0x2092,
0xcc58, 0x3012,
0xcc59, 0x1002,
0xcc5a, 0x5cc3,
0xcc5b, 0x317,
0xcc5c, 0x2f72,
0xcc5d, 0x3002,
0xcc5e, 0x1002,
0xcc5f, 0x2942,
0xcc60, 0x3002,
0xcc61, 0x1002,
0xcc62, 0x22cd,
0xcc63, 0x301d,
0xcc64, 0x2862,
0xcc65, 0x3012,
0xcc66, 0x1002,
0xcc67, 0x2ed2,
0xcc68, 0x3002,
0xcc69, 0x1002,
0xcc6a, 0x2d72,
0xcc6b, 0x3002,
0xcc6c, 0x1002,
0xcc6d, 0x628f,
0xcc6e, 0x2112,
0xcc6f, 0x3012,
0xcc70, 0x1002,
0xcc71, 0x5aa3,
0xcc72, 0x2dc2,
0xcc73, 0x3002,
0xcc74, 0x1312,
0xcc75, 0x6f72,
0xcc76, 0x1002,
0xcc77, 0x2807,
0xcc78, 0x31a7,
0xcc79, 0x20c4,
0xcc7a, 0x3c24,
0xcc7b, 0x6724,
0xcc7c, 0x1002,
0xcc7d, 0x2807,
0xcc7e, 0x3187,
0xcc7f, 0x20c4,
0xcc80, 0x3c24,
0xcc81, 0x6724,
0xcc82, 0x1002,
0xcc83, 0x2514,
0xcc84, 0x3c64,
0xcc85, 0x6436,
0xcc86, 0xdff4,
0xcc87, 0x6436,
0xcc88, 0x1002,
0xcc89, 0x40a4,
0xcc8a, 0x643c,
0xcc8b, 0x4016,
0xcc8c, 0x8c6c,
0xcc8d, 0x2b24,
0xcc8e, 0x3c24,
0xcc8f, 0x6435,
0xcc90, 0x1002,
0xcc91, 0x2b24,
0xcc92, 0x3c24,
0xcc93, 0x643a,
0xcc94, 0x4025,
0xcc95, 0x8a5a,
0xcc96, 0x1002,
0xcc97, 0x2731,
0xcc98, 0x3011,
0xcc99, 0x1001,
0xcc9a, 0xc7a0,
0xcc9b, 0x100,
0xcc9c, 0xc502,
0xcc9d, 0x53ac,
0xcc9e, 0xc503,
0xcc9f, 0xd5d5,
0xcca0, 0xc600,
0xcca1, 0x2a6d,
0xcca2, 0xc601,
0xcca3, 0x2a4c,
0xcca4, 0xc602,
0xcca5, 0x111,
0xcca6, 0xc60c,
0xcca7, 0x5900,
0xcca8, 0xc710,
0xcca9, 0x700,
0xccaa, 0xc718,
0xccab, 0x700,
0xccac, 0xc720,
0xccad, 0x4700,
0xccae, 0xc801,
0xccaf, 0x7f50,
0xccb0, 0xc802,
0xccb1, 0x7760,
0xccb2, 0xc803,
0xccb3, 0x7fce,
0xccb4, 0xc804,
0xccb5, 0x5700,
0xccb6, 0xc805,
0xccb7, 0x5f11,
0xccb8, 0xc806,
0xccb9, 0x4751,
0xccba, 0xc807,
0xccbb, 0x57e1,
0xccbc, 0xc808,
0xccbd, 0x2700,
0xccbe, 0xc809,
0xccbf, 0x000,
0xccc0, 0xc821,
0xccc1, 0x002,
0xccc2, 0xc822,
0xccc3, 0x014,
0xccc4, 0xc832,
0xccc5, 0x1186,
0xccc6, 0xc847,
0xccc7, 0x1e02,
0xccc8, 0xc013,
0xccc9, 0xf341,
0xccca, 0xc01a,
0xcccb, 0x446,
0xcccc, 0xc024,
0xcccd, 0x1000,
0xccce, 0xc025,
0xcccf, 0xa00,
0xccd0, 0xc026,
0xccd1, 0xc0c,
0xccd2, 0xc027,
0xccd3, 0xc0c,
0xccd4, 0xc029,
0xccd5, 0x0a0,
0xccd6, 0xc030,
0xccd7, 0xa00,
0xccd8, 0xc03c,
0xccd9, 0x01c,
0xccda, 0xc005,
0xccdb, 0x7a06,
0xccdc, 0x000,
0xccdd, 0x2731,
0xccde, 0x3011,
0xccdf, 0x1001,
0xcce0, 0xc620,
0xcce1, 0x000,
0xcce2, 0xc621,
0xcce3, 0x03f,
0xcce4, 0xc622,
0xcce5, 0x000,
0xcce6, 0xc623,
0xcce7, 0x000,
0xcce8, 0xc624,
0xcce9, 0x000,
0xccea, 0xc625,
0xcceb, 0x000,
0xccec, 0xc627,
0xcced, 0x000,
0xccee, 0xc628,
0xccef, 0x000,
0xccf0, 0xc62c,
0xccf1, 0x000,
0xccf2, 0x000,
0xccf3, 0x2806,
0xccf4, 0x3cb6,
0xccf5, 0xc161,
0xccf6, 0x6134,
0xccf7, 0x6135,
0xccf8, 0x5443,
0xccf9, 0x303,
0xccfa, 0x6524,
0xccfb, 0x00b,
0xccfc, 0x1002,
0xccfd, 0x2104,
0xccfe, 0x3c24,
0xccff, 0x2105,
0xcd00, 0x3805,
0xcd01, 0x6524,
0xcd02, 0xdff4,
0xcd03, 0x4005,
0xcd04, 0x6524,
0xcd05, 0x1002,
0xcd06, 0x5dd3,
0xcd07, 0x306,
0xcd08, 0x2ff7,
0xcd09, 0x38f7,
0xcd0a, 0x60b7,
0xcd0b, 0xdffd,
0xcd0c, 0x00a,
0xcd0d, 0x1002,
0xcd0e, 0
};
int i, err;
err = set_phy_regs(phy, regs);
if (err)
return err;
msleep(50);
for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
err = mdio_write(phy, MDIO_DEV_PMA_PMD, sr_edc[i],
sr_edc[i + 1]);
if (!err)
phy->priv = edc_sr;
return err;
}
static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
{
static struct reg_val regs[] = {
{ MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 },
{ 0, 0, 0, 0 }
};
static struct reg_val preemphasis[] = {
{ MDIO_DEV_PMA_PMD, 0xc014, 0xffff, 0xfe16 },
{ MDIO_DEV_PMA_PMD, 0xc015, 0xffff, 0xa000 },
{ 0, 0, 0, 0 }
};
static u16 twinax_edc[] = {
0xcc00, 0x4009,
0xcc01, 0x27ff,
0xcc02, 0x300f,
0xcc03, 0x40aa,
0xcc04, 0x401c,
0xcc05, 0x401e,
0xcc06, 0x2ff4,
0xcc07, 0x3cd4,
0xcc08, 0x2035,
0xcc09, 0x3145,
0xcc0a, 0x6524,
0xcc0b, 0x26a2,
0xcc0c, 0x3012,
0xcc0d, 0x1002,
0xcc0e, 0x29c2,
0xcc0f, 0x3002,
0xcc10, 0x1002,
0xcc11, 0x2072,
0xcc12, 0x3012,
0xcc13, 0x1002,
0xcc14, 0x22cd,
0xcc15, 0x301d,
0xcc16, 0x2e52,
0xcc17, 0x3012,
0xcc18, 0x1002,
0xcc19, 0x28e2,
0xcc1a, 0x3002,
0xcc1b, 0x1002,
0xcc1c, 0x628f,
0xcc1d, 0x2ac2,
0xcc1e, 0x3012,
0xcc1f, 0x1002,
0xcc20, 0x5553,
0xcc21, 0x2ae2,
0xcc22, 0x3002,
0xcc23, 0x1302,
0xcc24, 0x401e,
0xcc25, 0x2be2,
0xcc26, 0x3012,
0xcc27, 0x1002,
0xcc28, 0x2da2,
0xcc29, 0x3012,
0xcc2a, 0x1002,
0xcc2b, 0x2ba2,
0xcc2c, 0x3002,
0xcc2d, 0x1002,
0xcc2e, 0x5ee3,
0xcc2f, 0x305,
0xcc30, 0x400e,
0xcc31, 0x2bc2,
0xcc32, 0x3002,
0xcc33, 0x1002,
0xcc34, 0x2b82,
0xcc35, 0x3012,
0xcc36, 0x1002,
0xcc37, 0x5663,
0xcc38, 0x302,
0xcc39, 0x401e,
0xcc3a, 0x6f72,
0xcc3b, 0x1002,
0xcc3c, 0x628f,
0xcc3d, 0x2be2,
0xcc3e, 0x3012,
0xcc3f, 0x1002,
0xcc40, 0x22cd,
0xcc41, 0x301d,
0xcc42, 0x2e52,
0xcc43, 0x3012,
0xcc44, 0x1002,
0xcc45, 0x2522,
0xcc46, 0x3012,
0xcc47, 0x1002,
0xcc48, 0x2da2,
0xcc49, 0x3012,
0xcc4a, 0x1002,
0xcc4b, 0x2ca2,
0xcc4c, 0x3012,
0xcc4d, 0x1002,
0xcc4e, 0x2fa4,
0xcc4f, 0x3cd4,
0xcc50, 0x6624,
0xcc51, 0x410b,
0xcc52, 0x56b3,
0xcc53, 0x3c4,
0xcc54, 0x2fb2,
0xcc55, 0x3002,
0xcc56, 0x1002,
0xcc57, 0x220b,
0xcc58, 0x303b,
0xcc59, 0x56b3,
0xcc5a, 0x3c3,
0xcc5b, 0x866b,
0xcc5c, 0x400c,
0xcc5d, 0x23a2,
0xcc5e, 0x3012,
0xcc5f, 0x1002,
0xcc60, 0x2da2,
0xcc61, 0x3012,
0xcc62, 0x1002,
0xcc63, 0x2ca2,
0xcc64, 0x3012,
0xcc65, 0x1002,
0xcc66, 0x2fb4,
0xcc67, 0x3cd4,
0xcc68, 0x6624,
0xcc69, 0x56b3,
0xcc6a, 0x3c3,
0xcc6b, 0x866b,
0xcc6c, 0x401c,
0xcc6d, 0x2205,
0xcc6e, 0x3035,
0xcc6f, 0x5b53,
0xcc70, 0x2c52,
0xcc71, 0x3002,
0xcc72, 0x13c2,
0xcc73, 0x5cc3,
0xcc74, 0x317,
0xcc75, 0x2522,
0xcc76, 0x3012,
0xcc77, 0x1002,
0xcc78, 0x2da2,
0xcc79, 0x3012,
0xcc7a, 0x1002,
0xcc7b, 0x2b82,
0xcc7c, 0x3012,
0xcc7d, 0x1002,
0xcc7e, 0x5663,
0xcc7f, 0x303,
0xcc80, 0x401e,
0xcc81, 0x004,
0xcc82, 0x2c42,
0xcc83, 0x3012,
0xcc84, 0x1002,
0xcc85, 0x6f72,
0xcc86, 0x1002,
0xcc87, 0x628f,
0xcc88, 0x2304,
0xcc89, 0x3c84,
0xcc8a, 0x6436,
0xcc8b, 0xdff4,
0xcc8c, 0x6436,
0xcc8d, 0x2ff5,
0xcc8e, 0x3005,
0xcc8f, 0x8656,
0xcc90, 0xdfba,
0xcc91, 0x56a3,
0xcc92, 0xd05a,
0xcc93, 0x21c2,
0xcc94, 0x3012,
0xcc95, 0x1392,
0xcc96, 0xd05a,
0xcc97, 0x56a3,
0xcc98, 0xdfba,
0xcc99, 0x383,
0xcc9a, 0x6f72,
0xcc9b, 0x1002,
0xcc9c, 0x28c5,
0xcc9d, 0x3005,
0xcc9e, 0x4178,
0xcc9f, 0x5653,
0xcca0, 0x384,
0xcca1, 0x22b2,
0xcca2, 0x3012,
0xcca3, 0x1002,
0xcca4, 0x2be5,
0xcca5, 0x3005,
0xcca6, 0x41e8,
0xcca7, 0x5653,
0xcca8, 0x382,
0xcca9, 0x002,
0xccaa, 0x4258,
0xccab, 0x2474,
0xccac, 0x3c84,
0xccad, 0x6437,
0xccae, 0xdff4,
0xccaf, 0x6437,
0xccb0, 0x2ff5,
0xccb1, 0x3c05,
0xccb2, 0x8757,
0xccb3, 0xb888,
0xccb4, 0x9787,
0xccb5, 0xdff4,
0xccb6, 0x6724,
0xccb7, 0x866a,
0xccb8, 0x6f72,
0xccb9, 0x1002,
0xccba, 0x2d01,
0xccbb, 0x3011,
0xccbc, 0x1001,
0xccbd, 0xc620,
0xccbe, 0x14e5,
0xccbf, 0xc621,
0xccc0, 0xc53d,
0xccc1, 0xc622,
0xccc2, 0x3cbe,
0xccc3, 0xc623,
0xccc4, 0x4452,
0xccc5, 0xc624,
0xccc6, 0xc5c5,
0xccc7, 0xc625,
0xccc8, 0xe01e,
0xccc9, 0xc627,
0xccca, 0x000,
0xcccb, 0xc628,
0xcccc, 0x000,
0xcccd, 0xc62b,
0xccce, 0x000,
0xcccf, 0xc62c,
0xccd0, 0x000,
0xccd1, 0x000,
0xccd2, 0x2d01,
0xccd3, 0x3011,
0xccd4, 0x1001,
0xccd5, 0xc620,
0xccd6, 0x000,
0xccd7, 0xc621,
0xccd8, 0x000,
0xccd9, 0xc622,
0xccda, 0x0ce,
0xccdb, 0xc623,
0xccdc, 0x07f,
0xccdd, 0xc624,
0xccde, 0x032,
0xccdf, 0xc625,
0xcce0, 0x000,
0xcce1, 0xc627,
0xcce2, 0x000,
0xcce3, 0xc628,
0xcce4, 0x000,
0xcce5, 0xc62b,
0xcce6, 0x000,
0xcce7, 0xc62c,
0xcce8, 0x000,
0xcce9, 0x000,
0xccea, 0x2d01,
0xcceb, 0x3011,
0xccec, 0x1001,
0xcced, 0xc502,
0xccee, 0x609f,
0xccef, 0xc600,
0xccf0, 0x2a6e,
0xccf1, 0xc601,
0xccf2, 0x2a2c,
0xccf3, 0xc60c,
0xccf4, 0x5400,
0xccf5, 0xc710,
0xccf6, 0x700,
0xccf7, 0xc718,
0xccf8, 0x700,
0xccf9, 0xc720,
0xccfa, 0x4700,
0xccfb, 0xc728,
0xccfc, 0x700,
0xccfd, 0xc729,
0xccfe, 0x1207,
0xccff, 0xc801,
0xcd00, 0x7f50,
0xcd01, 0xc802,
0xcd02, 0x7760,
0xcd03, 0xc803,
0xcd04, 0x7fce,
0xcd05, 0xc804,
0xcd06, 0x520e,
0xcd07, 0xc805,
0xcd08, 0x5c11,
0xcd09, 0xc806,
0xcd0a, 0x3c51,
0xcd0b, 0xc807,
0xcd0c, 0x4061,
0xcd0d, 0xc808,
0xcd0e, 0x49c1,
0xcd0f, 0xc809,
0xcd10, 0x3840,
0xcd11, 0xc80a,
0xcd12, 0x000,
0xcd13, 0xc821,
0xcd14, 0x002,
0xcd15, 0xc822,
0xcd16, 0x046,
0xcd17, 0xc844,
0xcd18, 0x182f,
0xcd19, 0xc013,
0xcd1a, 0xf341,
0xcd1b, 0xc01a,
0xcd1c, 0x446,
0xcd1d, 0xc024,
0xcd1e, 0x1000,
0xcd1f, 0xc025,
0xcd20, 0xa00,
0xcd21, 0xc026,
0xcd22, 0xc0c,
0xcd23, 0xc027,
0xcd24, 0xc0c,
0xcd25, 0xc029,
0xcd26, 0x0a0,
0xcd27, 0xc030,
0xcd28, 0xa00,
0xcd29, 0xc03c,
0xcd2a, 0x01c,
0xcd2b, 0x000,
0xcd2c, 0x2b84,
0xcd2d, 0x3c74,
0xcd2e, 0x6435,
0xcd2f, 0xdff4,
0xcd30, 0x6435,
0xcd31, 0x2806,
0xcd32, 0x3006,
0xcd33, 0x8565,
0xcd34, 0x2b24,
0xcd35, 0x3c24,
0xcd36, 0x6436,
0xcd37, 0x1002,
0xcd38, 0x2b24,
0xcd39, 0x3c24,
0xcd3a, 0x6436,
0xcd3b, 0x4045,
0xcd3c, 0x8656,
0xcd3d, 0x1002,
0xcd3e, 0x2807,
0xcd3f, 0x31a7,
0xcd40, 0x20c4,
0xcd41, 0x3c24,
0xcd42, 0x6724,
0xcd43, 0x1002,
0xcd44, 0x2807,
0xcd45, 0x3187,
0xcd46, 0x20c4,
0xcd47, 0x3c24,
0xcd48, 0x6724,
0xcd49, 0x1002,
0xcd4a, 0x2514,
0xcd4b, 0x3c64,
0xcd4c, 0x6436,
0xcd4d, 0xdff4,
0xcd4e, 0x6436,
0xcd4f, 0x1002,
0xcd50, 0x2806,
0xcd51, 0x3cb6,
0xcd52, 0xc161,
0xcd53, 0x6134,
0xcd54, 0x6135,
0xcd55, 0x5443,
0xcd56, 0x303,
0xcd57, 0x6524,
0xcd58, 0x00b,
0xcd59, 0x1002,
0xcd5a, 0xd019,
0xcd5b, 0x2104,
0xcd5c, 0x3c24,
0xcd5d, 0x2105,
0xcd5e, 0x3805,
0xcd5f, 0x6524,
0xcd60, 0xdff4,
0xcd61, 0x4005,
0xcd62, 0x6524,
0xcd63, 0x2e8d,
0xcd64, 0x303d,
0xcd65, 0x5dd3,
0xcd66, 0x306,
0xcd67, 0x2ff7,
0xcd68, 0x38f7,
0xcd69, 0x60b7,
0xcd6a, 0xdffd,
0xcd6b, 0x00a,
0xcd6c, 0x1002,
0xcd6d, 0
};
int i, err;
err = set_phy_regs(phy, regs);
if (!err && modtype == phy_modtype_twinax_long)
err = set_phy_regs(phy, preemphasis);
if (err)
return err;
msleep(50);
for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i],
twinax_edc[i + 1]);
if (!err)
phy->priv = edc_twinax;
return err;
}
static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
{
int i, err;
unsigned int stat, data;
err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL_I2C_CTRL,
(dev_addr << 8) | (1 << 8) | word_addr);
if (err)
return err;
for (i = 0; i < 5; i++) {
msleep(1);
err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_STAT, &stat);
if (err)
return err;
if ((stat & 3) == 1) {
err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA,
&data);
if (err)
return err;
return data >> 8;
}
}
CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n",
phy->addr, word_addr);
return -ETIMEDOUT;
}
static int get_module_type(struct cphy *phy, int delay_ms)
{
int v;
unsigned int stat;
v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat);
if (v)
return v;
if (stat & (1 << 8)) /* module absent */
return phy_modtype_none;
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;
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)
{
int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200);
return err ? err : t3_phy_lasi_intr_enable(phy);
}
static int ael2005_intr_disable(struct cphy *phy)
{
int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x100);
return err ? err : t3_phy_lasi_intr_disable(phy);
}
static int ael2005_intr_clear(struct cphy *phy)
{
int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0xd00);
return err ? err : t3_phy_lasi_intr_clear(phy);
}
static int ael2005_reset(struct cphy *phy, int wait)
{
static struct reg_val regs0[] = {
{ MDIO_DEV_PMA_PMD, 0xc001, 0, 1 << 5 },
{ MDIO_DEV_PMA_PMD, 0xc017, 0, 1 << 5 },
{ MDIO_DEV_PMA_PMD, 0xc013, 0xffff, 0xf341 },
{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 },
{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8100 },
{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 },
{ MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0 },
{ 0, 0, 0, 0 }
};
static struct reg_val regs1[] = {
{ MDIO_DEV_PMA_PMD, 0xca00, 0xffff, 0x0080 },
{ MDIO_DEV_PMA_PMD, 0xca12, 0xffff, 0 },
{ 0, 0, 0, 0 }
};
int err, lasi_ctrl;
err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl);
if (err)
return err;
err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0);
if (err)
return err;
msleep(125);
phy->priv = edc_none;
err = set_phy_regs(phy, regs0);
if (err)
return err;
msleep(50);
err = get_module_type(phy, 0);
if (err < 0)
return err;
phy->modtype = (u8)err;
if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
err = ael2005_setup_twinax_edc(phy, err);
else
err = ael2005_setup_sr_edc(phy);
if (err)
return err;
err = set_phy_regs(phy, regs1);
if (err)
return err;
/* reset wipes out interrupts, reenable them if they were on */
if (lasi_ctrl & 1)
err = ael2005_intr_enable(phy);
return err;
}
static int ael2005_intr_handler(struct cphy *phy)
{
unsigned int stat;
int ret, edc_needed, cause = 0;
ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_STAT, &stat);
if (ret)
return ret;
if (stat & AEL2005_MODDET_IRQ) {
ret = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL,
0xd00);
if (ret)
return ret;
/* modules have max 300 ms init time after hot plug */
ret = get_module_type(phy, 300);
if (ret < 0)
return ret;
phy->modtype = (u8)ret;
if (ret == phy_modtype_none)
edc_needed = phy->priv; /* on unplug retain EDC */
else if (ret == phy_modtype_twinax ||
ret == phy_modtype_twinax_long)
edc_needed = edc_twinax;
else
edc_needed = edc_sr;
if (edc_needed != phy->priv) {
ret = ael2005_reset(phy, 0);
return ret ? ret : cphy_cause_module_change;
}
cause = cphy_cause_module_change;
}
ret = t3_phy_lasi_intr_handler(phy);
return ret < 0 ? ret : ret + cause;
}
#ifdef C99_NOT_SUPPORTED
static struct cphy_ops ael2005_ops = {
ael2005_reset,
ael2005_intr_enable,
ael2005_intr_disable,
ael2005_intr_clear,
ael2005_intr_handler,
NULL,
NULL,
NULL,
NULL,
NULL,
get_link_status_r,
ael1002_power_down,
};
#else
static struct cphy_ops ael2005_ops = {
.reset = ael2005_reset,
.intr_enable = ael2005_intr_enable,
.intr_disable = ael2005_intr_disable,
.intr_clear = ael2005_intr_clear,
.intr_handler = ael2005_intr_handler,
.get_link_status = get_link_status_r,
.power_down = ael1002_power_down,
};
#endif
int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_IRQ, "10GBASE-R");
msleep(125);
return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0,
1 << 5);
}
/*
* Get link status for a 10GBASE-X device.
*/
static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
int *duplex, int *fc)
{
if (link_ok) {
unsigned int stat0, stat1, stat2;
int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0);
if (!err)
err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1);
if (!err)
err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2);
if (err)
return err;
*link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
}
if (speed)
*speed = SPEED_10000;
if (duplex)
*duplex = DUPLEX_FULL;
return 0;
}
#ifdef C99_NOT_SUPPORTED
static struct cphy_ops qt2045_ops = {
ael1006_reset,
t3_phy_lasi_intr_enable,
t3_phy_lasi_intr_disable,
t3_phy_lasi_intr_clear,
t3_phy_lasi_intr_handler,
NULL,
NULL,
NULL,
NULL,
NULL,
get_link_status_x,
ael1006_power_down,
};
#else
static struct cphy_ops qt2045_ops = {
.reset = ael1006_reset,
.intr_enable = t3_phy_lasi_intr_enable,
.intr_disable = t3_phy_lasi_intr_disable,
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_x,
.power_down = ael1006_power_down,
};
#endif
int t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
unsigned int stat;
cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
"10GBASE-CX4");
/*
* Some cards where the PHY is supposed to be at address 0 actually
* have it at 1.
*/
if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
stat == 0xffff)
phy->addr = 1;
return 0;
}
static int xaui_direct_reset(struct cphy *phy, int wait)
{
return 0;
}
static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
int *speed, int *duplex, int *fc)
{
if (link_ok) {
unsigned int status;
status = t3_read_reg(phy->adapter,
XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) |
t3_read_reg(phy->adapter,
XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) |
t3_read_reg(phy->adapter,
XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) |
t3_read_reg(phy->adapter,
XGM_REG(A_XGM_SERDES_STAT3, phy->addr));
*link_ok = !(status & F_LOWSIG0);
}
if (speed)
*speed = SPEED_10000;
if (duplex)
*duplex = DUPLEX_FULL;
return 0;
}
static int xaui_direct_power_down(struct cphy *phy, int enable)
{
return 0;
}
#ifdef C99_NOT_SUPPORTED
static struct cphy_ops xaui_direct_ops = {
xaui_direct_reset,
ael1002_intr_noop,
ael1002_intr_noop,
ael1002_intr_noop,
ael1002_intr_noop,
NULL,
NULL,
NULL,
NULL,
NULL,
xaui_direct_get_link_status,
xaui_direct_power_down,
};
#else
static struct cphy_ops xaui_direct_ops = {
.reset = xaui_direct_reset,
.intr_enable = ael1002_intr_noop,
.intr_disable = ael1002_intr_noop,
.intr_clear = ael1002_intr_noop,
.intr_handler = ael1002_intr_noop,
.get_link_status = xaui_direct_get_link_status,
.power_down = xaui_direct_power_down,
};
#endif
int t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
"10GBASE-CX4");
return 0;
}