Commit db5ac083 authored by David S. Miller's avatar David S. Miller

Tigon3: Make fibre PHY support work.

parent edb697e6
......@@ -52,8 +52,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "0.98"
#define DRV_MODULE_RELDATE "Mar 28, 2002"
#define DRV_MODULE_VERSION "0.99"
#define DRV_MODULE_RELDATE "Jun 11, 2002"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
......@@ -971,7 +971,9 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
tw32(MAC_MODE, tp->mac_mode);
if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
if (tp->tg3_flags &
(TG3_FLAG_USE_LINKCHG_REG |
TG3_FLAG_POLL_SERDES)) {
/* Polled via timer. */
tw32(MAC_EVENT, 0);
} else {
......@@ -1065,6 +1067,7 @@ struct tg3_fiber_aneginfo {
#define ANEG_TIMER_ENAB 2
#define ANEG_FAILED -1
#define ANEG_STATE_SETTLE_TIME 10000
static int tg3_fiber_aneg_smachine(struct tg3 *tp,
struct tg3_fiber_aneginfo *ap)
......@@ -1093,8 +1096,10 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
ap->ability_match = 0;
ap->ability_match_count = 0;
} else {
if (++ap->ability_match_count > 1)
if (++ap->ability_match_count > 1) {
ap->ability_match = 1;
ap->ability_match_cfg = rx_cfg_reg;
}
}
if (rx_cfg_reg & ANEG_CFG_ACK)
ap->ack_match = 1;
......@@ -1151,10 +1156,11 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
/* fallthru */
case ANEG_STATE_RESTART:
delta = ap->cur_time - ap->link_time;
if (delta > 100000)
if (delta > ANEG_STATE_SETTLE_TIME) {
ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
else
} else {
ret = ANEG_TIMER_ENAB;
}
break;
case ANEG_STATE_DISABLE_LINK_OK:
......@@ -1167,12 +1173,14 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32(MAC_MODE, tp->mac_mode);
ap->state = ANEG_STATE_ABILITY_DETECT;
break;
case ANEG_STATE_ABILITY_DETECT:
if (ap->ability_match != 0 && ap->rxconfig != 0)
if (ap->ability_match != 0 && ap->rxconfig != 0) {
ap->state = ANEG_STATE_ACK_DETECT_INIT;
}
break;
case ANEG_STATE_ACK_DETECT_INIT:
......@@ -1180,16 +1188,18 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32(MAC_MODE, tp->mac_mode);
ap->state = ANEG_STATE_ACK_DETECT;
/* fallthru */
case ANEG_STATE_ACK_DETECT:
if (ap->ack_match != 0) {
if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
(ap->ability_match_cfg & ~ANEG_CFG_ACK))
(ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
else
} else {
ap->state = ANEG_STATE_AN_ENABLE;
}
} else if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
......@@ -1245,23 +1255,25 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
break;
}
delta = ap->cur_time - ap->link_time;
if (delta > 100000) {
if (delta > ANEG_STATE_SETTLE_TIME) {
if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
ap->state = ANEG_STATE_IDLE_DETECT_INIT;
} else {
if ((ap->txconfig & 0x0080) == 0 &&
!(ap->flags & MR_NP_RX))
if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
!(ap->flags & MR_NP_RX)) {
ap->state = ANEG_STATE_IDLE_DETECT_INIT;
else
} else {
ret = ANEG_FAILED;
}
}
}
break;
case ANEG_STATE_IDLE_DETECT_INIT:
ap->link_time = ap->cur_time;
tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
tw32(MAC_MODE, tp->mac_mode);
ap->state = ANEG_STATE_IDLE_DETECT;
ret = ANEG_TIMER_ENAB;
break;
......@@ -1273,7 +1285,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
break;
}
delta = ap->cur_time - ap->link_time;
if (delta > 100000) {
if (delta > ANEG_STATE_SETTLE_TIME) {
/* XXX another gem from the Broadcom driver :( */
ap->state = ANEG_STATE_LINK_OK;
}
......@@ -1302,9 +1314,18 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
static int tg3_setup_fiber_phy(struct tg3 *tp)
{
u32 orig_pause_cfg;
u16 orig_active_speed;
u8 orig_active_duplex;
int current_link_up;
int i;
orig_pause_cfg =
(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
TG3_FLAG_TX_PAUSE));
orig_active_speed = tp->link_config.active_speed;
orig_active_duplex = tp->link_config.active_duplex;
tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
tw32(MAC_MODE, tp->mac_mode);
......@@ -1353,22 +1374,23 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tg3_writephy(tp, 0x10, 0x8011);
}
/* Enable link change interrupt. */
/* Enable link change interrupt unless serdes polling. */
if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES))
tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
else
tw32(MAC_EVENT, 0);
current_link_up = 0;
if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
struct tg3_fiber_aneginfo aninfo;
int status = ANEG_FAILED;
unsigned int tick;
u32 tmp;
memset(&aninfo, 0, sizeof(aninfo));
aninfo.flags |= (MR_AN_ENABLE);
for (i = 0; i < 6; i++) {
unsigned int tick;
u32 tmp;
tw32(MAC_TX_AUTO_NEG, 0);
tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
......@@ -1380,7 +1402,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
aninfo.state = ANEG_STATE_UNKNOWN;
aninfo.cur_time = 0;
tick = 0;
while (++tick < 95000) {
while (++tick < 195000) {
status = tg3_fiber_aneg_smachine(tp, &aninfo);
if (status == ANEG_DONE ||
status == ANEG_FAILED)
......@@ -1388,18 +1410,14 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
udelay(1);
}
if (status == ANEG_DONE ||
status == ANEG_FAILED)
break;
}
tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
tw32(MAC_MODE, tp->mac_mode);
if (status == ANEG_DONE &&
(aninfo.flags & MR_AN_COMPLETE) &&
(aninfo.flags & MR_LINK_OK) &&
(aninfo.flags & MR_LP_ADV_FULL_DUPLEX)) {
(aninfo.flags &
(MR_AN_COMPLETE | MR_LINK_OK |
MR_LP_ADV_FULL_DUPLEX))) {
u32 local_adv, remote_adv;
local_adv = ADVERTISE_PAUSE_CAP;
......@@ -1425,6 +1443,10 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
MAC_STATUS_CFG_CHANGED)) == 0)
break;
}
if (current_link_up == 0 &&
(tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
current_link_up = 1;
}
} else {
/* Forcing 1000FD link up. */
current_link_up = 1;
......@@ -1467,6 +1489,14 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
else
netif_carrier_off(tp->dev);
tg3_link_report(tp);
} else {
u32 now_pause_cfg =
tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
TG3_FLAG_TX_PAUSE);
if (orig_pause_cfg != now_pause_cfg ||
orig_active_speed != tp->link_config.active_speed ||
orig_active_duplex != tp->link_config.active_duplex)
tg3_link_report(tp);
}
if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
......@@ -1965,7 +1995,9 @@ static void tg3_interrupt_main_work(struct tg3 *tp)
struct tg3_hw_status *sblk = tp->hw_status;
int did_pkts;
if (!(tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG)) {
if (!(tp->tg3_flags &
(TG3_FLAG_USE_LINKCHG_REG |
TG3_FLAG_POLL_SERDES))) {
if (sblk->status & SD_STATUS_LINK_CHG) {
sblk->status = SD_STATUS_UPDATED |
(sblk->status & ~SD_STATUS_LINK_CHG);
......@@ -3807,6 +3839,19 @@ static void tg3_timer(unsigned long __opaque)
if (phy_event)
tg3_setup_phy(tp);
} else if (tp->tg3_flags & TG3_FLAG_POLL_SERDES) {
u32 mac_stat = tr32 (MAC_STATUS);
int need_setup = 0;
if (netif_carrier_ok(tp->dev) &&
(mac_stat & MAC_STATUS_LNKSTATE_CHANGED))
need_setup = 1;
if (! netif_carrier_ok(tp->dev) &&
(mac_stat & MAC_STATUS_PCS_SYNCED))
need_setup = 1;
if (need_setup)
tg3_setup_phy(tp);
}
tp->timer_counter = tp->timer_multiplier;
......@@ -5732,6 +5777,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
TG3_FLAG_USE_LINKCHG_REG);
}
/* For all SERDES we poll the MAC status register. */
if (tp->phy_id == PHY_ID_SERDES)
tp->tg3_flags |= TG3_FLAG_POLL_SERDES;
else
tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
/* 5700 BX chips need to have their TX producer index mailboxes
* written twice to workaround a bug.
*/
......
......@@ -1769,6 +1769,7 @@ struct tg3 {
#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010
#define TG3_FLAG_ADAPTIVE_RX 0x00000020
#define TG3_FLAG_ADAPTIVE_TX 0x00000040
#define TG3_FLAG_POLL_SERDES 0x00000080
#define TG3_FLAG_PHY_RESET_ON_INIT 0x00000100
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
#define TG3_FLAG_TAGGED_IRQ_STATUS 0x00000400
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment