summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/tg3.c334
-rw-r--r--drivers/net/tg3.h49
2 files changed, 167 insertions, 216 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 6b2a16825fbf..f82c58505056 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1,8 +1,9 @@
/*
* 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>
@@ -56,8 +57,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.6"
-#define DRV_MODULE_RELDATE "June 12, 2004"
+#define DRV_MODULE_VERSION "3.7"
+#define DRV_MODULE_RELDATE "July 2, 2004"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -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)) {
@@ -2031,53 +2107,18 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
udelay(40);
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 (status == ANEG_DONE &&
- (aninfo.flags &
- (MR_AN_COMPLETE | MR_LINK_OK |
- MR_LP_ADV_FULL_DUPLEX))) {
+ if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
+ if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ u32 flags;
+
+ 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)
- remote_adv |= LPA_PAUSE_CAP;
- if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
+ if (flags & MR_LP_ADV_SYM_PAUSE)
+ remote_adv |= LPA_PAUSE_CAP;
+ 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);
@@ -2811,11 +2854,10 @@ static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
u32 base = (u32) mapping & 0xffffffff;
return ((base > 0xffffdcc0) &&
- ((u64) mapping >> 32) == 0 &&
(base + len + 8 < base));
}
-static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
+static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
dma_addr_t mapping;
@@ -3019,165 +3061,6 @@ out_unlock:
return 0;
}
-static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct tg3 *tp = netdev_priv(dev);
- dma_addr_t mapping;
- u32 len, entry, base_flags, mss;
- unsigned long flags;
-
- len = skb_headlen(skb);
-
- /* No BH disabling for tx_lock here. We are running in BH disabled
- * context and TX reclaim runs via tp->poll inside of a software
- * interrupt. Rejoice!
- *
- * Actually, things are not so simple. If we are to take a hw
- * IRQ here, we can deadlock, consider:
- *
- * CPU1 CPU2
- * tg3_start_xmit
- * take tp->tx_lock
- * tg3_timer
- * take tp->lock
- * tg3_interrupt
- * spin on tp->lock
- * spin on tp->tx_lock
- *
- * So we really do need to disable interrupts when taking
- * tx_lock here.
- */
- spin_lock_irqsave(&tp->tx_lock, flags);
-
- /* This is a hard error, log it. */
- if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&tp->tx_lock, flags);
- printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
- dev->name);
- return 1;
- }
-
- entry = tp->tx_prod;
- base_flags = 0;
- if (skb->ip_summed == CHECKSUM_HW)
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_TSO_SUPPORT != 0
- mss = 0;
- if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->tso_size) != 0) {
- int tcp_opt_len, ip_tcp_len;
-
- tcp_opt_len = ((skb->h.th->doff - 5) * 4);
- ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
-
- base_flags |= (TXD_FLAG_CPU_PRE_DMA |
- TXD_FLAG_CPU_POST_DMA);
-
- skb->nh.iph->check = 0;
- skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
- skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
- skb->nh.iph->daddr,
- 0, IPPROTO_TCP, 0);
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
- if (tcp_opt_len || skb->nh.iph->ihl > 5) {
- int tsflags;
-
- tsflags = ((skb->nh.iph->ihl - 5) +
- (tcp_opt_len >> 2));
- mss |= (tsflags << 11);
- }
- } else {
- if (tcp_opt_len || skb->nh.iph->ihl > 5) {
- int tsflags;
-
- tsflags = ((skb->nh.iph->ihl - 5) +
- (tcp_opt_len >> 2));
- base_flags |= tsflags << 12;
- }
- }
- }
-#else
- mss = 0;
-#endif
-#if TG3_VLAN_TAG_USED
- if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
- base_flags |= (TXD_FLAG_VLAN |
- (vlan_tx_tag_get(skb) << 16));
-#endif
-
- /* Queue skb data, a.k.a. the main skb fragment. */
- mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-
- tp->tx_buffers[entry].skb = skb;
- pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
-
- tg3_set_txd(tp, entry, mapping, len, base_flags,
- (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
-
- entry = NEXT_TX(entry);
-
- /* Now loop through additional data fragments, and queue them. */
- if (skb_shinfo(skb)->nr_frags > 0) {
- unsigned int i, last;
-
- last = skb_shinfo(skb)->nr_frags - 1;
- for (i = 0; i <= last; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-
- len = frag->size;
- mapping = pci_map_page(tp->pdev,
- frag->page,
- frag->page_offset,
- len, PCI_DMA_TODEVICE);
-
- tp->tx_buffers[entry].skb = NULL;
- pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
- tg3_set_txd(tp, entry, mapping, len,
- base_flags, (i == last)|(mss << 1));
- else
- tg3_set_txd(tp, entry, mapping, len,
- base_flags, (i == last));
-
- entry = NEXT_TX(entry);
- }
- }
-
- /* Packets are ready, update Tx producer idx local and on card.
- * We know this is not a 5700 (by virtue of not being a chip
- * requiring the 4GB overflow workaround) so we can safely omit
- * the double-write bug tests.
- */
- if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
- tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 +
- TG3_64BIT_REG_LOW), entry);
- } else {
- /* First, make sure tg3 sees last descriptor fully
- * in SRAM.
- */
- if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
- tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
- TG3_64BIT_REG_LOW);
-
- tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 +
- TG3_64BIT_REG_LOW), entry);
- }
-
- tp->tx_prod = entry;
- if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
- netif_stop_queue(dev);
-
- spin_unlock_irqrestore(&tp->tx_lock, flags);
-
- dev->trans_start = jiffies;
-
- return 0;
-}
-
static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
int new_mtu)
{
@@ -5363,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;
@@ -6696,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);
@@ -6706,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;
@@ -7636,13 +7545,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
else
tp->tg3_flags &= ~TG3_FLAG_TXD_MBOX_HWBUG;
- /* 5700 chips can get confused if TX buffers straddle the
- * 4GB address boundary in some cases.
+ /* It seems all chips can get confused if TX buffers
+ * straddle the 4GB address boundary in some cases.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
- tp->dev->hard_start_xmit = tg3_start_xmit_4gbug;
- else
- tp->dev->hard_start_xmit = tg3_start_xmit;
+ tp->dev->hard_start_xmit = tg3_start_xmit;
tp->rx_offset = 2;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index fabc65f7adc7..5c0c104f441e 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1,8 +1,9 @@
/* $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