#include "bge_impl.h"
#define BIS(w, b) (((w) & (b)) ? B_TRUE : B_FALSE)
#define BIC(w, b) (((w) & (b)) ? B_FALSE : B_TRUE)
#define UPORDOWN(x) ((x) ? "up" : "down")
#define BGE_DBG BGE_DBG_PHY
#define BGE_COPPER_WIRESPEED B_TRUE
#define BGE_COPPER_IDLEOFF B_FALSE
static const int16_t bge_copper_link_speed[] = {
0,
10,
10,
100,
0,
100,
1000,
1000
};
static const int8_t bge_copper_link_duplex[] = {
LINK_DUPLEX_UNKNOWN,
LINK_DUPLEX_HALF,
LINK_DUPLEX_FULL,
LINK_DUPLEX_HALF,
LINK_DUPLEX_UNKNOWN,
LINK_DUPLEX_FULL,
LINK_DUPLEX_HALF,
LINK_DUPLEX_FULL
};
static const int16_t bge_copper_link_speed_5906[] = {
0,
10,
10,
100,
0,
100,
0,
0
};
static const int8_t bge_copper_link_duplex_5906[] = {
LINK_DUPLEX_UNKNOWN,
LINK_DUPLEX_HALF,
LINK_DUPLEX_FULL,
LINK_DUPLEX_HALF,
LINK_DUPLEX_UNKNOWN,
LINK_DUPLEX_FULL,
LINK_DUPLEX_UNKNOWN,
LINK_DUPLEX_UNKNOWN
};
#if BGE_DEBUGGING
static void
bge_phydump(bge_t *bgep, uint16_t mii_status, uint16_t aux)
{
uint16_t regs[32];
int i;
ASSERT(mutex_owned(bgep->genlock));
for (i = 0; i < 32; ++i)
switch (i) {
default:
regs[i] = bge_mii_get16(bgep, i);
break;
case MII_STATUS:
regs[i] = mii_status;
break;
case MII_AUX_STATUS:
regs[i] = aux;
break;
case 0x0b: case 0x0c: case 0x0d: case 0x0e:
case 0x15: case 0x16: case 0x17:
case 0x1c:
case 0x1f:
regs[i] = 0;
break;
}
for (i = 0; i < 32; i += 8)
BGE_DEBUG(("bge_phydump: "
"0x%04x %04x %04x %04x %04x %04x %04x %04x",
regs[i+0], regs[i+1], regs[i+2], regs[i+3],
regs[i+4], regs[i+5], regs[i+6], regs[i+7]));
}
#endif
static void
bge_phy_toggle_auxctl_smdsp(bge_t *bgep,
boolean_t enable)
{
uint16_t val;
val = bge_mii_get16(bgep, MII_AUX_CONTROL);
if (enable) {
val |= MII_AUX_CTRL_SMDSP_ENA;
} else {
val &= ~MII_AUX_CTRL_SMDSP_ENA;
}
bge_mii_put16(bgep, MII_AUX_CONTROL, (val | MII_AUX_CTRL_TX_6DB));
}
static boolean_t
bge_phy_probe(bge_t *bgep)
{
uint16_t miicfg;
uint32_t nicsig, niccfg;
int i;
BGE_TRACE(("bge_phy_probe($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR);
if (nicsig == BGE_NIC_DATA_SIG) {
niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR);
switch (niccfg & BGE_NIC_CFG_PHY_TYPE_MASK) {
default:
case BGE_NIC_CFG_PHY_TYPE_COPPER:
return (B_TRUE);
case BGE_NIC_CFG_PHY_TYPE_FIBER:
return (B_FALSE);
}
} else {
for (i = 0; i < 100; i++) {
drv_usecwait(40);
miicfg = bge_mii_get16(bgep, MII_STATUS);
}
BGE_DEBUG(("bge_phy_probe: status 0x%x", miicfg));
switch (miicfg) {
case 0x0000:
case 0xffff:
return (B_FALSE);
default:
return (B_TRUE);
}
}
}
static boolean_t
bge_phy_reset(bge_t *bgep)
{
uint16_t control;
uint_t count;
BGE_TRACE(("bge_phy_reset($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
drv_usecwait(40);
bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ);
(void) bge_reg_get32(bgep, MISC_CONFIG_REG);
drv_usecwait(40);
}
bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_RESET);
for (count = 0; ++count < 1000; ) {
drv_usecwait(5);
control = bge_mii_get16(bgep, MII_CONTROL);
if (BIC(control, MII_CONTROL_RESET))
return (B_TRUE);
}
if (DEVICE_5906_SERIES_CHIPSETS(bgep))
(void) bge_adj_volt_5906(bgep);
BGE_DEBUG(("bge_phy_reset: FAILED, control now 0x%x", control));
return (B_FALSE);
}
static void
bge_phy_powerdown(bge_t *bgep)
{
BGE_TRACE(("bge_phy_powerdown"));
#if BGE_COPPER_IDLEOFF
bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_PWRDN);
#endif
}
static void
bge_phy_macro_wait(bge_t *bgep)
{
uint_t count;
for (count = 100; --count; )
if ((bge_mii_get16(bgep, 0x16) & 0x1000) == 0)
break;
}
#define N_CHANNELS 4
#define N_TAPS 3
static struct {
uint16_t lo;
uint16_t hi;
} tap_data[N_CHANNELS][N_TAPS] = {
{
{ 0x5555, 0x0005 },
{ 0x2aaa, 0x000a },
{ 0x3456, 0x0003 }
},
{
{ 0x2aaa, 0x000a },
{ 0x3333, 0x0003 },
{ 0x789a, 0x0005 }
},
{
{ 0x5a5a, 0x0005 },
{ 0x2a6a, 0x000a },
{ 0x1bcd, 0x0003 }
},
{
{ 0x2a5a, 0x000a },
{ 0x33c3, 0x0003 },
{ 0x2ef1, 0x0005 }
}
};
static boolean_t
bge_phy_locked_up(bge_t *bgep)
{
uint16_t dataLo;
uint16_t dataHi;
uint_t chan;
uint_t tap;
for (chan = 0; chan < N_CHANNELS; ++chan) {
bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200);
bge_mii_put16(bgep, 0x16, 0x0002);
for (tap = 0; tap < N_TAPS; ++tap) {
bge_mii_put16(bgep, 0x15, tap_data[chan][tap].lo);
bge_mii_put16(bgep, 0x15, tap_data[chan][tap].hi);
}
bge_mii_put16(bgep, 0x16, 0x0202);
bge_phy_macro_wait(bgep);
bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200);
bge_mii_put16(bgep, 0x16, 0x0082);
bge_phy_macro_wait(bgep);
bge_mii_put16(bgep, 0x16, 0x0802);
bge_phy_macro_wait(bgep);
for (tap = 0; tap < N_TAPS; ++tap) {
dataLo = bge_mii_get16(bgep, 0x15) & 0x7fff;
dataHi = bge_mii_get16(bgep, 0x15) & 0x003f;
bge_phy_macro_wait(bgep);
if (dataLo != tap_data[chan][tap].lo)
return (B_TRUE);
if (dataHi != tap_data[chan][tap].hi)
return (B_TRUE);
}
}
return (B_FALSE);
}
static boolean_t
bge_phy_reset_and_check(bge_t *bgep)
{
boolean_t reset_success;
boolean_t phy_locked;
uint16_t extctrl;
uint16_t gigctrl;
uint_t retries;
for (retries = 0; retries < 5; ++retries) {
reset_success = bge_phy_reset(bgep);
extctrl = bge_mii_get16(bgep, 0x10);
bge_mii_put16(bgep, 0x10, extctrl | 0x3000);
bge_mii_put16(bgep, 0x0, 0x0140);
gigctrl = bge_mii_get16(bgep, 0x9);
bge_mii_put16(bgep, 0x9, 0x1800);
bge_mii_put16(bgep, 0x18, 0x0c00);
bge_mii_put16(bgep, 0x17, 0x201f);
bge_mii_put16(bgep, 0x15, 0x2aaa);
bge_mii_put16(bgep, 0x17, 0x000a);
bge_mii_put16(bgep, 0x15, 0x0323);
bge_mii_put16(bgep, 0x17, 0x8005);
bge_mii_put16(bgep, 0x15, 0x0800);
phy_locked = bge_phy_locked_up(bgep);
if (reset_success && !phy_locked)
break;
if (!reset_success)
BGE_REPORT((bgep, "PHY didn't reset!"));
if (phy_locked)
BGE_REPORT((bgep, "PHY locked up!"));
}
bge_mii_put16(bgep, 0x17, 0x8005);
bge_mii_put16(bgep, 0x15, 0x0000);
bge_mii_put16(bgep, 0x17, 0x8200);
bge_mii_put16(bgep, 0x16, 0x0000);
bge_mii_put16(bgep, 0x18, 0x0400);
bge_mii_put16(bgep, 0x9, gigctrl);
extctrl = bge_mii_get16(bgep, 0x10);
bge_mii_put16(bgep, 0x10, extctrl & ~0x3000);
if (DEVICE_5906_SERIES_CHIPSETS(bgep))
(void) bge_adj_volt_5906(bgep);
if (!reset_success)
bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
else if (phy_locked)
bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE);
return (reset_success && !phy_locked);
}
static void
bge_phy_tweak_gmii(bge_t *bgep)
{
bge_mii_put16(bgep, 0x1c, 0x8d68);
bge_mii_put16(bgep, 0x1c, 0x8d68);
}
static void
bge_phy_bit_err_fix(bge_t *bgep)
{
bge_mii_put16(bgep, 0x18, 0x0c00);
bge_mii_put16(bgep, 0x17, 0x000a);
bge_mii_put16(bgep, 0x15, 0x310b);
bge_mii_put16(bgep, 0x17, 0x201f);
bge_mii_put16(bgep, 0x15, 0x9506);
bge_mii_put16(bgep, 0x17, 0x401f);
bge_mii_put16(bgep, 0x15, 0x14e2);
bge_mii_put16(bgep, 0x18, 0x0400);
}
static int
bge_restart_copper(bge_t *bgep, boolean_t powerdown)
{
uint16_t phy_status;
boolean_t reset_ok;
uint16_t extctrl, auxctrl;
int i;
BGE_TRACE(("bge_restart_copper($%p, %d)", (void *)bgep, powerdown));
ASSERT(mutex_owned(bgep->genlock));
switch (MHCR_CHIP_ASIC_REV(bgep)) {
default:
case MHCR_CHIP_ASIC_REV_5703:
case MHCR_CHIP_ASIC_REV_5704:
case MHCR_CHIP_ASIC_REV_5705:
case MHCR_CHIP_ASIC_REV_5752:
case MHCR_CHIP_ASIC_REV_5714:
case MHCR_CHIP_ASIC_REV_5715:
reset_ok = bge_phy_reset_and_check(bgep);
break;
case MHCR_CHIP_ASIC_REV_5906:
case MHCR_CHIP_ASIC_REV_5700:
case MHCR_CHIP_ASIC_REV_5701:
case MHCR_CHIP_ASIC_REV_5723:
case MHCR_CHIP_ASIC_REV_5721_5751:
reset_ok = bge_phy_reset(bgep);
if (!reset_ok)
bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
break;
}
if (!reset_ok) {
BGE_REPORT((bgep, "PHY failed to reset correctly"));
return (DDI_FAILURE);
}
switch (bgep->chipid.asic_rev) {
default:
break;
case MHCR_CHIP_REV_5704_A0:
bge_phy_tweak_gmii(bgep);
break;
}
switch (MHCR_CHIP_ASIC_REV(bgep)) {
case MHCR_CHIP_ASIC_REV_5705:
case MHCR_CHIP_ASIC_REV_5721_5751:
bge_phy_bit_err_fix(bgep);
break;
}
if (!(bgep->chipid.flags & CHIP_FLAG_NO_JUMBO) &&
(bgep->chipid.default_mtu > BGE_DEFAULT_MTU)) {
extctrl = bge_mii_get16(bgep, 0x10);
bge_mii_put16(bgep, 0x10, extctrl | 0x1);
bge_mii_put16(bgep, MII_AUX_CONTROL, 0x0007);
auxctrl = bge_mii_get16(bgep, MII_AUX_CONTROL);
auxctrl |= 0x4000;
bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl);
}
for (i = 0; i < 100; i++) {
drv_usecwait(40);
phy_status = bge_mii_get16(bgep, MII_STATUS);
}
BGE_DEBUG(("bge_restart_copper: status 0x%x", phy_status));
if (powerdown)
bge_phy_powerdown(bgep);
return (DDI_SUCCESS);
}
boolean_t
bge_eee_cap(bge_t * bgep)
{
if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) ||
DEVICE_5725_SERIES_CHIPSETS(bgep))) {
BGE_DEBUG(("bge_eee: eee not supported (device 0x%x)",
bgep->chipid.device));
return (B_FALSE);
}
switch (CHIP_ASIC_REV_PROD_ID(bgep)) {
case CHIP_ASIC_REV_5717_B0:
case CHIP_ASIC_REV_5717_C0:
case CHIP_ASIC_REV_5719_A0:
case CHIP_ASIC_REV_5719_A1:
case CHIP_ASIC_REV_5720_A0:
case CHIP_ASIC_REV_5725_A0:
case CHIP_ASIC_REV_5727_B0:
return (B_TRUE);
default:
BGE_DEBUG(("bge_eee: eee not supported (asic rev 0x%08x)",
bgep->chipid.asic_rev));
return (B_FALSE);
}
}
void
bge_eee_init(bge_t * bgep)
{
uint32_t val;
BGE_TRACE(("bge_eee_init($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
if (!bge_eee_cap(bgep)) {
return;
}
val = (EEE_LINK_IDLE_PCIE_NL0 | EEE_LINK_IDLE_UART_IDL);
if (DEVICE_5725_SERIES_CHIPSETS(bgep))
val |= EEE_LINK_IDLE_APE_TX_MT;
bge_reg_put32(bgep, EEE_LINK_IDLE_CONTROL_REG, val);
bge_reg_put32(bgep, EEE_CONTROL_REG, EEE_CONTROL_EXIT_20_1_US);
val = EEE_MODE_ERLY_L1_XIT_DET | EEE_MODE_LPI_IN_TX |
EEE_MODE_LPI_IN_RX | EEE_MODE_EEE_ENABLE;
if (bgep->chipid.device != DEVICE_ID_5717)
val |= EEE_MODE_SND_IDX_DET_EN;
if (!bgep->chipid.eee) {
val = 0;
}
bge_reg_put32(bgep, EEE_MODE_REG, val);
bge_reg_put32(bgep, EEE_DEBOUNCE_T1_CONTROL_REG,
EEE_DEBOUNCE_T1_PCIEXIT_2047US | EEE_DEBOUNCE_T1_LNKIDLE_2047US);
bge_reg_put32(bgep, EEE_DEBOUNCE_T2_CONTROL_REG,
EEE_DEBOUNCE_T2_APE_TX_2047US | EEE_DEBOUNCE_T2_TXIDXEQ_2047US);
}
void
bge_eee_autoneg(bge_t * bgep, boolean_t adv_100fdx, boolean_t adv_1000fdx)
{
uint32_t val;
uint16_t mii_val;
BGE_TRACE(("bge_eee_autoneg($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
if (!bge_eee_cap(bgep)) {
return;
}
val = bge_reg_get32(bgep, EEE_MODE_REG);
val &= ~EEE_MODE_LPI_ENABLE;
bge_reg_put32(bgep, EEE_MODE_REG, val);
bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE);
mii_val = 0;
if (bgep->chipid.eee) {
if (adv_100fdx) {
mii_val |= EEE_CL45_D7_RESULT_STAT_LP_100TX;
}
if (adv_1000fdx) {
mii_val |= EEE_CL45_D7_RESULT_STAT_LP_1000T;
}
}
bge_mii_put16(bgep, MII_MMD_CTRL, MDIO_MMD_AN);
bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, MDIO_AN_EEE_ADV);
bge_mii_put16(bgep, MII_MMD_CTRL,
MII_MMD_CTRL_DATA_NOINC | MDIO_MMD_AN);
bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA, mii_val);
switch (bgep->chipid.device) {
case DEVICE_ID_5717:
case DEVICE_ID_5718:
case DEVICE_ID_5719:
if (mii_val) {
mii_val = (MII_DSP_TAP26_ALNOKO |
MII_DSP_TAP26_RMRXSTO |
MII_DSP_TAP26_OPCSINPT);
}
bge_phydsp_write(bgep, MII_DSP_TAP26, mii_val);
case DEVICE_ID_5720:
case DEVICE_ID_5725:
case DEVICE_ID_5727:
mii_val = bge_phydsp_read(bgep, MII_DSP_CH34TP2);
bge_phydsp_write(bgep, MII_DSP_CH34TP2,
(mii_val | MII_DSP_CH34TP2_HIBW01));
}
bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE);
}
void
bge_eee_adjust(bge_t * bgep)
{
uint32_t val;
uint16_t mii_val;
BGE_TRACE(("bge_eee_adjust($%p, %d)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
if (!bge_eee_cap(bgep)) {
return;
}
bgep->eee_lpi_wait = 0;
if (bgep->param_link_up) {
BGE_DEBUG(("bge_eee_adjust: link status up"));
if (bgep->param_link_speed == 1000) {
BGE_DEBUG(("bge_eee_adjust: eee timing for 1000Mb"));
bge_reg_put32(bgep, EEE_CONTROL_REG,
EEE_CONTROL_EXIT_16_5_US);
} else if (bgep->param_link_speed == 100) {
BGE_DEBUG(("bge_eee_adjust: eee timing for 100Mb"));
bge_reg_put32(bgep, EEE_CONTROL_REG,
EEE_CONTROL_EXIT_36_US);
}
bge_mii_put16(bgep, MII_MMD_CTRL, MDIO_MMD_AN);
bge_mii_put16(bgep, MII_MMD_ADDRESS_DATA,
EEE_CL45_D7_RESULT_STAT);
bge_mii_put16(bgep, MII_MMD_CTRL,
MII_MMD_CTRL_DATA_NOINC | MDIO_MMD_AN);
mii_val = bge_mii_get16(bgep, MII_MMD_ADDRESS_DATA);
if ((mii_val == EEE_CL45_D7_RESULT_STAT_LP_1000T) ||
(mii_val == EEE_CL45_D7_RESULT_STAT_LP_100TX)) {
BGE_DEBUG(("bge_eee_adjust: eee negotiaton success, lpi scheduled"));
bgep->eee_lpi_wait = 2;
} else {
BGE_DEBUG(("bge_eee_adjust: eee negotiation failed"));
}
} else {
BGE_DEBUG(("bge_eee_adjust: link status down"));
}
if (!bgep->eee_lpi_wait) {
if (bgep->param_link_up) {
bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE);
bge_phydsp_write(bgep, MII_DSP_TAP26, 0);
bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE);
}
val = bge_reg_get32(bgep, EEE_MODE_REG);
val &= ~EEE_MODE_LPI_ENABLE;
bge_reg_put32(bgep, EEE_MODE_REG, val);
}
}
void
bge_eee_enable(bge_t * bgep)
{
uint32_t val;
if (bgep->param_link_speed == 1000) {
bge_phy_toggle_auxctl_smdsp(bgep, B_TRUE);
bge_phydsp_write(bgep, MII_DSP_TAP26,
MII_DSP_TAP26_ALNOKO | MII_DSP_TAP26_RMRXSTO);
bge_phy_toggle_auxctl_smdsp(bgep, B_FALSE);
}
val = bge_reg_get32(bgep, EEE_MODE_REG);
val |= EEE_MODE_LPI_ENABLE;
bge_reg_put32(bgep, EEE_MODE_REG, val);
}
static int
bge_update_copper(bge_t *bgep)
{
boolean_t adv_autoneg;
boolean_t adv_pause;
boolean_t adv_asym_pause;
boolean_t adv_1000fdx;
boolean_t adv_1000hdx;
boolean_t adv_100fdx;
boolean_t adv_100hdx;
boolean_t adv_10fdx;
boolean_t adv_10hdx;
uint16_t control;
uint16_t gigctrl;
uint16_t auxctrl;
uint16_t anar;
BGE_TRACE(("bge_update_copper($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
BGE_DEBUG(("bge_update_copper: autoneg %d "
"pause %d asym_pause %d "
"1000fdx %d 1000hdx %d "
"100fdx %d 100hdx %d "
"10fdx %d 10hdx %d ",
bgep->param_adv_autoneg,
bgep->param_adv_pause, bgep->param_adv_asym_pause,
bgep->param_adv_1000fdx, bgep->param_adv_1000hdx,
bgep->param_adv_100fdx, bgep->param_adv_100hdx,
bgep->param_adv_10fdx, bgep->param_adv_10hdx));
control = gigctrl = auxctrl = anar = 0;
switch (bgep->param_loop_mode) {
case BGE_LOOP_NONE:
default:
adv_autoneg = bgep->param_adv_autoneg;
adv_pause = bgep->param_adv_pause;
adv_asym_pause = bgep->param_adv_asym_pause;
adv_1000fdx = bgep->param_adv_1000fdx;
adv_1000hdx = bgep->param_adv_1000hdx;
adv_100fdx = bgep->param_adv_100fdx;
adv_100hdx = bgep->param_adv_100hdx;
adv_10fdx = bgep->param_adv_10fdx;
adv_10hdx = bgep->param_adv_10hdx;
break;
case BGE_LOOP_EXTERNAL_1000:
case BGE_LOOP_EXTERNAL_100:
case BGE_LOOP_EXTERNAL_10:
case BGE_LOOP_INTERNAL_PHY:
case BGE_LOOP_INTERNAL_MAC:
adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
adv_1000hdx = adv_100hdx = adv_10hdx = B_FALSE;
bgep->param_link_duplex = LINK_DUPLEX_FULL;
switch (bgep->param_loop_mode) {
case BGE_LOOP_EXTERNAL_1000:
bgep->param_link_speed = 1000;
adv_1000fdx = B_TRUE;
auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK;
gigctrl |= MII_MSCONTROL_MANUAL;
gigctrl |= MII_MSCONTROL_MASTER;
break;
case BGE_LOOP_EXTERNAL_100:
bgep->param_link_speed = 100;
adv_100fdx = B_TRUE;
auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK;
break;
case BGE_LOOP_EXTERNAL_10:
bgep->param_link_speed = 10;
adv_10fdx = B_TRUE;
auxctrl = MII_AUX_CTRL_NORM_EXT_LOOPBACK;
break;
case BGE_LOOP_INTERNAL_PHY:
bgep->param_link_speed = 1000;
adv_1000fdx = B_TRUE;
control = MII_CONTROL_LOOPBACK;
break;
case BGE_LOOP_INTERNAL_MAC:
bgep->param_link_speed = 1000;
adv_1000fdx = B_TRUE;
break;
}
}
BGE_DEBUG(("bge_update_copper: autoneg %d "
"pause %d asym_pause %d "
"1000fdx %d 1000hdx %d "
"100fdx %d 100hdx %d "
"10fdx %d 10hdx %d ",
adv_autoneg,
adv_pause, adv_asym_pause,
adv_1000fdx, adv_1000hdx,
adv_100fdx, adv_100hdx,
adv_10fdx, adv_10hdx));
if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
!adv_1000hdx && !adv_100hdx && !adv_10hdx)
adv_1000fdx = B_TRUE;
if (adv_autoneg)
control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;
if (adv_1000fdx)
control |= MII_CONTROL_1GB|MII_CONTROL_FDUPLEX;
else if (adv_1000hdx)
control |= MII_CONTROL_1GB;
else if (adv_100fdx)
control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
else if (adv_100hdx)
control |= MII_CONTROL_100MB;
else if (adv_10fdx)
control |= MII_CONTROL_FDUPLEX;
else if (adv_10hdx)
control |= 0;
else
{ _NOTE(EMPTY); }
if (adv_1000fdx)
gigctrl |= MII_MSCONTROL_1000T_FD;
if (adv_1000hdx)
gigctrl |= MII_MSCONTROL_1000T;
if (adv_100fdx)
anar |= MII_ABILITY_100BASE_TX_FD;
if (adv_100hdx)
anar |= MII_ABILITY_100BASE_TX;
if (adv_10fdx)
anar |= MII_ABILITY_10BASE_T_FD;
if (adv_10hdx)
anar |= MII_ABILITY_10BASE_T;
if (adv_pause)
anar |= MII_ABILITY_PAUSE;
if (adv_asym_pause)
anar |= MII_ABILITY_ASMPAUSE;
anar |= MII_AN_SELECTOR_8023;
auxctrl |= MII_AUX_CTRL_NORM_TX_MODE;
auxctrl |= MII_AUX_CTRL_NORMAL;
if ((*bgep->physops->phys_restart)(bgep, B_FALSE) == DDI_FAILURE)
return (DDI_FAILURE);
bge_mii_put16(bgep, MII_AN_ADVERT, anar);
if (auxctrl & MII_AUX_CTRL_NORM_EXT_LOOPBACK)
bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl);
bge_mii_put16(bgep, MII_MSCONTROL, gigctrl);
bge_mii_put16(bgep, MII_CONTROL, control);
BGE_DEBUG(("bge_update_copper: anar <- 0x%x", anar));
BGE_DEBUG(("bge_update_copper: auxctrl <- 0x%x", auxctrl));
BGE_DEBUG(("bge_update_copper: gigctrl <- 0x%x", gigctrl));
BGE_DEBUG(("bge_update_copper: control <- 0x%x", control));
#if BGE_COPPER_WIRESPEED
switch (bgep->chipid.device) {
case DEVICE_ID_5700:
case DEVICE_ID_5700x:
case DEVICE_ID_5705C:
case DEVICE_ID_5782:
break;
default:
if (bgep->param_loop_mode == BGE_LOOP_NONE)
bge_mii_put16(bgep, MII_AUX_CONTROL,
MII_AUX_CTRL_MISC_WRITE_ENABLE |
MII_AUX_CTRL_MISC_WIRE_SPEED |
MII_AUX_CTRL_MISC);
break;
}
#endif
bge_eee_autoneg(bgep, adv_100fdx, adv_1000fdx);
return (DDI_SUCCESS);
}
static boolean_t
bge_check_copper(bge_t *bgep, boolean_t recheck)
{
uint32_t emac_status;
uint16_t mii_status;
uint16_t aux;
uint_t mode;
boolean_t linkup;
int i;
for (i = 0; i < 100; i++) {
drv_usecwait(40);
mii_status = bge_mii_get16(bgep, MII_STATUS);
}
emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG);
bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, emac_status);
BGE_DEBUG(("bge_check_copper: link %d/%s, MII status 0x%x "
"(was 0x%x), Ethernet MAC status 0x%x",
bgep->link_state, UPORDOWN(bgep->param_link_up), mii_status,
bgep->phy_gen_status, emac_status));
if (mii_status == bgep->phy_gen_status && !recheck) {
BGE_DEBUG(("bge_check_copper: no link change"));
return (B_FALSE);
}
do {
for (i = 0; i < 2000; i++) {
drv_usecwait(10);
aux = bge_mii_get16(bgep, MII_AUX_STATUS);
}
BGE_CDB(bge_phydump, (bgep, mii_status, aux));
mode = aux & MII_AUX_STATUS_MODE_MASK;
mode >>= MII_AUX_STATUS_MODE_SHIFT;
if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
linkup = BIS(aux, MII_AUX_STATUS_LINKUP);
linkup &= BIS(mii_status, MII_STATUS_LINKUP);
} else {
linkup = bge_copper_link_speed[mode] > 0;
linkup &= bge_copper_link_duplex[mode] !=
LINK_DUPLEX_UNKNOWN;
linkup &= BIS(aux, MII_AUX_STATUS_LINKUP);
linkup &= BIS(mii_status, MII_STATUS_LINKUP);
}
BGE_DEBUG(("bge_check_copper: MII status 0x%x aux 0x%x "
"=> mode %d (%s)",
mii_status, aux,
mode, UPORDOWN(linkup)));
bgep->phy_aux_status = aux;
bgep->phy_gen_status = mii_status;
for (i = 0; i < 100; i++)
{
drv_usecwait(40);
mii_status = bge_mii_get16(bgep, MII_STATUS);
}
} while (mii_status != bgep->phy_gen_status);
bgep->param_lp_autoneg = B_FALSE;
bgep->param_lp_1000fdx = B_FALSE;
bgep->param_lp_1000hdx = B_FALSE;
bgep->param_lp_100fdx = B_FALSE;
bgep->param_lp_100hdx = B_FALSE;
bgep->param_lp_10fdx = B_FALSE;
bgep->param_lp_10hdx = B_FALSE;
bgep->param_lp_pause = B_FALSE;
bgep->param_lp_asym_pause = B_FALSE;
bgep->param_link_autoneg = B_FALSE;
bgep->param_link_tx_pause = B_FALSE;
if (bgep->param_adv_autoneg)
bgep->param_link_rx_pause = B_FALSE;
else
bgep->param_link_rx_pause = bgep->param_adv_pause;
if (BIS(aux, MII_AUX_STATUS_LP_ANEG_ABLE)) {
bgep->param_lp_autoneg = B_TRUE;
bgep->param_link_autoneg = B_TRUE;
bgep->param_link_tx_pause = BIS(aux, MII_AUX_STATUS_TX_PAUSE);
bgep->param_link_rx_pause = BIS(aux, MII_AUX_STATUS_RX_PAUSE);
aux = bge_mii_get16(bgep, MII_MSSTATUS);
bgep->param_lp_1000fdx = BIS(aux, MII_MSSTATUS_LP1000T_FD);
bgep->param_lp_1000hdx = BIS(aux, MII_MSSTATUS_LP1000T);
aux = bge_mii_get16(bgep, MII_AN_LPABLE);
bgep->param_lp_100fdx = BIS(aux, MII_ABILITY_100BASE_TX_FD);
bgep->param_lp_100hdx = BIS(aux, MII_ABILITY_100BASE_TX);
bgep->param_lp_10fdx = BIS(aux, MII_ABILITY_10BASE_T_FD);
bgep->param_lp_10hdx = BIS(aux, MII_ABILITY_10BASE_T);
bgep->param_lp_pause = BIS(aux, MII_ABILITY_PAUSE);
bgep->param_lp_asym_pause = BIS(aux, MII_ABILITY_ASMPAUSE);
}
BGE_DEBUG(("bge_check_copper: link was %s speed %d duplex %d",
UPORDOWN(bgep->param_link_up),
bgep->param_link_speed,
bgep->param_link_duplex));
if (!linkup)
mode = MII_AUX_STATUS_MODE_NONE;
bgep->param_link_up = linkup;
bgep->link_state = LINK_STATE_UNKNOWN;
if (DEVICE_5906_SERIES_CHIPSETS(bgep)) {
if (bgep->phy_aux_status & MII_AUX_STATUS_NEG_ENABLED_5906) {
bgep->param_link_speed =
bge_copper_link_speed_5906[mode];
bgep->param_link_duplex =
bge_copper_link_duplex_5906[mode];
} else {
bgep->param_link_speed = (bgep->phy_aux_status &
MII_AUX_STATUS_SPEED_IND_5906) ? 100 : 10;
bgep->param_link_duplex = (bgep->phy_aux_status &
MII_AUX_STATUS_DUPLEX_IND_5906) ? LINK_DUPLEX_FULL :
LINK_DUPLEX_HALF;
}
} else {
bgep->param_link_speed = bge_copper_link_speed[mode];
bgep->param_link_duplex = bge_copper_link_duplex[mode];
}
bge_eee_adjust(bgep);
bge_log(bgep, "bge_check_copper: link now %s speed %d duplex %d",
UPORDOWN(bgep->param_link_up),
bgep->param_link_speed,
bgep->param_link_duplex);
return (B_TRUE);
}
static const phys_ops_t copper_ops = {
bge_restart_copper,
bge_update_copper,
bge_check_copper
};
#undef BGE_DBG
#define BGE_DBG BGE_DBG_SERDES
static int
bge_restart_serdes(bge_t *bgep, boolean_t powerdown)
{
uint32_t macmode;
BGE_TRACE(("bge_restart_serdes($%p, %d)", (void *)bgep, powerdown));
ASSERT(mutex_owned(bgep->genlock));
macmode = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG);
macmode &= ~ETHERNET_MODE_LINK_POLARITY;
macmode &= ~ETHERNET_MODE_PORTMODE_MASK;
if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
DEVICE_5725_SERIES_CHIPSETS(bgep) ||
DEVICE_5714_SERIES_CHIPSETS(bgep) ||
DEVICE_57765_SERIES_CHIPSETS(bgep)) {
macmode |= ETHERNET_MODE_PORTMODE_GMII;
} else {
macmode |= ETHERNET_MODE_PORTMODE_TBI;
}
bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode);
bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TBI_LOOPBACK);
bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_COMMA_DETECT);
bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE);
if (powerdown)
return (DDI_SUCCESS);
drv_usecwait(10000);
bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE);
bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, 0);
bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS);
drv_usecwait(10);
bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS);
bgep->serdes_lpadv = AUTONEG_CODE_FAULT_ANEG_ERR;
bgep->serdes_status = ~0U;
return (DDI_SUCCESS);
}
static int
bge_update_serdes(bge_t *bgep)
{
boolean_t adv_autoneg;
boolean_t adv_pause;
boolean_t adv_asym_pause;
boolean_t adv_1000fdx;
boolean_t adv_1000hdx;
uint32_t serdes;
uint32_t advert;
BGE_TRACE(("bge_update_serdes($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
BGE_DEBUG(("bge_update_serdes: autoneg %d "
"pause %d asym_pause %d "
"1000fdx %d 1000hdx %d "
"100fdx %d 100hdx %d "
"10fdx %d 10hdx %d ",
bgep->param_adv_autoneg,
bgep->param_adv_pause, bgep->param_adv_asym_pause,
bgep->param_adv_1000fdx, bgep->param_adv_1000hdx,
bgep->param_adv_100fdx, bgep->param_adv_100hdx,
bgep->param_adv_10fdx, bgep->param_adv_10hdx));
serdes = advert = 0;
switch (bgep->param_loop_mode) {
case BGE_LOOP_NONE:
default:
adv_autoneg = bgep->param_adv_autoneg;
adv_pause = bgep->param_adv_pause;
adv_asym_pause = bgep->param_adv_asym_pause;
adv_1000fdx = bgep->param_adv_1000fdx;
adv_1000hdx = bgep->param_adv_1000hdx;
break;
case BGE_LOOP_INTERNAL_PHY:
serdes |= SERDES_CONTROL_TBI_LOOPBACK;
case BGE_LOOP_INTERNAL_MAC:
case BGE_LOOP_EXTERNAL_1000:
case BGE_LOOP_EXTERNAL_100:
case BGE_LOOP_EXTERNAL_10:
adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
adv_1000fdx = B_TRUE;
adv_1000hdx = B_FALSE;
break;
}
BGE_DEBUG(("bge_update_serdes: autoneg %d "
"pause %d asym_pause %d "
"1000fdx %d 1000hdx %d ",
adv_autoneg,
adv_pause, adv_asym_pause,
adv_1000fdx, adv_1000hdx));
if (!adv_1000fdx && !adv_1000hdx)
adv_1000fdx = B_TRUE;
if (!adv_autoneg)
advert |= AUTONEG_CODE_FAULT_ANEG_ERR;
if (adv_1000fdx) {
advert |= AUTONEG_CODE_FULL_DUPLEX;
bgep->param_adv_1000fdx = adv_1000fdx;
bgep->param_link_duplex = LINK_DUPLEX_FULL;
bgep->param_link_speed = 1000;
}
if (adv_1000hdx) {
advert |= AUTONEG_CODE_HALF_DUPLEX;
bgep->param_adv_1000hdx = adv_1000hdx;
bgep->param_link_duplex = LINK_DUPLEX_HALF;
bgep->param_link_speed = 1000;
}
if (adv_pause)
advert |= AUTONEG_CODE_PAUSE;
if (adv_asym_pause)
advert |= AUTONEG_CODE_ASYM_PAUSE;
bgep->serdes_advert = advert;
(void) bge_restart_serdes(bgep, B_FALSE);
bge_reg_set32(bgep, SERDES_CONTROL_REG, serdes);
BGE_DEBUG(("bge_update_serdes: serdes |= 0x%x, advert 0x%x",
serdes, advert));
return (DDI_SUCCESS);
}
static void
bge_autoneg_serdes(bge_t *bgep)
{
boolean_t ack;
bgep->serdes_lpadv = bge_reg_get32(bgep, RX_1000BASEX_AUTONEG_REG);
ack = BIS(bgep->serdes_lpadv, AUTONEG_CODE_ACKNOWLEDGE);
if (!ack) {
bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG,
bgep->serdes_advert | AUTONEG_CODE_ACKNOWLEDGE);
bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG,
ETHERNET_MODE_SEND_CFGS);
} else {
bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG,
ETHERNET_MODE_SEND_CFGS);
}
BGE_DEBUG(("bge_autoneg_serdes: Rx 0x%x %s Tx 0x%x",
bgep->serdes_lpadv,
ack ? "stop" : "send",
bgep->serdes_advert));
}
static boolean_t
bge_check_serdes(bge_t *bgep, boolean_t recheck)
{
uint32_t emac_status;
uint32_t tx_status;
uint32_t lpadv;
boolean_t linkup;
boolean_t linkup_old = bgep->param_link_up;
for (;;) {
if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
DEVICE_5725_SERIES_CHIPSETS(bgep) ||
DEVICE_5714_SERIES_CHIPSETS(bgep) ||
DEVICE_57765_SERIES_CHIPSETS(bgep)) {
tx_status = bge_reg_get32(bgep,
TRANSMIT_MAC_STATUS_REG);
linkup = BIS(tx_status, TRANSMIT_STATUS_LINK_UP);
emac_status = bge_reg_get32(bgep,
ETHERNET_MAC_STATUS_REG);
bgep->serdes_status = emac_status;
if ((emac_status & ETHERNET_STATUS_MI_COMPLETE) &&
(DEVICE_5717_SERIES_CHIPSETS(bgep) ||
DEVICE_5725_SERIES_CHIPSETS(bgep))) {
emac_status |= ETHERNET_STATUS_SYNC_CHANGED |
ETHERNET_STATUS_CFG_CHANGED;
}
bge_reg_put32(bgep,
ETHERNET_MAC_STATUS_REG, emac_status);
if ((linkup && linkup_old) ||
(!linkup && !linkup_old)) {
break;
}
if (linkup)
linkup_old = B_TRUE;
else
linkup_old = B_FALSE;
recheck = B_TRUE;
} else {
emac_status = bge_reg_get32(bgep,
ETHERNET_MAC_STATUS_REG);
bge_reg_put32(bgep,
ETHERNET_MAC_STATUS_REG, emac_status);
BGE_DEBUG(("bge_check_serdes: link %d/%s, "
"MAC status 0x%x (was 0x%x)",
bgep->link_state, UPORDOWN(bgep->param_link_up),
emac_status, bgep->serdes_status));
bgep->serdes_status = emac_status;
linkup = BIS(emac_status,
ETHERNET_STATUS_SIGNAL_DETECT);
linkup &= BIS(emac_status, ETHERNET_STATUS_PCS_SYNCHED);
if (BIS(emac_status, ETHERNET_STATUS_PCS_ERROR))
emac_status |= ETHERNET_STATUS_LINK_CHANGED;
else if (BIC(emac_status, ETHERNET_STATUS_CFG_CHANGED))
if (bgep->param_link_up && linkup)
emac_status &=
~ETHERNET_STATUS_LINK_CHANGED;
BGE_DEBUG(("bge_check_serdes: status 0x%x => 0x%x %s",
bgep->serdes_status, emac_status,
UPORDOWN(linkup)));
if (linkup && BIS(emac_status,
ETHERNET_STATUS_RECEIVING_CFG))
bge_autoneg_serdes(bgep);
if (BIC(emac_status, ETHERNET_STATUS_LINK_CHANGED))
break;
recheck = B_TRUE;
}
}
if (!recheck)
return (B_FALSE);
if (linkup && BIS(emac_status, ETHERNET_STATUS_RECEIVING_CFG))
return (B_FALSE);
bgep->param_lp_autoneg = B_FALSE;
bgep->param_lp_1000fdx = B_FALSE;
bgep->param_lp_1000hdx = B_FALSE;
bgep->param_lp_100fdx = B_FALSE;
bgep->param_lp_100hdx = B_FALSE;
bgep->param_lp_10fdx = B_FALSE;
bgep->param_lp_10hdx = B_FALSE;
bgep->param_lp_pause = B_FALSE;
bgep->param_lp_asym_pause = B_FALSE;
bgep->param_link_autoneg = B_FALSE;
bgep->param_link_tx_pause = B_FALSE;
if (bgep->param_adv_autoneg)
bgep->param_link_rx_pause = B_FALSE;
else
bgep->param_link_rx_pause = bgep->param_adv_pause;
lpadv = bgep->serdes_lpadv;
if (lpadv != 0 && BIC(lpadv, AUTONEG_CODE_FAULT_MASK)) {
bgep->param_lp_autoneg = B_TRUE;
bgep->param_lp_1000fdx = BIS(lpadv, AUTONEG_CODE_FULL_DUPLEX);
bgep->param_lp_1000hdx = BIS(lpadv, AUTONEG_CODE_HALF_DUPLEX);
bgep->param_lp_pause = BIS(lpadv, AUTONEG_CODE_PAUSE);
bgep->param_lp_asym_pause = BIS(lpadv, AUTONEG_CODE_ASYM_PAUSE);
bgep->param_link_autoneg = B_TRUE;
if (bgep->param_adv_pause &&
bgep->param_lp_pause) {
bgep->param_link_tx_pause = B_TRUE;
bgep->param_link_rx_pause = B_TRUE;
}
if (bgep->param_adv_asym_pause &&
bgep->param_lp_asym_pause) {
if (bgep->param_adv_pause)
bgep->param_link_rx_pause = B_TRUE;
if (bgep->param_lp_pause)
bgep->param_link_tx_pause = B_TRUE;
}
}
BGE_DEBUG(("bge_check_serdes: link was %s speed %d duplex %d",
UPORDOWN(bgep->param_link_up),
bgep->param_link_speed,
bgep->param_link_duplex));
if (linkup) {
bgep->param_link_up = B_TRUE;
bgep->param_link_speed = 1000;
if (bgep->param_adv_1000fdx)
bgep->param_link_duplex = LINK_DUPLEX_FULL;
else
bgep->param_link_duplex = LINK_DUPLEX_HALF;
if (bgep->param_lp_autoneg && !bgep->param_lp_1000fdx)
bgep->param_link_duplex = LINK_DUPLEX_HALF;
} else {
bgep->param_link_up = B_FALSE;
bgep->param_link_speed = 0;
bgep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
}
bgep->link_state = LINK_STATE_UNKNOWN;
bge_log(bgep, "bge_check_serdes: link now %s speed %d duplex %d",
UPORDOWN(bgep->param_link_up),
bgep->param_link_speed,
bgep->param_link_duplex);
return (B_TRUE);
}
static const phys_ops_t serdes_ops = {
bge_restart_serdes,
bge_update_serdes,
bge_check_serdes
};
#undef BGE_DBG
#define BGE_DBG BGE_DBG_PHYS
int
bge_phys_init(bge_t *bgep)
{
uint32_t regval;
BGE_TRACE(("bge_phys_init($%p)", (void *)bgep));
mutex_enter(bgep->genlock);
bgep->phy_mii_addr = 1;
if (DEVICE_5717_SERIES_CHIPSETS(bgep)) {
bgep->phy_mii_addr = (bgep->pci_func + 1);
regval = bge_reg_get32(bgep, SGMII_STATUS_REG);
if (regval & MEDIA_SELECTION_MODE)
bgep->phy_mii_addr += 7;
}
if (bge_phy_probe(bgep)) {
bgep->chipid.flags &= ~CHIP_FLAG_SERDES;
bgep->physops = &copper_ops;
} else {
bgep->chipid.flags |= CHIP_FLAG_SERDES;
bgep->physops = &serdes_ops;
}
if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS) {
mutex_exit(bgep->genlock);
return (EIO);
}
if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
mutex_exit(bgep->genlock);
return (EIO);
}
mutex_exit(bgep->genlock);
return (0);
}
void
bge_phys_reset(bge_t *bgep)
{
BGE_TRACE(("bge_phys_reset($%p)", (void *)bgep));
mutex_enter(bgep->genlock);
if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS)
ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED);
if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK)
ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED);
mutex_exit(bgep->genlock);
}
int
bge_phys_idle(bge_t *bgep)
{
BGE_TRACE(("bge_phys_idle($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
return ((*bgep->physops->phys_restart)(bgep, B_TRUE));
}
int
bge_phys_update(bge_t *bgep)
{
BGE_TRACE(("bge_phys_update($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
return ((*bgep->physops->phys_update)(bgep));
}
#undef BGE_DBG
#define BGE_DBG BGE_DBG_LINK
boolean_t
bge_phys_check(bge_t *bgep)
{
BGE_TRACE(("bge_phys_check($%p)", (void *)bgep));
ASSERT(mutex_owned(bgep->genlock));
return ((*bgep->physops->phys_check)(bgep,
(bgep->link_state == LINK_STATE_UNKNOWN)));
}
mac_ether_media_t
bge_phys_media(bge_t *bgep)
{
switch (bgep->link_state) {
case LINK_STATE_UP:
break;
case LINK_STATE_DOWN:
return (ETHER_MEDIA_NONE);
case LINK_STATE_UNKNOWN:
default:
return (ETHER_MEDIA_UNKNOWN);
}
if ((bgep->chipid.flags & CHIP_FLAG_SERDES) != 0) {
switch (bgep->param_link_speed) {
case 1000:
return (ETHER_MEDIA_1000BASE_X);
case 100:
return (ETHER_MEDIA_100BASE_FX);
default:
break;
}
} else {
switch (bgep->param_link_speed) {
case 1000:
return (ETHER_MEDIA_1000BASE_T);
case 100:
return (ETHER_MEDIA_100BASE_TX);
case 10:
return (ETHER_MEDIA_10BASE_T);
default:
break;
}
}
return (ETHER_MEDIA_UNKNOWN);
}