Merge tag 'mvebu-soc-3.17-2' of git://git.infradead.org/linux-mvebu into next/soc
[cascardo/linux.git] / drivers / net / ethernet / broadcom / tg3.c
index e5d95c5..8afa579 100644 (file)
@@ -4,7 +4,7 @@
  * 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.
- * Copyright (C) 2005-2013 Broadcom Corporation.
+ * Copyright (C) 2005-2014 Broadcom Corporation.
  *
  * Firmware is:
  *     Derived from proprietary unpublished source code,
@@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    136
+#define TG3_MIN_NUM                    137
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "Jan 03, 2014"
+#define DRV_MODULE_RELDATE     "May 11, 2014"
 
 #define RESET_KIND_SHUTDOWN    0
 #define RESET_KIND_INIT                1
@@ -3224,7 +3224,7 @@ static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
        return 0;
 }
 
-#define NVRAM_CMD_TIMEOUT 10000
+#define NVRAM_CMD_TIMEOUT 5000
 
 static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
 {
@@ -3232,7 +3232,7 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
 
        tw32(NVRAM_CMD, nvram_cmd);
        for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
-               udelay(10);
+               usleep_range(10, 40);
                if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
                        udelay(10);
                        break;
@@ -7854,8 +7854,8 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
                netif_wake_queue(tp->dev);
        }
 
-       segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
-       if (IS_ERR(segs))
+       segs = skb_gso_segment(skb, tp->dev->features & ~(NETIF_F_TSO | NETIF_F_TSO6));
+       if (IS_ERR(segs) || !segs)
                goto tg3_tso_bug_end;
 
        do {
@@ -7871,9 +7871,7 @@ tg3_tso_bug_end:
        return NETDEV_TX_OK;
 }
 
-/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
- * support TG3_FLAG_HW_TSO_1 or firmware TSO only.
- */
+/* hard_start_xmit for all devices */
 static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -7884,6 +7882,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct tg3_napi *tnapi;
        struct netdev_queue *txq;
        unsigned int last;
+       struct iphdr *iph = NULL;
+       struct tcphdr *tcph = NULL;
+       __sum16 tcp_csum = 0, ip_csum = 0;
+       __be16 ip_tot_len = 0;
 
        txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
        tnapi = &tp->napi[skb_get_queue_mapping(skb)];
@@ -7915,7 +7917,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        mss = skb_shinfo(skb)->gso_size;
        if (mss) {
-               struct iphdr *iph;
                u32 tcp_opt_len, hdr_len;
 
                if (skb_cow_head(skb, 0))
@@ -7927,27 +7928,31 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb) - ETH_HLEN;
 
                if (!skb_is_gso_v6(skb)) {
+                       if (unlikely((ETH_HLEN + hdr_len) > 80) &&
+                           tg3_flag(tp, TSO_BUG))
+                               return tg3_tso_bug(tp, skb);
+
+                       ip_csum = iph->check;
+                       ip_tot_len = iph->tot_len;
                        iph->check = 0;
                        iph->tot_len = htons(mss + hdr_len);
                }
 
-               if (unlikely((ETH_HLEN + hdr_len) > 80) &&
-                   tg3_flag(tp, TSO_BUG))
-                       return tg3_tso_bug(tp, skb);
-
                base_flags |= (TXD_FLAG_CPU_PRE_DMA |
                               TXD_FLAG_CPU_POST_DMA);
 
+               tcph = tcp_hdr(skb);
+               tcp_csum = tcph->check;
+
                if (tg3_flag(tp, HW_TSO_1) ||
                    tg3_flag(tp, HW_TSO_2) ||
                    tg3_flag(tp, HW_TSO_3)) {
-                       tcp_hdr(skb)->check = 0;
+                       tcph->check = 0;
                        base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
-               } else
-                       tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
-                                                                iph->daddr, 0,
-                                                                IPPROTO_TCP,
-                                                                0);
+               } else {
+                       tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                        0, IPPROTO_TCP, 0);
+               }
 
                if (tg3_flag(tp, HW_TSO_3)) {
                        mss |= (hdr_len & 0xc) << 12;
@@ -8047,6 +8052,18 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (would_hit_hwbug) {
                tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
 
+               if (mss) {
+                       /* If it's a TSO packet, do GSO instead of
+                        * allocating and copying to a large linear SKB
+                        */
+                       if (ip_tot_len) {
+                               iph->check = ip_csum;
+                               iph->tot_len = ip_tot_len;
+                       }
+                       tcph->check = tcp_csum;
+                       return tg3_tso_bug(tp, skb);
+               }
+
                /* If the workaround fails due to memory/mapping
                 * failure, silently drop this packet.
                 */
@@ -11876,9 +11893,9 @@ static int tg3_get_eeprom_len(struct net_device *dev)
 static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int ret;
+       int ret, cpmu_restore = 0;
        u8  *pd;
-       u32 i, offset, len, b_offset, b_count;
+       u32 i, offset, len, b_offset, b_count, cpmu_val = 0;
        __be32 val;
 
        if (tg3_flag(tp, NO_NVRAM))
@@ -11890,6 +11907,19 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        eeprom->magic = TG3_EEPROM_MAGIC;
 
+       /* Override clock, link aware and link idle modes */
+       if (tg3_flag(tp, CPMU_PRESENT)) {
+               cpmu_val = tr32(TG3_CPMU_CTRL);
+               if (cpmu_val & (CPMU_CTRL_LINK_AWARE_MODE |
+                               CPMU_CTRL_LINK_IDLE_MODE)) {
+                       tw32(TG3_CPMU_CTRL, cpmu_val &
+                                           ~(CPMU_CTRL_LINK_AWARE_MODE |
+                                            CPMU_CTRL_LINK_IDLE_MODE));
+                       cpmu_restore = 1;
+               }
+       }
+       tg3_override_clk(tp);
+
        if (offset & 3) {
                /* adjustments to start on required 4 byte boundary */
                b_offset = offset & 3;
@@ -11900,7 +11930,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                }
                ret = tg3_nvram_read_be32(tp, offset-b_offset, &val);
                if (ret)
-                       return ret;
+                       goto eeprom_done;
                memcpy(data, ((char *)&val) + b_offset, b_count);
                len -= b_count;
                offset += b_count;
@@ -11912,10 +11942,20 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        for (i = 0; i < (len - (len & 3)); i += 4) {
                ret = tg3_nvram_read_be32(tp, offset + i, &val);
                if (ret) {
+                       if (i)
+                               i -= 4;
                        eeprom->len += i;
-                       return ret;
+                       goto eeprom_done;
                }
                memcpy(pd + i, &val, 4);
+               if (need_resched()) {
+                       if (signal_pending(current)) {
+                               eeprom->len += i;
+                               ret = -EINTR;
+                               goto eeprom_done;
+                       }
+                       cond_resched();
+               }
        }
        eeprom->len += i;
 
@@ -11926,11 +11966,19 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                b_offset = offset + len - b_count;
                ret = tg3_nvram_read_be32(tp, b_offset, &val);
                if (ret)
-                       return ret;
+                       goto eeprom_done;
                memcpy(pd, &val, b_count);
                eeprom->len += b_count;
        }
-       return 0;
+       ret = 0;
+
+eeprom_done:
+       /* Restore clock, link aware and link idle modes */
+       tg3_restore_clk(tp);
+       if (cpmu_restore)
+               tw32(TG3_CPMU_CTRL, cpmu_val);
+
+       return ret;
 }
 
 static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
@@ -12484,7 +12532,7 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev)
        return size;
 }
 
-static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir)
+static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key)
 {
        struct tg3 *tp = netdev_priv(dev);
        int i;
@@ -12495,7 +12543,7 @@ static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir)
        return 0;
 }
 
-static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir)
+static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key)
 {
        struct tg3 *tp = netdev_priv(dev);
        size_t i;
@@ -14027,8 +14075,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
        .get_sset_count         = tg3_get_sset_count,
        .get_rxnfc              = tg3_get_rxnfc,
        .get_rxfh_indir_size    = tg3_get_rxfh_indir_size,
-       .get_rxfh_indir         = tg3_get_rxfh_indir,
-       .set_rxfh_indir         = tg3_set_rxfh_indir,
+       .get_rxfh               = tg3_get_rxfh,
+       .set_rxfh               = tg3_set_rxfh,
        .get_channels           = tg3_get_channels,
        .set_channels           = tg3_set_channels,
        .get_ts_info            = tg3_get_ts_info,