Commit 5dde4af0 authored by David S. Miller's avatar David S. Miller

[TG3]: Fibre PHY fixes from Sun.

- Support HW autoneg on 5704.
- On serdes, no MII reg ioctl support.
parent 5f983ea0
/*
* tg3.c: Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
*/
#include <linux/config.h>
......@@ -1961,6 +1962,67 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
return ret;
}
static int fiber_autoneg(struct tg3 *tp, u32 *flags)
{
int res = 0;
if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) {
u32 dig_status;
dig_status = tr32(SG_DIG_STATUS);
*flags = 0;
if (dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
*flags |= MR_LP_ADV_ASYM_PAUSE;
if (dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
*flags |= MR_LP_ADV_SYM_PAUSE;
if ((dig_status & SG_DIG_AUTONEG_COMPLETE) &&
!(dig_status & (SG_DIG_AUTONEG_ERROR |
SG_DIG_PARTNER_FAULT_MASK)))
res = 1;
} else {
struct tg3_fiber_aneginfo aninfo;
int status = ANEG_FAILED;
unsigned int tick;
u32 tmp;
tw32_f(MAC_TX_AUTO_NEG, 0);
tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
udelay(40);
tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
udelay(40);
memset(&aninfo, 0, sizeof(aninfo));
aninfo.flags |= MR_AN_ENABLE;
aninfo.state = ANEG_STATE_UNKNOWN;
aninfo.cur_time = 0;
tick = 0;
while (++tick < 195000) {
status = tg3_fiber_aneg_smachine(tp, &aninfo);
if (status == ANEG_DONE || status == ANEG_FAILED)
break;
udelay(1);
}
tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
*flags = aninfo.flags;
if (status == ANEG_DONE &&
(aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
MR_LP_ADV_FULL_DUPLEX)))
res = 1;
}
return res;
}
static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
{
u32 orig_pause_cfg;
......@@ -1980,6 +2042,20 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) {
/* Allow time for the hardware to auto-negotiate (195ms) */
unsigned int tick = 0;
while (++tick < 195000) {
if (tr32(SG_DIG_STATUS) & SG_DIG_AUTONEG_COMPLETE)
break;
udelay(1);
}
if (tick >= 195000)
printk(KERN_INFO PFX "%s: HW autoneg failed !\n",
tp->dev->name);
}
/* Reset when initting first time or we have a link. */
if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
(tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
......@@ -2032,52 +2108,17 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
current_link_up = 0;
if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
if (tp->link_config.autoneg == AUTONEG_ENABLE &&
!(tp->tg3_flags & TG3_FLAG_GOT_SERDES_FLOWCTL)) {
struct tg3_fiber_aneginfo aninfo;
int status = ANEG_FAILED;
unsigned int tick;
u32 tmp;
memset(&aninfo, 0, sizeof(aninfo));
aninfo.flags |= (MR_AN_ENABLE);
tw32(MAC_TX_AUTO_NEG, 0);
tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
udelay(40);
tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
udelay(40);
aninfo.state = ANEG_STATE_UNKNOWN;
aninfo.cur_time = 0;
tick = 0;
while (++tick < 195000) {
status = tg3_fiber_aneg_smachine(tp, &aninfo);
if (status == ANEG_DONE ||
status == ANEG_FAILED)
break;
udelay(1);
}
tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 flags;
if (status == ANEG_DONE &&
(aninfo.flags &
(MR_AN_COMPLETE | MR_LINK_OK |
MR_LP_ADV_FULL_DUPLEX))) {
if (fiber_autoneg(tp, &flags)) {
u32 local_adv, remote_adv;
local_adv = ADVERTISE_PAUSE_CAP;
remote_adv = 0;
if (aninfo.flags & MR_LP_ADV_SYM_PAUSE)
if (flags & MR_LP_ADV_SYM_PAUSE)
remote_adv |= LPA_PAUSE_CAP;
if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
if (flags & MR_LP_ADV_ASYM_PAUSE)
remote_adv |= LPA_PAUSE_ASYM;
tg3_setup_flow_control(tp, local_adv, remote_adv);
......@@ -2104,8 +2145,10 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
} else {
/* Forcing 1000FD link up. */
current_link_up = 1;
tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
}
}
} else
tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL;
tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
tw32_f(MAC_MODE, tp->mac_mode);
......@@ -5203,6 +5246,26 @@ static int tg3_reset_hw(struct tg3 *tp)
*/
tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
tp->phy_id == PHY_ID_SERDES) {
/* Enable hardware link auto-negotiation */
u32 digctrl, txctrl;
digctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_CRC16_CLEAR_N |
SG_DIG_LOCAL_DUPLEX_STATUS | SG_DIG_LOCAL_LINK_STATUS |
(2 << SG_DIG_SPEED_STATUS_SHIFT) | SG_DIG_FIBER_MODE |
SG_DIG_GBIC_ENABLE;
txctrl = tr32(MAC_SERDES_CFG);
tw32_f(MAC_SERDES_CFG, txctrl | MAC_SERDES_CFG_EDGE_SELECT);
tw32_f(SG_DIG_CTRL, digctrl | SG_DIG_SOFT_RESET);
tr32(SG_DIG_CTRL);
udelay(5);
tw32_f(SG_DIG_CTRL, digctrl);
tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
}
err = tg3_setup_phy(tp, 1);
if (err)
return err;
......@@ -6536,6 +6599,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG: {
u32 mii_regval;
if (tp->phy_id == PHY_ID_SERDES)
break; /* We have no PHY */
spin_lock_irq(&tp->lock);
err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
spin_unlock_irq(&tp->lock);
......@@ -6546,6 +6612,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
case SIOCSMIIREG:
if (tp->phy_id == PHY_ID_SERDES)
break; /* We have no PHY */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
......
/* $Id: tg3.h,v 1.37.2.32 2002/03/11 12:18:18 davem Exp $
* tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
*/
#ifndef _T3_H
......@@ -116,6 +117,7 @@
#define CHIPREV_ID_5704_A0 0x2000
#define CHIPREV_ID_5704_A1 0x2001
#define CHIPREV_ID_5704_A2 0x2002
#define CHIPREV_ID_5704_A3 0x2003
#define CHIPREV_ID_5705_A0 0x3000
#define CHIPREV_ID_5705_A1 0x3001
#define CHIPREV_ID_5705_A2 0x3002
......@@ -518,8 +520,50 @@
#define MAC_EXTADDR_11_HIGH 0x00000588
#define MAC_EXTADDR_11_LOW 0x0000058c
#define MAC_SERDES_CFG 0x00000590
#define MAC_SERDES_CFG_EDGE_SELECT 0x00001000
#define MAC_SERDES_STAT 0x00000594
/* 0x598 --> 0x600 unused */
/* 0x598 --> 0x5b0 unused */
#define SG_DIG_CTRL 0x000005b0
#define SG_DIG_USING_HW_AUTONEG 0x80000000
#define SG_DIG_SOFT_RESET 0x40000000
#define SG_DIG_DISABLE_LINKRDY 0x20000000
#define SG_DIG_CRC16_CLEAR_N 0x01000000
#define SG_DIG_EN10B 0x00800000
#define SG_DIG_CLEAR_STATUS 0x00400000
#define SG_DIG_LOCAL_DUPLEX_STATUS 0x00200000
#define SG_DIG_LOCAL_LINK_STATUS 0x00100000
#define SG_DIG_SPEED_STATUS_MASK 0x000c0000
#define SG_DIG_SPEED_STATUS_SHIFT 18
#define SG_DIG_JUMBO_PACKET_DISABLE 0x00020000
#define SG_DIG_RESTART_AUTONEG 0x00010000
#define SG_DIG_FIBER_MODE 0x00008000
#define SG_DIG_REMOTE_FAULT_MASK 0x00006000
#define SG_DIG_PAUSE_MASK 0x00001800
#define SG_DIG_GBIC_ENABLE 0x00000400
#define SG_DIG_CHECK_END_ENABLE 0x00000200
#define SG_DIG_SGMII_AUTONEG_TIMER 0x00000100
#define SG_DIG_CLOCK_PHASE_SELECT 0x00000080
#define SG_DIG_GMII_INPUT_SELECT 0x00000040
#define SG_DIG_MRADV_CRC16_SELECT 0x00000020
#define SG_DIG_COMMA_DETECT_ENABLE 0x00000010
#define SG_DIG_AUTONEG_TIMER_REDUCE 0x00000008
#define SG_DIG_AUTONEG_LOW_ENABLE 0x00000004
#define SG_DIG_REMOTE_LOOPBACK 0x00000002
#define SG_DIG_LOOPBACK 0x00000001
#define SG_DIG_STATUS 0x000005b4
#define SG_DIG_CRC16_BUS_MASK 0xffff0000
#define SG_DIG_PARTNER_FAULT_MASK 0x00600000 /* If !MRADV_CRC16_SELECT */
#define SG_DIG_PARTNER_ASYM_PAUSE 0x00100000 /* If !MRADV_CRC16_SELECT */
#define SG_DIG_PARTNER_PAUSE_CAPABLE 0x00080000 /* If !MRADV_CRC16_SELECT */
#define SG_DIG_PARTNER_HALF_DUPLEX 0x00040000 /* If !MRADV_CRC16_SELECT */
#define SG_DIG_PARTNER_FULL_DUPLEX 0x00020000 /* If !MRADV_CRC16_SELECT */
#define SG_DIG_PARTNER_NEXT_PAGE 0x00010000 /* If !MRADV_CRC16_SELECT */
#define SG_DIG_AUTONEG_STATE_MASK 0x00000ff0
#define SG_DIG_COMMA_DETECTOR 0x00000008
#define SG_DIG_MAC_ACK_STATUS 0x00000004
#define SG_DIG_AUTONEG_COMPLETE 0x00000002
#define SG_DIG_AUTONEG_ERROR 0x00000001
/* 0x5b8 --> 0x600 unused */
#define MAC_TX_MAC_STATE_BASE 0x00000600 /* 16 bytes */
#define MAC_RX_MAC_STATE_BASE 0x00000610 /* 20 bytes */
/* 0x624 --> 0x800 unused */
......@@ -2044,6 +2088,7 @@ struct tg3 {
#define TG3_FLG2_PHY_BER_BUG 0x00000100
#define TG3_FLG2_PCI_EXPRESS 0x00000200
#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400
#define TG3_FLG2_HW_AUTONEG 0x00000800
u32 split_mode_max_reqs;
#define SPLIT_MODE_5704_MAX_REQ 3
......
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