cxgb(4) updates, including:

- support for the new Gen-2, BT, and LP-CR cards.
- T3 firmware 7.7.0
- shared "common code" updates.

Approved by:	gnn (mentor)
Obtained from:	Chelsio
MFC after:	1 month
This commit is contained in:
Navdeep Parhar 2009-10-05 20:21:41 +00:00
parent 2880192bf2
commit c01f2b8301
15 changed files with 4412 additions and 2598 deletions

View File

@ -774,6 +774,8 @@ dev/cxgb/common/cxgb_vsc8211.c optional cxgb pci \
compile-with "${NORMAL_C} -I$S/dev/cxgb"
dev/cxgb/common/cxgb_ael1002.c optional cxgb pci \
compile-with "${NORMAL_C} -I$S/dev/cxgb"
dev/cxgb/common/cxgb_aq100x.c optional cxgb pci \
compile-with "${NORMAL_C} -I$S/dev/cxgb"
dev/cxgb/common/cxgb_mv88e1xxx.c optional cxgb pci \
compile-with "${NORMAL_C} -I$S/dev/cxgb"
dev/cxgb/common/cxgb_xgmac.c optional cxgb pci \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,544 @@
/**************************************************************************
Copyright (c) 2009 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 {
/* MDIO_DEV_PMA_PMD registers */
AQ_LINK_STAT = 0xe800,
/* MDIO_DEV_XGXS registers */
AQ_XAUI_RX_CFG = 0xc400,
AQ_XAUI_KX_CFG = 0xc440,
AQ_XAUI_TX_CFG = 0xe400,
/* MDIO_DEV_ANEG registers */
AQ_100M_CTRL = 0x0010,
AQ_10G_CTRL = 0x0020,
AQ_1G_CTRL = 0xc400,
AQ_ANEG_STAT = 0xc800,
/* MDIO_DEV_VEND1 registers */
AQ_FW_VERSION = 0x0020,
AQ_THERMAL_THR = 0xc421,
AQ_THERMAL1 = 0xc820,
AQ_THERMAL2 = 0xc821,
AQ_IFLAG_GLOBAL = 0xfc00,
AQ_IMASK_GLOBAL = 0xff00,
};
#define AQBIT(x) (1 << (0x##x))
#define ADV_1G_FULL AQBIT(f)
#define ADV_1G_HALF AQBIT(e)
#define ADV_10G_FULL AQBIT(c)
#define AQ_WRITE_REGS(phy, regs) do { \
int i; \
for (i = 0; i < ARRAY_SIZE(regs); i++) { \
(void) mdio_write(phy, regs[i].mmd, regs[i].reg, regs[i].val); \
} \
} while (0)
#define AQ_READ_REGS(phy, regs) do { \
unsigned i, v; \
for (i = 0; i < ARRAY_SIZE(regs); i++) { \
(void) mdio_read(phy, regs[i].mmd, regs[i].reg, &v); \
} \
} while (0)
/*
* Return value is temperature in celcius, 0xffff for error or don't know.
*/
static int
aq100x_temperature(struct cphy *phy)
{
unsigned int v;
if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL2, &v) ||
v == 0xffff || (v & 1) != 1)
return (0xffff);
if (mdio_read(phy, MDIO_DEV_VEND1, AQ_THERMAL1, &v))
return (0xffff);
return ((int)((signed char)(v >> 8)));
}
static int
aq100x_set_defaults(struct cphy *phy)
{
return mdio_write(phy, MDIO_DEV_VEND1, AQ_THERMAL_THR, 0x6c00);
}
static int
aq100x_reset(struct cphy *phy, int wait)
{
int err;
err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
if (!err)
err = aq100x_set_defaults(phy);
return (err);
}
static int
aq100x_intr_enable(struct cphy *phy)
{
struct {
int mmd;
int reg;
int val;
} imasks[] = {
{MDIO_DEV_VEND1, 0xd400, AQBIT(e)},
{MDIO_DEV_VEND1, 0xff01, AQBIT(2)},
{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, AQBIT(0)}
};
AQ_WRITE_REGS(phy, imasks);
return (0);
}
static int
aq100x_intr_disable(struct cphy *phy)
{
struct {
int mmd;
int reg;
int val;
} imasks[] = {
{MDIO_DEV_VEND1, 0xd400, 0},
{MDIO_DEV_VEND1, 0xff01, 0},
{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL, 0}
};
AQ_WRITE_REGS(phy, imasks);
return (0);
}
static int
aq100x_intr_clear(struct cphy *phy)
{
struct {
int mmd;
int reg;
} iclr[] = {
{MDIO_DEV_VEND1, 0xcc00},
{MDIO_DEV_VEND1, AQ_IMASK_GLOBAL} /* needed? */
};
AQ_READ_REGS(phy, iclr);
return (0);
}
static int
aq100x_vendor_intr(struct cphy *phy, int *rc)
{
int err;
unsigned int cause, v;
err = mdio_read(phy, MDIO_DEV_VEND1, 0xfc01, &cause);
if (err)
return (err);
if (cause & AQBIT(2)) {
err = mdio_read(phy, MDIO_DEV_VEND1, 0xcc00, &v);
if (err)
return (err);
if (v & AQBIT(e)) {
CH_WARN(phy->adapter, "PHY%d: temperature is now %dC\n",
phy->addr, aq100x_temperature(phy));
t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN,
phy->addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL, 0);
*rc |= cphy_cause_alarm;
}
cause &= ~4;
}
if (cause)
CH_WARN(phy->adapter, "PHY%d: unhandled vendor interrupt"
" (0x%x)\n", phy->addr, cause);
return (0);
}
static int
aq100x_intr_handler(struct cphy *phy)
{
int err, rc = 0;
unsigned int cause;
err = mdio_read(phy, MDIO_DEV_VEND1, AQ_IFLAG_GLOBAL, &cause);
if (err)
return (err);
if (cause & AQBIT(0)) {
err = aq100x_vendor_intr(phy, &rc);
if (err)
return (err);
cause &= ~AQBIT(0);
}
if (cause)
CH_WARN(phy->adapter, "PHY%d: unhandled interrupt (0x%x)\n",
phy->addr, cause);
return (rc);
}
static int
aq100x_power_down(struct cphy *phy, int off)
{
int err, wait = 500;
unsigned int v;
err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, BMCR_PDOWN,
off ? BMCR_PDOWN : 0);
if (err || off)
return (v);
msleep(300);
do {
err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
if (err)
return (err);
v &= BMCR_RESET;
if (v)
msleep(10);
} while (v && --wait);
if (v) {
CH_WARN(phy->adapter, "PHY%d: power-up timed out (0x%x).\n",
phy->addr, v);
return (ETIMEDOUT);
}
return (0);
}
static int
aq100x_autoneg_enable(struct cphy *phy)
{
int err;
err = aq100x_power_down(phy, 0);
if (!err)
err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
BMCR_RESET, BMCR_ANENABLE | BMCR_ANRESTART);
return (err);
}
static int
aq100x_autoneg_restart(struct cphy *phy)
{
return aq100x_autoneg_enable(phy);
}
static int
aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
{
unsigned int adv;
int err;
/* 10G advertisement */
adv = 0;
if (advertise_map & ADVERTISED_10000baseT_Full)
adv |= ADV_10G_FULL;
err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_10G_CTRL,
ADV_10G_FULL, adv);
if (err)
return (err);
/* 1G advertisement */
adv = 0;
if (advertise_map & ADVERTISED_1000baseT_Full)
adv |= ADV_1G_FULL;
if (advertise_map & ADVERTISED_1000baseT_Half)
adv |= ADV_1G_HALF;
err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_1G_CTRL,
ADV_1G_FULL | ADV_1G_HALF, adv);
if (err)
return (err);
/* 100M, pause advertisement */
adv = 0;
if (advertise_map & ADVERTISED_100baseT_Half)
adv |= ADVERTISE_100HALF;
if (advertise_map & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
if (advertise_map & ADVERTISED_Pause)
adv |= ADVERTISE_PAUSE_CAP;
if (advertise_map & ADVERTISED_Asym_Pause)
adv |= ADVERTISE_PAUSE_ASYM;
err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, AQ_100M_CTRL, 0xfe0, adv);
return (err);
}
static int
aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
{
return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
BMCR_LOOPBACK, enable ? BMCR_LOOPBACK : 0);
}
static int
aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
{
int err, set;
if (speed == SPEED_100)
set = BMCR_SPEED100;
else if (speed == SPEED_1000)
set = BMCR_SPEED1000;
else if (speed == SPEED_10000)
set = BMCR_SPEED1000 | BMCR_SPEED100;
else
return (EINVAL);
if (duplex != DUPLEX_FULL)
return (EINVAL);
err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR,
BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART, 0);
if (err)
return (err);
err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
BMCR_SPEED1000 | BMCR_SPEED100, set);
if (err)
return (err);
return (0);
}
static int
aq100x_get_link_status(struct cphy *phy, int *link_ok, int *speed, int *duplex,
int *fc)
{
int err;
unsigned int v, link = 0;
err = mdio_read(phy, MDIO_DEV_PMA_PMD, AQ_LINK_STAT, &v);
if (err)
return (err);
if (v == 0xffff || !(v & 1))
goto done;
err = mdio_read(phy, MDIO_DEV_ANEG, MII_BMCR, &v);
if (err)
return (err);
if (v & 0x8000)
goto done;
if (v & BMCR_ANENABLE) {
err = mdio_read(phy, MDIO_DEV_ANEG, 1, &v);
if (err)
return (err);
if ((v & 0x20) == 0)
goto done;
err = mdio_read(phy, MDIO_DEV_ANEG, AQ_ANEG_STAT, &v);
if (err)
return (err);
if (speed) {
switch (v & 0x6) {
case 0x6: *speed = SPEED_10000;
break;
case 0x4: *speed = SPEED_1000;
break;
case 0x2: *speed = SPEED_100;
break;
case 0x0: *speed = SPEED_10;
break;
}
}
if (duplex)
*duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
if (fc) {
unsigned int lpa, adv;
err = mdio_read(phy, MDIO_DEV_ANEG, 0x13, &lpa);
if (!err)
err = mdio_read(phy, MDIO_DEV_ANEG,
AQ_100M_CTRL, &adv);
if (err)
return err;
if (lpa & adv & ADVERTISE_PAUSE_CAP)
*fc = PAUSE_RX | PAUSE_TX;
else if (lpa & ADVERTISE_PAUSE_CAP &&
lpa & ADVERTISE_PAUSE_ASYM &&
adv & ADVERTISE_PAUSE_ASYM)
*fc = PAUSE_TX;
else if (lpa & ADVERTISE_PAUSE_ASYM &&
adv & ADVERTISE_PAUSE_CAP)
*fc = PAUSE_RX;
else
*fc = 0;
}
} else {
err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
if (err)
return (err);
v &= BMCR_SPEED1000 | BMCR_SPEED100;
if (speed) {
if (v == (BMCR_SPEED1000 | BMCR_SPEED100))
*speed = SPEED_10000;
else if (v == BMCR_SPEED1000)
*speed = SPEED_1000;
else if (v == BMCR_SPEED100)
*speed = SPEED_100;
else
*speed = SPEED_10;
}
if (duplex)
*duplex = DUPLEX_FULL;
}
link = 1;
done:
if (link_ok)
*link_ok = link;
return (0);
}
static struct cphy_ops aq100x_ops = {
.reset = aq100x_reset,
.intr_enable = aq100x_intr_enable,
.intr_disable = aq100x_intr_disable,
.intr_clear = aq100x_intr_clear,
.intr_handler = aq100x_intr_handler,
.autoneg_enable = aq100x_autoneg_enable,
.autoneg_restart = aq100x_autoneg_restart,
.advertise = aq100x_advertise,
.set_loopback = aq100x_set_loopback,
.set_speed_duplex = aq100x_set_speed_duplex,
.get_link_status = aq100x_get_link_status,
.power_down = aq100x_power_down,
};
int
t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops)
{
struct cphy *phy = &pinfo->phy;
unsigned int v, v2, gpio, wait;
int err;
adapter_t *adapter = pinfo->adapter;
cphy_init(&pinfo->phy, adapter, pinfo, phy_addr, &aq100x_ops, mdio_ops,
SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI |
SUPPORTED_MISC_IRQ, "1000/10GBASE-T");
/*
* Hard reset the PHY.
*/
gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
msleep(1);
t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
/*
* Give it enough time to load the firmware and get ready for mdio.
*/
msleep(1000);
wait = 500; /* in 10ms increments */
do {
err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
if (err || v == 0xffff) {
/* Allow prep_adapter to succeed when ffff is read */
CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
phy_addr, err, v);
goto done;
}
v &= BMCR_RESET;
if (v)
msleep(10);
} while (v && --wait);
if (v) {
CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
phy_addr, v);
goto done; /* let prep_adapter succeed */
}
/* Firmware version check. */
(void) mdio_read(phy, MDIO_DEV_VEND1, AQ_FW_VERSION, &v);
if (v < 0x115)
CH_WARN(adapter, "PHY%d: unknown firmware %d.%d\n", phy_addr,
v >> 8, v & 0xff);
#if 0
/* The PHY should start in really-low-power mode. */
(void) mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMCR, &v);
if ((v & BMCR_PDOWN) == 0)
CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
phy_addr);
#endif
/*
* Verify XAUI and 1000-X settings, but let prep succeed no matter what.
*/
v = v2 = 0;
(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_RX_CFG, &v);
(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_TX_CFG, &v2);
if (v != 0x1b || v2 != 0x1b)
CH_WARN(adapter, "PHY%d: incorrect XAUI settings "
"(0x%x, 0x%x).\n", phy_addr, v, v2);
v = 0;
(void) mdio_read(phy, MDIO_DEV_XGXS, AQ_XAUI_KX_CFG, &v);
if ((v & 0xf) != 0xf)
CH_WARN(adapter, "PHY%d: incorrect 1000-X settings "
"(0x%x).\n", phy_addr, v);
(void) aq100x_set_defaults(phy);
done:
return (err);
}

View File

@ -56,7 +56,11 @@ enum {
};
enum {
SUPPORTED_IRQ = 1 << 24
SUPPORTED_LINK_IRQ = 1 << 24,
/* skip 25 */
SUPPORTED_MISC_IRQ = 1 << 26,
SUPPORTED_IRQ = (SUPPORTED_LINK_IRQ | SUPPORTED_MISC_IRQ),
POLL_LINK_1ST_TIME = 1 << 27
};
enum { /* adapter interrupt-maintained statistics */
@ -93,7 +97,7 @@ enum {
enum {
FW_VERSION_MAJOR = 7,
FW_VERSION_MINOR = 1,
FW_VERSION_MINOR = 7,
FW_VERSION_MICRO = 0
};
@ -484,6 +488,7 @@ struct cmac {
u64 rx_mcnt;
unsigned int toggle_cnt;
unsigned int txen;
unsigned int was_reset;
u64 rx_pause;
struct mac_stats stats;
};
@ -526,6 +531,7 @@ enum {
cphy_cause_link_change = 1,
cphy_cause_fifo_error = 2,
cphy_cause_module_change = 4,
cphy_cause_alarm = 8,
};
/* PHY module types */
@ -563,9 +569,10 @@ struct cphy_ops {
struct cphy {
u8 addr; /* PHY address */
u8 modtype; /* PHY module type */
short priv; /* scratch pad */
unsigned int priv; /* scratch pad */
unsigned int caps; /* PHY capabilities */
adapter_t *adapter; /* associated adapter */
pinfo_t *pinfo; /* associated port */
const char *desc; /* PHY description */
unsigned long fifo_errors; /* FIFO over/under-flows */
const struct cphy_ops *ops; /* PHY operations */
@ -589,7 +596,7 @@ static inline int mdio_write(struct cphy *phy, int mmd, int reg,
}
/* Convenience initializer */
static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
static inline void cphy_init(struct cphy *phy, adapter_t *adapter, pinfo_t *pinfo,
int phy_addr, struct cphy_ops *phy_ops,
const struct mdio_ops *mdio_ops, unsigned int caps,
const char *desc)
@ -597,6 +604,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
phy->addr = (u8)phy_addr;
phy->caps = caps;
phy->adapter = adapter;
phy->pinfo = pinfo;
phy->desc = desc;
phy->ops = phy_ops;
if (mdio_ops) {
@ -742,7 +750,7 @@ int t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n,
int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
u64 *buf);
int t3_mac_reset(struct cmac *mac);
int t3_mac_init(struct cmac *mac);
void t3b_pcs_reset(struct cmac *mac);
void t3_mac_disable_exact_filters(struct cmac *mac);
void t3_mac_enable_exact_filters(struct cmac *mac);
@ -827,25 +835,33 @@ int t3_vsc7323_enable(adapter_t *adap, int port, int which);
int t3_vsc7323_disable(adapter_t *adap, int port, int which);
const struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac);
int t3_i2c_read8(adapter_t *adapter, int chained, u8 *valp);
int t3_i2c_write8(adapter_t *adapter, int chained, u8 val);
int t3_mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr, int reg_addr,
unsigned int *valp);
int t3_mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr, int reg_addr,
unsigned int val);
int t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port);
int t3_ael1002_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_ael1006_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_ael2005_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_ael2020_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_qt2045_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_tn1010_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_tn1010_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_xaui_direct_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
int t3_aq100x_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops);
#endif /* __CHELSIO_COMMON_H */

View File

@ -294,12 +294,13 @@ static struct cphy_ops mv88e1xxx_ops = {
};
#endif
int t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops)
{
struct cphy *phy = &pinfo->phy;
int err;
cphy_init(phy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops,
cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &mv88e1xxx_ops, mdio_ops,
SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");

View File

@ -280,6 +280,11 @@ $FreeBSD$
#define V_RSPQ7STARVED(x) ((x) << S_RSPQ7STARVED)
#define F_RSPQ7STARVED V_RSPQ7STARVED(1U)
#define S_RSPQXSTARVED 0
#define M_RSPQXSTARVED 0xff
#define V_RSPQXSTARVED(x) ((x) << S_RSPQXSTARVED)
#define G_RSPQXSTARVED(x) (((x) >> S_RSPQXSTARVED) & M_RSPQXSTARVED)
#define S_RSPQ0DISABLED 8
#define V_RSPQ0DISABLED(x) ((x) << S_RSPQ0DISABLED)
#define F_RSPQ0DISABLED V_RSPQ0DISABLED(1U)
@ -376,6 +381,11 @@ $FreeBSD$
#define V_FL15EMPTY(x) ((x) << S_FL15EMPTY)
#define F_FL15EMPTY V_FL15EMPTY(1U)
#define S_FLXEMPTY 16
#define M_FLXEMPTY 0xffff
#define V_FLXEMPTY(x) ((x) << S_FLXEMPTY)
#define G_FLXEMPTY(x) (((x) >> S_FLXEMPTY) & M_FLXEMPTY)
#define A_SG_EGR_PRI_CNT 0x50
#define S_EGRERROPCODE 24
@ -6235,10 +6245,28 @@ $FreeBSD$
#define V_ACK(x) ((x) << S_ACK)
#define F_ACK V_ACK(1U)
#define S_I2C_DATA 0
#define M_I2C_DATA 0xff
#define V_I2C_DATA(x) ((x) << S_I2C_DATA)
#define G_I2C_DATA(x) (((x) >> S_I2C_DATA) & M_I2C_DATA)
#define S_I2C_BUSY 31
#define V_I2C_BUSY(x) ((x) << S_I2C_BUSY)
#define F_I2C_BUSY V_I2C_BUSY(1U)
#define S_I2C_ACK 30
#define V_I2C_ACK(x) ((x) << S_I2C_ACK)
#define F_I2C_ACK V_I2C_ACK(1U)
#define S_I2C_CONT 1
#define V_I2C_CONT(x) ((x) << S_I2C_CONT)
#define F_I2C_CONT V_I2C_CONT(1U)
#define S_I2C_RDWR 0
#define V_I2C_RDWR(x) ((x) << S_I2C_RDWR)
#define F_I2C_READ V_I2C_RDWR(0U)
#define F_I2C_WRITE V_I2C_RDWR(1U)
/* registers for module MI1 */
#define MI1_BASE_ADDR 0x6b0

View File

@ -188,6 +188,62 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
return 0;
}
/*
* Low-level I2C read and write routines. These simply read and write a
* single byte with the option of indicating a "continue" if another operation
* is to be chained. Generally most code will use higher-level routines to
* read and write to I2C Slave Devices.
*/
#define I2C_ATTEMPTS 100
/*
* Read an 8-bit value from the I2C bus. If the "chained" parameter is
* non-zero then a STOP bit will not be written after the read command. On
* error (the read timed out, etc.), a negative errno will be returned (e.g.
* -EAGAIN, etc.). On success, the 8-bit value read from the I2C bus is
* stored into the buffer *valp and the value of the I2C ACK bit is returned
* as a 0/1 value.
*/
int t3_i2c_read8(adapter_t *adapter, int chained, u8 *valp)
{
int ret;
u32 opval;
MDIO_LOCK(adapter);
t3_write_reg(adapter, A_I2C_OP,
F_I2C_READ | (chained ? F_I2C_CONT : 0));
ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0,
I2C_ATTEMPTS, 10, &opval);
if (ret >= 0) {
ret = ((opval & F_I2C_ACK) == F_I2C_ACK);
*valp = G_I2C_DATA(t3_read_reg(adapter, A_I2C_DATA));
}
MDIO_UNLOCK(adapter);
return ret;
}
/*
* Write an 8-bit value to the I2C bus. If the "chained" parameter is
* non-zero, then a STOP bit will not be written after the write command. On
* error (the write timed out, etc.), a negative errno will be returned (e.g.
* -EAGAIN, etc.). On success, the value of the I2C ACK bit is returned as a
* 0/1 value.
*/
int t3_i2c_write8(adapter_t *adapter, int chained, u8 val)
{
int ret;
u32 opval;
MDIO_LOCK(adapter);
t3_write_reg(adapter, A_I2C_DATA, V_I2C_DATA(val));
t3_write_reg(adapter, A_I2C_OP,
F_I2C_WRITE | (chained ? F_I2C_CONT : 0));
ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0,
I2C_ATTEMPTS, 10, &opval);
if (ret >= 0)
ret = ((opval & F_I2C_ACK) == F_I2C_ACK);
MDIO_UNLOCK(adapter);
return ret;
}
/*
* Initialize MI1.
*/
@ -515,7 +571,12 @@ static struct adapter_info t3_adap_info[] = {
F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
{ S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
&mi1_mdio_ext_ops, "Chelsio N310" }
&mi1_mdio_ext_ops, "Chelsio T310" },
{ 1, 0, 0,
F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL,
{ S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
&mi1_mdio_ext_ops, "Chelsio N320E-G2" },
};
/*
@ -528,7 +589,7 @@ const struct adapter_info *t3_get_adapter_info(unsigned int id)
}
struct port_type_info {
int (*phy_prep)(struct cphy *phy, adapter_t *adapter, int phy_addr,
int (*phy_prep)(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *ops);
};
@ -542,6 +603,8 @@ static struct port_type_info port_types[] = {
{ t3_qt2045_phy_prep },
{ t3_ael1006_phy_prep },
{ t3_tn1010_phy_prep },
{ t3_aq100x_phy_prep },
{ t3_ael2020_phy_prep },
};
#define VPD_ENTRY(name, len) \
@ -669,6 +732,125 @@ static unsigned int hex2int(unsigned char c)
return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
}
/**
* get_desc_len - get the length of a vpd descriptor.
* @adapter: the adapter
* @offset: first byte offset of the vpd descriptor
*
* Retrieves the length of the small/large resource
* data type starting at offset.
*/
static int get_desc_len(adapter_t *adapter, u32 offset)
{
u32 read_offset, tmp, shift, len = 0;
u8 tag, buf[8];
int ret;
read_offset = offset & 0xfffffffc;
shift = offset & 0x03;
ret = t3_seeprom_read(adapter, read_offset, &tmp);
if (ret < 0)
return ret;
*((u32 *)buf) = cpu_to_le32(tmp);
tag = buf[shift];
if (tag & 0x80) {
ret = t3_seeprom_read(adapter, read_offset + 4, &tmp);
if (ret < 0)
return ret;
*((u32 *)(&buf[4])) = cpu_to_le32(tmp);
len = (buf[shift + 1] & 0xff) +
((buf[shift+2] << 8) & 0xff00) + 3;
} else
len = (tag & 0x07) + 1;
return len;
}
/**
* is_end_tag - Check if a vpd tag is the end tag.
* @adapter: the adapter
* @offset: first byte offset of the tag
*
* Checks if the tag located at offset is the end tag.
*/
static int is_end_tag(adapter_t * adapter, u32 offset)
{
u32 read_offset, shift, ret, tmp;
u8 buf[4];
read_offset = offset & 0xfffffffc;
shift = offset & 0x03;
ret = t3_seeprom_read(adapter, read_offset, &tmp);
if (ret)
return ret;
*((u32 *)buf) = cpu_to_le32(tmp);
if (buf[shift] == 0x78)
return 1;
else
return 0;
}
/**
* t3_get_vpd_len - computes the length of a vpd structure
* @adapter: the adapter
* @vpd: contains the offset of first byte of vpd
*
* Computes the lentgh of the vpd structure starting at vpd->offset.
*/
int t3_get_vpd_len(adapter_t * adapter, struct generic_vpd *vpd)
{
u32 len=0, offset;
int inc, ret;
offset = vpd->offset;
while (offset < (vpd->offset + MAX_VPD_BYTES)) {
ret = is_end_tag(adapter, offset);
if (ret < 0)
return ret;
else if (ret == 1)
break;
inc = get_desc_len(adapter, offset);
if (inc < 0)
return inc;
len += inc;
offset += inc;
}
return (len + 1);
}
/**
* t3_read_vpd - reads the stream of bytes containing a vpd structure
* @adapter: the adapter
* @vpd: contains a buffer that would hold the stream of bytes
*
* Reads the vpd structure starting at vpd->offset into vpd->data,
* the length of the byte stream to read is vpd->len.
*/
int t3_read_vpd(adapter_t *adapter, struct generic_vpd *vpd)
{
u32 i, ret;
for (i = 0; i < vpd->len; i += 4) {
ret = t3_seeprom_read(adapter, vpd->offset + i,
(u32 *) &(vpd->data[i]));
if (ret)
return ret;
}
return 0;
}
/**
* get_vpd_params - read VPD parameters from VPD EEPROM
* @adapter: adapter to read
@ -1313,11 +1495,6 @@ static void t3_clear_faults(adapter_t *adapter, int port_id)
struct port_info *pi = adap2pinfo(adapter, port_id);
struct cmac *mac = &pi->mac;
t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset,
F_ENDROPPKT, 0);
t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset, F_CLRSTATS, 1);
if (adapter->params.nports <= 2) {
t3_xgm_intr_disable(adapter, pi->port_id);
t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
@ -1339,7 +1516,7 @@ static void t3_clear_faults(adapter_t *adapter, int port_id)
*/
void t3_link_changed(adapter_t *adapter, int port_id)
{
int link_ok, speed, duplex, fc, link_fault, link_change;
int link_ok, speed, duplex, fc, link_fault;
struct port_info *pi = adap2pinfo(adapter, port_id);
struct cphy *phy = &pi->phy;
struct cmac *mac = &pi->mac;
@ -1353,6 +1530,16 @@ void t3_link_changed(adapter_t *adapter, int port_id)
phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
if (lc->requested_fc & PAUSE_AUTONEG)
fc &= lc->requested_fc;
else
fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
/* Update mac speed before checking for link fault. */
if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE &&
(speed != lc->speed || duplex != lc->duplex || fc != lc->fc))
t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
/*
* Check for link faults if any of these is true:
* a) A link fault is suspected, and PHY says link ok
@ -1368,11 +1555,8 @@ void t3_link_changed(adapter_t *adapter, int port_id)
pi->link_fault = LF_YES;
}
/* Don't report link up or any other change */
/* Don't report link up */
link_ok = 0;
speed = lc->speed;
duplex = lc->duplex;
fc = lc->fc;
} else {
/* clear faults here if this was a false alarm. */
if (pi->link_fault == LF_MAYBE &&
@ -1383,37 +1567,29 @@ void t3_link_changed(adapter_t *adapter, int port_id)
}
}
if (lc->requested_fc & PAUSE_AUTONEG)
fc &= lc->requested_fc;
else
fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
if (link_ok == lc->link_ok && speed == lc->speed &&
duplex == lc->duplex && fc == lc->fc)
return; /* nothing changed */
link_change = link_ok != lc->link_ok;
lc->link_ok = (unsigned char)link_ok;
lc->speed = speed < 0 ? SPEED_INVALID : speed;
lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
lc->fc = fc;
if (link_ok) {
/* down -> up, or up -> up with changed settings */
if (link_change && adapter->params.rev > 0 &&
uses_xaui(adapter)) {
t3b_pcs_reset(mac);
if (adapter->params.rev > 0 && uses_xaui(adapter)) {
t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
F_TXACTENABLE | F_RXEN);
}
if (speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
/* Set MAC settings to match PHY. */
t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
lc->fc = (unsigned char)fc;
}
t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset,
F_ENDROPPKT, 0);
t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset,
F_CLRSTATS, 1);
t3_clear_faults(adapter, port_id);
} else {
@ -1450,7 +1626,9 @@ void t3_link_changed(adapter_t *adapter, int port_id)
t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, F_RXEN);
}
t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc,
mac->was_reset);
mac->was_reset = 0;
}
/**
@ -1478,6 +1656,7 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
if (fc & PAUSE_RX)
lc->advertising |= ADVERTISED_Pause;
}
phy->ops->advertise(phy, lc->advertising);
if (lc->autoneg == AUTONEG_DISABLE) {
@ -1490,7 +1669,7 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
/* PR 5666. Power phy up when doing an ifup */
if (!is_10G(phy->adapter))
phy->ops->power_down(phy, 0);
phy->ops->power_down(phy, 0);
} else
phy->ops->autoneg_enable(phy);
} else {
@ -2020,6 +2199,10 @@ int t3_phy_intr_handler(adapter_t *adapter)
p->phy.fifo_errors++;
if (phy_cause & cphy_cause_module_change)
t3_os_phymod_changed(adapter, i);
if (phy_cause & cphy_cause_alarm)
CH_WARN(adapter, "Operation affected due to "
"adverse environment. Check the spec "
"sheet for corrective action.");
}
}
@ -3871,7 +4054,7 @@ static void config_pcie(adapter_t *adap)
{ 201, 321, 258, 450, 834, 1602 }
};
u16 val;
u16 val, devid;
unsigned int log2_width, pldsize;
unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
@ -3880,6 +4063,18 @@ static void config_pcie(adapter_t *adap)
&val);
pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
/*
* Gen2 adapter pcie bridge compatibility requires minimum
* Max_Read_Request_size
*/
t3_os_pci_read_config_2(adap, 0x2, &devid);
if (devid == 0x37) {
t3_os_pci_write_config_2(adap,
adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
val & ~PCI_EXP_DEVCTL_READRQ & ~PCI_EXP_DEVCTL_PAYLOAD);
pldsize = 0;
}
t3_os_pci_read_config_2(adap,
adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
&val);
@ -3934,7 +4129,7 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params)
goto out_err;
if (adapter->params.nports > 2)
t3_mac_reset(&adap2pinfo(adapter, 0)->mac);
t3_mac_init(&adap2pinfo(adapter, 0)->mac);
if (vpd->mclk) {
partition_mem(adapter, &adapter->params.tp);
@ -4098,15 +4293,25 @@ static void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7,
void mac_prep(struct cmac *mac, adapter_t *adapter, int index)
{
u16 devid;
mac->adapter = adapter;
mac->multiport = adapter->params.nports > 2;
if (mac->multiport) {
mac->ext_port = (unsigned char)index;
mac->nucast = 8;
index = 0;
} else
mac->nucast = 1;
/* Gen2 adapter uses VPD xauicfg[] to notify driver which MAC
is connected to each port, its suppose to be using xgmac0 for both ports
*/
t3_os_pci_read_config_2(adapter, 0x2, &devid);
if (mac->multiport ||
(!adapter->params.vpd.xauicfg[1] && (devid==0x37)))
index = 0;
mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
if (adapter->params.rev == 0 && uses_xaui(adapter)) {
@ -4336,7 +4541,7 @@ int __devinit t3_prep_adapter(adapter_t *adapter,
if (j >= ARRAY_SIZE(adapter->params.vpd.port_type))
return -EINVAL;
}
ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
ret = pti->phy_prep(p, ai->phy_base_addr + j,
ai->mdio_ops);
if (ret)
return ret;
@ -4408,7 +4613,7 @@ int t3_reinit_adapter(adapter_t *adap)
if (j >= ARRAY_SIZE(adap->params.vpd.port_type))
return -EINVAL;
}
ret = pti->phy_prep(&p->phy, adap, p->phy.addr, NULL);
ret = pti->phy_prep(p, p->phy.addr, NULL);
if (ret)
return ret;
p->phy.ops->power_down(&p->phy, 1);

View File

@ -209,10 +209,10 @@ static struct cphy_ops tn1010_ops = {
};
#endif
int t3_tn1010_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
int t3_tn1010_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops)
{
cphy_init(phy, adapter, phy_addr, &tn1010_ops, mdio_ops,
cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &tn1010_ops, mdio_ops,
SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_AUI | SUPPORTED_TP,
"1000/10GBASE-T");

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
enum {
VSC8211_SIGDET_CTRL = 19,
VSC8211_EXT_CTRL = 23,
VSC8211_PHY_CTRL = 24,
VSC8211_INTR_ENABLE = 25,
VSC8211_INTR_STATUS = 26,
VSC8211_LED_CTRL = 27,
@ -375,13 +376,62 @@ static struct cphy_ops vsc8211_fiber_ops = {
};
#endif
int t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
#define VSC8211_PHY_CTRL 24
#define S_VSC8211_TXFIFODEPTH 7
#define M_VSC8211_TXFIFODEPTH 0x7
#define V_VSC8211_TXFIFODEPTH(x) ((x) << S_VSC8211_TXFIFODEPTH)
#define G_VSC8211_TXFIFODEPTH(x) (((x) >> S_VSC8211_TXFIFODEPTH) & M_VSC8211_TXFIFODEPTH)
#define S_VSC8211_RXFIFODEPTH 4
#define M_VSC8211_RXFIFODEPTH 0x7
#define V_VSC8211_RXFIFODEPTH(x) ((x) << S_VSC8211_RXFIFODEPTH)
#define G_VSC8211_RXFIFODEPTH(x) (((x) >> S_VSC8211_RXFIFODEPTH) & M_VSC8211_RXFIFODEPTH)
int t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port)
{
/* TX FIFO Depth set bits 9:7 to 100 (IEEE mode) */
unsigned int val = 4;
unsigned int currentregval;
unsigned int regval;
int err;
/* Retrieve the port info structure from adater_t */
struct port_info *portinfo = adap2pinfo(adap, port);
/* What phy is this */
struct cphy *phy = &portinfo->phy;
/* Read the current value of the PHY control Register */
err = mdio_read(phy, 0, VSC8211_PHY_CTRL, &currentregval);
if (err)
return err;
/* IEEE mode supports up to 1518 bytes */
/* mtu does not contain the header + FCS (18 bytes) */
if (mtu > 1500)
/*
* If using a packet size > 1500 set TX FIFO Depth bits
* 9:7 to 011 (Jumbo packet mode)
*/
val = 3;
regval = V_VSC8211_TXFIFODEPTH(val) | V_VSC8211_RXFIFODEPTH(val) |
(currentregval & ~V_VSC8211_TXFIFODEPTH(M_VSC8211_TXFIFODEPTH) &
~V_VSC8211_RXFIFODEPTH(M_VSC8211_RXFIFODEPTH));
return mdio_write(phy, 0, VSC8211_PHY_CTRL, regval);
}
int t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr,
const struct mdio_ops *mdio_ops)
{
struct cphy *phy = &pinfo->phy;
int err;
unsigned int val;
cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops,
cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &vsc8211_ops, mdio_ops,
SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");

View File

@ -41,6 +41,28 @@ static inline int macidx(const struct cmac *mac)
return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
}
/*
* Returns a reasonable A_XGM_RESET_CTRL value for the mac specified.
*/
static inline int xgm_reset_ctrl(const struct cmac *mac)
{
adapter_t *adap = mac->adapter;
int val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
if (is_10G(adap)) {
int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset);
val |= F_PCS_RESET_;
if (G_PORTSPEED(cfg) != 3) /* not running at 10G */
val |= F_XG2G_RESET_;
} else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
else
val |= F_RGMII_RESET_ | F_XG2G_RESET_;
return (val);
}
static void xaui_serdes_reset(struct cmac *mac)
{
static const unsigned int clear[] = {
@ -81,12 +103,12 @@ void t3b_pcs_reset(struct cmac *mac)
}
/**
* t3_mac_reset - reset a MAC
* @mac: the MAC to reset
* t3_mac_init - initialize a MAC
* @mac: the MAC to initialize
*
* Reset the given MAC.
* Initialize the given MAC.
*/
int t3_mac_reset(struct cmac *mac)
int t3_mac_init(struct cmac *mac)
{
static struct addr_val_pair mac_reset_avp[] = {
{ A_XGM_TX_CTRL, 0 },
@ -138,7 +160,7 @@ int t3_mac_reset(struct cmac *mac)
if (mac->multiport) {
t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
MAX_FRAME_SIZE - 4);
V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4));
t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
F_DISPREAMBLE);
t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
@ -154,13 +176,7 @@ int t3_mac_reset(struct cmac *mac)
V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
if (!mac->multiport)
val |= F_XG2G_RESET_;
if (uses_xaui(adap))
val |= F_PCS_RESET_;
else
val |= F_RGMII_RESET_;
val = xgm_reset_ctrl(mac);
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
if ((val & F_PCS_RESET_) && adap->params.rev) {
@ -172,16 +188,17 @@ int t3_mac_reset(struct cmac *mac)
return 0;
}
static int t3b2_mac_reset(struct cmac *mac)
static int t3_mac_reset(struct cmac *mac, int portspeed)
{
u32 val;
u32 val, store_mps;
adapter_t *adap = mac->adapter;
unsigned int oft = mac->offset;
int idx = macidx(mac);
unsigned int store;
/* Stop egress traffic to xgm*/
if (!macidx(mac))
store_mps = t3_read_reg(adap, A_MPS_CFG);
if (!idx)
t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
else
t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
@ -198,7 +215,7 @@ static int t3b2_mac_reset(struct cmac *mac)
/* Store A_TP_TX_DROP_CFG_CH0 */
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
store = t3_read_reg(adap, A_TP_PIO_DATA);
msleep(10);
@ -209,44 +226,55 @@ static int t3b2_mac_reset(struct cmac *mac)
/* Check for xgm Rx fifo empty */
/* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
0x80000000, 1, 1000, 2)) {
CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
macidx(mac));
0x80000000, 1, 1000, 2) && portspeed < 0) {
CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx);
return -1;
}
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
if (portspeed >= 0) {
u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft);
val = F_MAC_RESET_;
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
else
val |= F_RGMII_RESET_ | F_XG2G_RESET_;
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
if ((val & F_PCS_RESET_) && adap->params.rev) {
msleep(1);
t3b_pcs_reset(mac);
/*
* safespeedchange: wipes out pretty much all XGMAC registers.
*/
t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE,
portspeed | F_SAFESPEEDCHANGE);
(void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
F_SAFESPEEDCHANGE, 0);
(void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
t3_mac_init(mac);
t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr);
} else {
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
val = xgm_reset_ctrl(mac);
t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
if ((val & F_PCS_RESET_) && adap->params.rev) {
msleep(1);
t3b_pcs_reset(mac);
}
t3_write_reg(adap, A_XGM_RX_CFG + oft,
F_DISPAUSEFRAMES | F_EN1536BFRAMES |
F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
}
t3_write_reg(adap, A_XGM_RX_CFG + oft,
F_DISPAUSEFRAMES | F_EN1536BFRAMES |
F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
/* Restore the DROP_CFG */
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
t3_write_reg(adap, A_TP_PIO_DATA, store);
/* Resume egress traffic to xgm */
if (!macidx(mac))
t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
else
t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
store_mps);
/* Set: re-enable NIC traffic */
t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT);
return 0;
}
@ -409,6 +437,8 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
int ipg;
unsigned int thres, v, reg;
adapter_t *adap = mac->adapter;
unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
unsigned int orig_mtu=mtu;
/*
* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
@ -422,6 +452,14 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
if (mac->multiport)
return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
/* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
if (port_type == 2) {
int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));
if (err)
return err;
}
if (adap->params.rev >= T3_REV_B2 &&
(t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
t3_mac_disable_exact_filters(mac);
@ -507,10 +545,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
if (duplex >= 0 && duplex != DUPLEX_FULL)
return -EINVAL;
if (mac->multiport) {
u32 rx_max_pkt_size =
G_RXMAXPKTSIZE(t3_read_reg(adap,
A_XGM_RX_MAX_PKT_SIZE + oft));
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
@ -529,15 +569,27 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
else
return -EINVAL;
t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
V_PORTSPEED(M_PORTSPEED), val);
if (!uses_xaui(adap)) /* T302 */
t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
V_PORTSPEED(M_PORTSPEED), val);
else {
u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
t3_mac_reset(mac, val);
mac->was_reset = 1;
}
}
}
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
if (fc & PAUSE_TX)
val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
if (fc & PAUSE_TX) {
u32 rx_max_pkt_size =
G_RXMAXPKTSIZE(t3_read_reg(adap,
A_XGM_RX_MAX_PKT_SIZE + oft));
val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
}
t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
@ -618,18 +670,12 @@ int t3_mac_disable(struct cmac *mac, int which)
mac->txen = 0;
}
if (which & MAC_DIRECTION_RX) {
int val = F_MAC_RESET_;
int val = xgm_reset_ctrl(mac);
t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
F_PCS_RESET_, 0);
msleep(100);
t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
else
val |= F_RGMII_RESET_ | F_XG2G_RESET_;
t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
}
return 0;
@ -650,10 +696,15 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
tx_xcnt = 1; /* By default tx_xcnt is making progress*/
tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
u32 cfg, active, enforcepkt;
tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_TX_SPI4_SOP_EOP_CNT +
mac->offset)));
if (tx_xcnt == 0) {
cfg = t3_read_reg(adap, A_MPS_CFG);
active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE;
enforcepkt = cfg & F_ENFORCEPKT;
if (active && enforcepkt && (tx_xcnt == 0)) {
t3_write_reg(adap, A_TP_PIO_ADDR,
A_TP_TX_DROP_CNT_CH0 + macidx(mac));
tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
@ -691,7 +742,7 @@ out:
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
mac->toggle_cnt++;
} else if (status == 2) {
t3b2_mac_reset(mac);
t3_mac_reset(mac, -1);
mac->toggle_cnt = 0;
}
return status;

View File

@ -361,8 +361,6 @@ struct adapter {
struct callout cxgb_tick_ch;
struct callout sge_timer_ch;
unsigned int check_task_cnt;
/* Register lock for use by the hardware layer */
struct mtx mdio_lock;
struct mtx elmer_lock;
@ -500,7 +498,7 @@ int t3_os_find_pci_capability(adapter_t *adapter, int cap);
int t3_os_pci_save_state(struct adapter *adapter);
int t3_os_pci_restore_state(struct adapter *adapter);
void t3_os_link_changed(adapter_t *adapter, int port_id, int link_status,
int speed, int duplex, int fc);
int speed, int duplex, int fc, int mac_was_reset);
void t3_os_phymod_changed(struct adapter *adap, int port_id);
void t3_sge_err_intr_handler(adapter_t *adapter);
int t3_offload_tx(struct t3cdev *, struct mbuf *);

View File

@ -116,7 +116,7 @@ static int cxgb_get_regs_len(void);
static int offload_open(struct port_info *pi);
static void touch_bars(device_t dev);
static int offload_close(struct t3cdev *tdev);
int t3_detect_link_fault(adapter_t *adapter, int port_id);
static void cxgb_update_mac_settings(struct port_info *p);
static device_method_t cxgb_controller_methods[] = {
DEVMETHOD(device_probe, cxgb_controller_probe),
@ -291,7 +291,9 @@ struct cxgb_ident {
{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
{PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
{PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "N310E"},
{PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "T3C10"},
{PCI_VENDOR_ID_CHELSIO, 0x0036, 3, "S320E-CR"},
{PCI_VENDOR_ID_CHELSIO, 0x0037, 7, "N320E-G2"},
{0, 0, 0, NULL}
};
@ -508,6 +510,9 @@ cxgb_controller_attach(device_t dev)
sc->bh = rman_get_bushandle(sc->regs_res);
sc->mmio_len = rman_get_size(sc->regs_res);
for (i = 0; i < MAX_NPORTS; i++)
sc->port[i].adapter = sc;
if (t3_prep_adapter(sc, ai, 1) < 0) {
printf("prep adapter failed\n");
error = ENODEV;
@ -1222,8 +1227,8 @@ t3_os_pci_restore_state(struct adapter *sc)
/**
* t3_os_link_changed - handle link status changes
* @adapter: the adapter associated with the link change
* @port_id: the port index whose limk status has changed
* @sc: the adapter associated with the link change
* @port_id: the port index whose link status has changed
* @link_status: the new status of the link
* @speed: the new speed setting
* @duplex: the new duplex setting
@ -1235,7 +1240,7 @@ t3_os_pci_restore_state(struct adapter *sc)
*/
void
t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
int duplex, int fc)
int duplex, int fc, int mac_was_reset)
{
struct port_info *pi = &adapter->port[port_id];
struct ifnet *ifp = pi->ifp;
@ -1243,6 +1248,13 @@ t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
/* no race with detach, so ifp should always be good */
KASSERT(ifp, ("%s: if detached.", __func__));
/* Reapply mac settings if they were lost due to a reset */
if (mac_was_reset) {
PORT_LOCK(pi);
cxgb_update_mac_settings(pi);
PORT_UNLOCK(pi);
}
if (link_status) {
ifp->if_baudrate = IF_Mbps(speed);
if_link_state_change(ifp, LINK_STATE_UP);
@ -1917,7 +1929,7 @@ cxgb_init_synchronized(struct port_info *p)
PORT_LOCK(p);
t3_port_intr_enable(sc, p->port_id);
if (!mac->multiport)
t3_mac_reset(mac);
t3_mac_init(mac);
cxgb_update_mac_settings(p);
t3_link_start(&p->phy, mac, &p->link_config);
t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
@ -1992,7 +2004,7 @@ cxgb_uninit_synchronized(struct port_info *pi)
PORT_UNLOCK(pi);
pi->link_config.link_ok = 0;
t3_os_link_changed(sc, pi->port_id, 0, 0, 0, 0);
t3_os_link_changed(sc, pi->port_id, 0, 0, 0, 0, 0);
if ((sc->open_device_map & PORT_MASK) == 0)
offload_close(&sc->tdev);
@ -2335,6 +2347,19 @@ cxgb_ext_intr_handler(void *arg, int count)
ADAPTER_UNLOCK(sc);
}
static inline int
link_poll_needed(struct port_info *p)
{
struct cphy *phy = &p->phy;
if (phy->caps & POLL_LINK_1ST_TIME) {
p->phy.caps &= ~POLL_LINK_1ST_TIME;
return (1);
}
return (p->link_fault || !(phy->caps & SUPPORTED_LINK_IRQ));
}
static void
check_link_status(adapter_t *sc)
{
@ -2346,7 +2371,7 @@ check_link_status(adapter_t *sc)
if (!isset(&sc->open_device_map, p->port_id))
continue;
if (p->link_fault || !(p->phy.caps & SUPPORTED_IRQ))
if (link_poll_needed(p))
t3_link_changed(sc, i);
}
}
@ -2366,7 +2391,8 @@ check_t3b2_mac(struct adapter *sc)
struct ifnet *ifp = p->ifp;
#endif
if (!isset(&sc->open_device_map, p->port_id))
if (!isset(&sc->open_device_map, p->port_id) || p->link_fault ||
!p->link_config.link_ok)
continue;
KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING,
@ -2414,7 +2440,6 @@ cxgb_tick_handler(void *arg, int count)
return;
check_link_status(sc);
sc->check_task_cnt++;
if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
check_t3b2_mac(sc);

View File

@ -48,6 +48,7 @@ $FreeBSD$
#define _CXGB_OSDEP_H_
typedef struct adapter adapter_t;
typedef struct port_info pinfo_t;
struct sge_rspq;
enum {
@ -247,10 +248,10 @@ static const int debug_flags = DBG_RX;
#define MII_CTRL1000 MII_100T2CR
#define ADVERTISE_PAUSE_CAP ANAR_FC
#define ADVERTISE_PAUSE_ASYM ANAR_X_PAUSE_ASYM
#define ADVERTISE_PAUSE ANAR_X_PAUSE_SYM
#define ADVERTISE_1000HALF ANAR_X_HD
#define ADVERTISE_1000FULL ANAR_X_FD
#define ADVERTISE_PAUSE_ASYM 0x800
#define ADVERTISE_PAUSE ANAR_FC
#define ADVERTISE_1000HALF 0x100
#define ADVERTISE_1000FULL 0x200
#define ADVERTISE_10FULL ANAR_10_FD
#define ADVERTISE_10HALF ANAR_10
#define ADVERTISE_100FULL ANAR_TX_FD
@ -266,17 +267,18 @@ static const int debug_flags = DBG_RX;
#define ADVERTISE_NPAGE ANAR_NP
/* Standard PCI Extended Capaibilities definitions */
#define PCI_CAP_ID_VPD 0x03
#define PCI_VPD_ADDR 2
/* Standard PCI Extended Capabilities definitions */
#define PCI_CAP_ID_VPD PCIY_VPD
#define PCI_VPD_ADDR PCIR_VPD_ADDR
#define PCI_VPD_ADDR_F 0x8000
#define PCI_VPD_DATA 4
#define PCI_VPD_DATA PCIR_VPD_DATA
#define PCI_CAP_ID_EXP 0x10
#define PCI_EXP_DEVCTL 8
#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0
#define PCI_EXP_LNKCTL 16
#define PCI_EXP_LNKSTA 18
#define PCI_CAP_ID_EXP PCIY_EXPRESS
#define PCI_EXP_DEVCTL PCIR_EXPRESS_DEVICE_CTL
#define PCI_EXP_DEVCTL_PAYLOAD PCIM_EXP_CTL_MAX_PAYLOAD
#define PCI_EXP_DEVCTL_READRQ PCIM_EXP_CTL_MAX_READ_REQUEST
#define PCI_EXP_LNKCTL PCIR_EXPRESS_LINK_CTL
#define PCI_EXP_LNKSTA PCIR_EXPRESS_LINK_STA
/*
* Linux compatibility macros

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ CXGB = ${.CURDIR}/../../../dev/cxgb
KMOD= if_cxgb
SRCS= cxgb_mc5.c cxgb_vsc8211.c cxgb_ael1002.c cxgb_mv88e1xxx.c
SRCS+= cxgb_xgmac.c cxgb_vsc7323.c cxgb_t3_hw.c cxgb_main.c
SRCS+= cxgb_xgmac.c cxgb_vsc7323.c cxgb_t3_hw.c cxgb_main.c cxgb_aq100x.c
SRCS+= cxgb_sge.c cxgb_offload.c cxgb_tn1010.c
SRCS+= device_if.h bus_if.h pci_if.h
SRCS+= opt_inet.h opt_zero.h opt_sched.h