diff options
| -rw-r--r-- | drivers/net/tg3.c | 334 | ||||
| -rw-r--r-- | drivers/net/tg3.h | 49 |
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 |
