/*
* 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>
#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.8"
+#define DRV_MODULE_RELDATE "July 14, 2004"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
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;
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)) {
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);
} 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);
int received;
hw_idx = tp->hw_status->idx[0].rx_producer;
+ /*
+ * We need to order the read of hw_idx and the read of
+ * the opaque cookie.
+ */
+ rmb();
sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp);
work_mask = 0;
received = 0;
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;
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)
{
/* restore 5701 hardware bug workaround flag */
tp->tg3_flags = flags_save;
+ /* Unfortunately, we have to delay before the PCI read back.
+ * Some 575X chips even will not respond to a PCI cfg access
+ * when the reset command is given to the chip.
+ *
+ * How do these hardware designers expect things to work
+ * properly if the PCI write is posted for a long period
+ * of time? It is always necessary to have some method by
+ * which a register read back can occur to push the write
+ * out which does the reset.
+ *
+ * For most tg3 variants the trick below was working.
+ * Ho hum...
+ */
+ udelay(120);
+
/* Flush PCI posted writes. The normal MMIO registers
* are inaccessible at this time so this is the only
- * way to make this reliably. I tried to use indirect
+ * way to make this reliably (actually, this is no longer
+ * the case, see above). I tried to use indirect
* register read/write but this upset some 5701 variants.
*/
pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
*/
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;
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);
}
case SIOCSMIIREG:
+ if (tp->phy_id == PHY_ID_SERDES)
+ break; /* We have no PHY */
+
if (!capable(CAP_NET_ADMIN))
return -EPERM;
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 &&