VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / net / tg3.c
index 6b2a168..0e46154 100644 (file)
@@ -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.8"
+#define DRV_MODULE_RELDATE     "July 14, 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);
@@ -2412,6 +2455,11 @@ static int tg3_rx(struct tg3 *tp, int budget)
        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;
@@ -2811,11 +2859,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 +3066,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)
 {
@@ -3747,9 +3635,25 @@ static int tg3_chip_reset(struct tg3 *tp)
        /* 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);
@@ -5363,6 +5267,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 +6620,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 +6633,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 +7566,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 &&