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

Tigon3: Make fibre PHY support work.

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