correction, one has a SoB, the other has a description. having both in
both patches would be nice

        John


On 08/10/2015 10:06, John Crispin wrote:
> Hi,
> 
> SoB is missing from this and the CC backport patch
> 
>       John
> 


> On 05/10/2015 22:26, David Woodhouse wrote:
>> For all kernels, add the fixes which are already in 4.3-rc4.
>>
>> For 4.0+, also add the fixes currently in net-next which fix and enable
>> hardware checksum and TSO support.
>>
>> ---
>>  .../patches-3.18/760-8139cp-fixes-from-4.3.patch   | 367 
>> +++++++++++++++++++++
>>  .../patches-4.0/760-8139cp-fixes-from-4.3.patch    | 367 
>> +++++++++++++++++++++
>>  .../patches-4.0/761-8139cp-fixes-from-4.4.patch    | 105 ++++++
>>  .../patches-4.1/760-8139cp-fixes-from-4.3.patch    | 367 
>> +++++++++++++++++++++
>>  .../patches-4.1/761-8139cp-fixes-from-4.4.patch    | 105 ++++++
>>  5 files changed, 1311 insertions(+)
>>  create mode 100644 
>> target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch
>>  create mode 100644 
>> target/linux/generic/patches-4.0/760-8139cp-fixes-from-4.3.patch
>>  create mode 100644 
>> target/linux/generic/patches-4.0/761-8139cp-fixes-from-4.4.patch
>>  create mode 100644 
>> target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch
>>  create mode 100644 
>> target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch
>>
>> diff --git 
>> a/target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch 
>> b/target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch
>> new file mode 100644
>> index 0000000..de4c127
>> --- /dev/null
>> +++ b/target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch
>> @@ -0,0 +1,367 @@
>> +commit 41b976414c88016e2c9d9b2f6667ee67a998d388
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:45:31 2015 +0100
>> +
>> +    8139cp: Dump contents of descriptor ring on TX timeout
>> +    
>> +    We are seeing unexplained TX timeouts under heavy load. Let's try to get
>> +    a better idea of what's going on.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 7f4c685633e2df9ba10d49a31dda13715745db37
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:45:16 2015 +0100
>> +
>> +    8139cp: Fix DMA unmapping of transmitted buffers
>> +    
>> +    The low 16 bits of the 'opts1' field in the TX descriptor are supposed
>> +    to still contain the buffer length when the descriptor is handed back to
>> +    us. In practice, at least on my hardware, they don't. So stash the
>> +    original value of the opts1 field and get the length to unmap from
>> +    there.
>> +    
>> +    There are other ways we could have worked out the length, but I actually
>> +    want a stash of the opts1 field anyway so that I can dump it alongside
>> +    the contents of the descriptor ring when we suffer a TX timeout.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 0a5aeee0b79fa99d8e04c98dd4e87d4f52aa497b
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:57 2015 +0100
>> +
>> +    8139cp: Reduce duplicate csum/tso code in cp_start_xmit()
>> +    
>> +    We calculate the value of the opts1 descriptor field in three different
>> +    places. With two different behaviours when given an invalid packet to
>> +    be checksummed — none of them correct. Sort that out.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit a3b804043f490aeec57d8ca5baccdd35e6250857
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:38 2015 +0100
>> +
>> +    8139cp: Fix TSO/scatter-gather descriptor setup
>> +    
>> +    When sending a TSO frame in multiple buffers, we were neglecting to set
>> +    the first descriptor up in TSO mode.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 26b0bad6ac3a0167792dc4ffb276c29bc597d239
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:06 2015 +0100
>> +
>> +    8139cp: Fix tx_queued debug message to print correct slot numbers
>> +    
>> +    After a certain amount of staring at the debug output of this driver, I
>> +    realised it was lying to me.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit aaa0062ecf4877a26dea66bee1039c6eaf906c94
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:43:41 2015 +0100
>> +
>> +    8139cp: Do not re-enable RX interrupts in cp_tx_timeout()
>> +    
>> +    If an RX interrupt was already received but NAPI has not yet run when
>> +    the RX timeout happens, we end up in cp_tx_timeout() with RX interrupts
>> +    already disabled. Blindly re-enabling them will cause an IRQ storm.
>> +    
>> +    (This is made particularly horrid by the fact that cp_interrupt() always
>> +    returns that it's handled the interrupt, even when it hasn't actually
>> +    done anything. If it didn't do that, the core IRQ code would have
>> +    detected the storm and handled it, I'd have had a clear smoking gun
>> +    backtrace instead of just a spontaneously resetting router, and I'd have
>> +    at *least* two days of my life back. Changing the return value of
>> +    cp_interrupt() will be argued about under separate cover.)
>> +    
>> +    Unconditionally leave RX interrupts disabled after the reset, and
>> +    schedule NAPI to check the receive ring and re-enable them.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 7a8a8e75d505147358b225173e890ada43a267e2
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Fri Sep 18 00:21:54 2015 +0100
>> +
>> +    8139cp: Call __cp_set_rx_mode() from cp_tx_timeout()
>> +    
>> +    Unless we reset the RX config, on real hardware I don't seem to receive
>> +    any packets after a TX timeout.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit fc27bd115b334e3ebdc682a42a47c3aea2566dcc
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Fri Sep 18 00:19:08 2015 +0100
>> +
>> +    8139cp: Use dev_kfree_skb_any() instead of dev_kfree_skb() in 
>> cp_clean_rings()
>> +    
>> +    This can be called from cp_tx_timeout() with interrupts disabled.
>> +    Spotted by Francois Romieu <rom...@fr.zoreil.com>
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +diff --git a/drivers/net/ethernet/realtek/8139cp.c 
>> b/drivers/net/ethernet/realtek/8139cp.c
>> +index d79e33b..686334f 100644
>> +--- a/drivers/net/ethernet/realtek/8139cp.c
>> ++++ b/drivers/net/ethernet/realtek/8139cp.c
>> +@@ -157,6 +157,7 @@ enum {
>> +    NWayAdvert      = 0x66, /* MII ADVERTISE */
>> +    NWayLPAR        = 0x68, /* MII LPA */
>> +    NWayExpansion   = 0x6A, /* MII Expansion */
>> ++   TxDmaOkLowDesc  = 0x82, /* Low 16 bit address of a Tx descriptor. */
>> +    Config5         = 0xD8, /* Config5 */
>> +    TxPoll          = 0xD9, /* Tell chip to check Tx descriptors for work */
>> +    RxMaxSize       = 0xDA, /* Max size of an Rx packet (8169 only) */
>> +@@ -341,6 +342,7 @@ struct cp_private {
>> +    unsigned                tx_tail;
>> +    struct cp_desc          *tx_ring;
>> +    struct sk_buff          *tx_skb[CP_TX_RING_SIZE];
>> ++   u32                     tx_opts[CP_TX_RING_SIZE];
>> + 
>> +    unsigned                rx_buf_sz;
>> +    unsigned                wol_enabled : 1; /* Is Wake-on-LAN enabled? */
>> +@@ -665,7 +667,7 @@ static void cp_tx (struct cp_private *cp)
>> +            BUG_ON(!skb);
>> + 
>> +            dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
>> +-                            le32_to_cpu(txd->opts1) & 0xffff,
>> ++                            cp->tx_opts[tx_tail] & 0xffff,
>> +                             PCI_DMA_TODEVICE);
>> + 
>> +            if (status & LastFrag) {
>> +@@ -733,7 +735,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> + {
>> +    struct cp_private *cp = netdev_priv(dev);
>> +    unsigned entry;
>> +-   u32 eor, flags;
>> ++   u32 eor, opts1;
>> +    unsigned long intr_flags;
>> +    __le32 opts2;
>> +    int mss = 0;
>> +@@ -753,6 +755,21 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +    mss = skb_shinfo(skb)->gso_size;
>> + 
>> +    opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
>> ++   opts1 = DescOwn;
>> ++   if (mss)
>> ++           opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
>> ++   else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> ++           const struct iphdr *ip = ip_hdr(skb);
>> ++           if (ip->protocol == IPPROTO_TCP)
>> ++                   opts1 |= IPCS | TCPCS;
>> ++           else if (ip->protocol == IPPROTO_UDP)
>> ++                   opts1 |= IPCS | UDPCS;
>> ++           else {
>> ++                   WARN_ONCE(1,
>> ++                             "Net bug: asked to checksum invalid Legacy IP 
>> packet\n");
>> ++                   goto out_dma_error;
>> ++           }
>> ++   }
>> + 
>> +    if (skb_shinfo(skb)->nr_frags == 0) {
>> +            struct cp_desc *txd = &cp->tx_ring[entry];
>> +@@ -768,31 +785,20 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +            txd->addr = cpu_to_le64(mapping);
>> +            wmb();
>> + 
>> +-           flags = eor | len | DescOwn | FirstFrag | LastFrag;
>> +-
>> +-           if (mss)
>> +-                   flags |= LargeSend | ((mss & MSSMask) << MSSShift);
>> +-           else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                   const struct iphdr *ip = ip_hdr(skb);
>> +-                   if (ip->protocol == IPPROTO_TCP)
>> +-                           flags |= IPCS | TCPCS;
>> +-                   else if (ip->protocol == IPPROTO_UDP)
>> +-                           flags |= IPCS | UDPCS;
>> +-                   else
>> +-                           WARN_ON(1);     /* we need a WARN() */
>> +-           }
>> ++           opts1 |= eor | len | FirstFrag | LastFrag;
>> + 
>> +-           txd->opts1 = cpu_to_le32(flags);
>> ++           txd->opts1 = cpu_to_le32(opts1);
>> +            wmb();
>> + 
>> +            cp->tx_skb[entry] = skb;
>> +-           entry = NEXT_TX(entry);
>> ++           cp->tx_opts[entry] = opts1;
>> ++           netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen 
>> %d\n",
>> ++                     entry, skb->len);
>> +    } else {
>> +            struct cp_desc *txd;
>> +-           u32 first_len, first_eor;
>> ++           u32 first_len, first_eor, ctrl;
>> +            dma_addr_t first_mapping;
>> +            int frag, first_entry = entry;
>> +-           const struct iphdr *ip = ip_hdr(skb);
>> + 
>> +            /* We must give this initial chunk to the device last.
>> +             * Otherwise we could race with the device.
>> +@@ -805,14 +811,14 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +                    goto out_dma_error;
>> + 
>> +            cp->tx_skb[entry] = skb;
>> +-           entry = NEXT_TX(entry);
>> + 
>> +            for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
>> +                    const skb_frag_t *this_frag = 
>> &skb_shinfo(skb)->frags[frag];
>> +                    u32 len;
>> +-                   u32 ctrl;
>> +                    dma_addr_t mapping;
>> + 
>> ++                   entry = NEXT_TX(entry);
>> ++
>> +                    len = skb_frag_size(this_frag);
>> +                    mapping = dma_map_single(&cp->pdev->dev,
>> +                                             skb_frag_address(this_frag),
>> +@@ -824,19 +830,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> + 
>> +                    eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
>> + 
>> +-                   ctrl = eor | len | DescOwn;
>> +-
>> +-                   if (mss)
>> +-                           ctrl |= LargeSend |
>> +-                                   ((mss & MSSMask) << MSSShift);
>> +-                   else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                           if (ip->protocol == IPPROTO_TCP)
>> +-                                   ctrl |= IPCS | TCPCS;
>> +-                           else if (ip->protocol == IPPROTO_UDP)
>> +-                                   ctrl |= IPCS | UDPCS;
>> +-                           else
>> +-                                   BUG();
>> +-                   }
>> ++                   ctrl = opts1 | eor | len;
>> + 
>> +                    if (frag == skb_shinfo(skb)->nr_frags - 1)
>> +                            ctrl |= LastFrag;
>> +@@ -849,8 +843,8 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +                    txd->opts1 = cpu_to_le32(ctrl);
>> +                    wmb();
>> + 
>> ++                   cp->tx_opts[entry] = ctrl;
>> +                    cp->tx_skb[entry] = skb;
>> +-                   entry = NEXT_TX(entry);
>> +            }
>> + 
>> +            txd = &cp->tx_ring[first_entry];
>> +@@ -858,27 +852,17 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +            txd->addr = cpu_to_le64(first_mapping);
>> +            wmb();
>> + 
>> +-           if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                   if (ip->protocol == IPPROTO_TCP)
>> +-                           txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                                    FirstFrag | DescOwn |
>> +-                                                    IPCS | TCPCS);
>> +-                   else if (ip->protocol == IPPROTO_UDP)
>> +-                           txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                                    FirstFrag | DescOwn |
>> +-                                                    IPCS | UDPCS);
>> +-                   else
>> +-                           BUG();
>> +-           } else
>> +-                   txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                            FirstFrag | DescOwn);
>> ++           ctrl = opts1 | first_eor | first_len | FirstFrag;
>> ++           txd->opts1 = cpu_to_le32(ctrl);
>> +            wmb();
>> ++
>> ++           cp->tx_opts[first_entry] = ctrl;
>> ++           netif_dbg(cp, tx_queued, cp->dev, "tx queued, slots %d-%d, 
>> skblen %d\n",
>> ++                     first_entry, entry, skb->len);
>> +    }
>> +-   cp->tx_head = entry;
>> ++   cp->tx_head = NEXT_TX(entry);
>> + 
>> +    netdev_sent_queue(dev, skb->len);
>> +-   netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
>> +-             entry, skb->len);
>> +    if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
>> +            netif_stop_queue(dev);
>> + 
>> +@@ -1115,6 +1099,7 @@ static int cp_init_rings (struct cp_private *cp)
>> + {
>> +    memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
>> +    cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
>> ++   memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
>> + 
>> +    cp_init_rings_index(cp);
>> + 
>> +@@ -1151,7 +1136,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> +                    desc = cp->rx_ring + i;
>> +                    dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
>> +                                     cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
>> +-                   dev_kfree_skb(cp->rx_skb[i]);
>> ++                   dev_kfree_skb_any(cp->rx_skb[i]);
>> +            }
>> +    }
>> + 
>> +@@ -1164,7 +1149,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> +                                     le32_to_cpu(desc->opts1) & 0xffff,
>> +                                     PCI_DMA_TODEVICE);
>> +                    if (le32_to_cpu(desc->opts1) & LastFrag)
>> +-                           dev_kfree_skb(skb);
>> ++                           dev_kfree_skb_any(skb);
>> +                    cp->dev->stats.tx_dropped++;
>> +            }
>> +    }
>> +@@ -1172,6 +1157,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> + 
>> +    memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
>> +    memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
>> ++   memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
>> + 
>> +    memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
>> +    memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
>> +@@ -1249,7 +1235,7 @@ static void cp_tx_timeout(struct net_device *dev)
>> + {
>> +    struct cp_private *cp = netdev_priv(dev);
>> +    unsigned long flags;
>> +-   int rc;
>> ++   int rc, i;
>> + 
>> +    netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
>> +                cpr8(Cmd), cpr16(CpCmd),
>> +@@ -1257,13 +1243,26 @@ static void cp_tx_timeout(struct net_device *dev)
>> + 
>> +    spin_lock_irqsave(&cp->lock, flags);
>> + 
>> ++   netif_dbg(cp, tx_err, cp->dev, "TX ring head %d tail %d desc %x\n",
>> ++             cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc));
>> ++   for (i = 0; i < CP_TX_RING_SIZE; i++) {
>> ++           netif_dbg(cp, tx_err, cp->dev,
>> ++                     "TX slot %d @%p: %08x (%08x) %08x %llx %p\n",
>> ++                     i, &cp->tx_ring[i], le32_to_cpu(cp->tx_ring[i].opts1),
>> ++                     cp->tx_opts[i], le32_to_cpu(cp->tx_ring[i].opts2),
>> ++                     le64_to_cpu(cp->tx_ring[i].addr),
>> ++                     cp->tx_skb[i]);
>> ++   }
>> ++
>> +    cp_stop_hw(cp);
>> +    cp_clean_rings(cp);
>> +    rc = cp_init_rings(cp);
>> +    cp_start_hw(cp);
>> +-   cp_enable_irq(cp);
>> ++   __cp_set_rx_mode(dev);
>> ++   cpw16_f(IntrMask, cp_norx_intr_mask);
>> + 
>> +    netif_wake_queue(dev);
>> ++   napi_schedule(&cp->napi);
>> + 
>> +    spin_unlock_irqrestore(&cp->lock, flags);
>> + }
>> diff --git 
>> a/target/linux/generic/patches-4.0/760-8139cp-fixes-from-4.3.patch 
>> b/target/linux/generic/patches-4.0/760-8139cp-fixes-from-4.3.patch
>> new file mode 100644
>> index 0000000..6cbcf2e
>> --- /dev/null
>> +++ b/target/linux/generic/patches-4.0/760-8139cp-fixes-from-4.3.patch
>> @@ -0,0 +1,367 @@
>> +commit 41b976414c88016e2c9d9b2f6667ee67a998d388
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:45:31 2015 +0100
>> +
>> +    8139cp: Dump contents of descriptor ring on TX timeout
>> +    
>> +    We are seeing unexplained TX timeouts under heavy load. Let's try to get
>> +    a better idea of what's going on.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 7f4c685633e2df9ba10d49a31dda13715745db37
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:45:16 2015 +0100
>> +
>> +    8139cp: Fix DMA unmapping of transmitted buffers
>> +    
>> +    The low 16 bits of the 'opts1' field in the TX descriptor are supposed
>> +    to still contain the buffer length when the descriptor is handed back to
>> +    us. In practice, at least on my hardware, they don't. So stash the
>> +    original value of the opts1 field and get the length to unmap from
>> +    there.
>> +    
>> +    There are other ways we could have worked out the length, but I actually
>> +    want a stash of the opts1 field anyway so that I can dump it alongside
>> +    the contents of the descriptor ring when we suffer a TX timeout.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 0a5aeee0b79fa99d8e04c98dd4e87d4f52aa497b
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:57 2015 +0100
>> +
>> +    8139cp: Reduce duplicate csum/tso code in cp_start_xmit()
>> +    
>> +    We calculate the value of the opts1 descriptor field in three different
>> +    places. With two different behaviours when given an invalid packet to
>> +    be checksummed — none of them correct. Sort that out.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit a3b804043f490aeec57d8ca5baccdd35e6250857
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:38 2015 +0100
>> +
>> +    8139cp: Fix TSO/scatter-gather descriptor setup
>> +    
>> +    When sending a TSO frame in multiple buffers, we were neglecting to set
>> +    the first descriptor up in TSO mode.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 26b0bad6ac3a0167792dc4ffb276c29bc597d239
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:06 2015 +0100
>> +
>> +    8139cp: Fix tx_queued debug message to print correct slot numbers
>> +    
>> +    After a certain amount of staring at the debug output of this driver, I
>> +    realised it was lying to me.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit aaa0062ecf4877a26dea66bee1039c6eaf906c94
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:43:41 2015 +0100
>> +
>> +    8139cp: Do not re-enable RX interrupts in cp_tx_timeout()
>> +    
>> +    If an RX interrupt was already received but NAPI has not yet run when
>> +    the RX timeout happens, we end up in cp_tx_timeout() with RX interrupts
>> +    already disabled. Blindly re-enabling them will cause an IRQ storm.
>> +    
>> +    (This is made particularly horrid by the fact that cp_interrupt() always
>> +    returns that it's handled the interrupt, even when it hasn't actually
>> +    done anything. If it didn't do that, the core IRQ code would have
>> +    detected the storm and handled it, I'd have had a clear smoking gun
>> +    backtrace instead of just a spontaneously resetting router, and I'd have
>> +    at *least* two days of my life back. Changing the return value of
>> +    cp_interrupt() will be argued about under separate cover.)
>> +    
>> +    Unconditionally leave RX interrupts disabled after the reset, and
>> +    schedule NAPI to check the receive ring and re-enable them.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 7a8a8e75d505147358b225173e890ada43a267e2
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Fri Sep 18 00:21:54 2015 +0100
>> +
>> +    8139cp: Call __cp_set_rx_mode() from cp_tx_timeout()
>> +    
>> +    Unless we reset the RX config, on real hardware I don't seem to receive
>> +    any packets after a TX timeout.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit fc27bd115b334e3ebdc682a42a47c3aea2566dcc
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Fri Sep 18 00:19:08 2015 +0100
>> +
>> +    8139cp: Use dev_kfree_skb_any() instead of dev_kfree_skb() in 
>> cp_clean_rings()
>> +    
>> +    This can be called from cp_tx_timeout() with interrupts disabled.
>> +    Spotted by Francois Romieu <rom...@fr.zoreil.com>
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +diff --git a/drivers/net/ethernet/realtek/8139cp.c 
>> b/drivers/net/ethernet/realtek/8139cp.c
>> +index d79e33b..686334f 100644
>> +--- a/drivers/net/ethernet/realtek/8139cp.c
>> ++++ b/drivers/net/ethernet/realtek/8139cp.c
>> +@@ -157,6 +157,7 @@ enum {
>> +    NWayAdvert      = 0x66, /* MII ADVERTISE */
>> +    NWayLPAR        = 0x68, /* MII LPA */
>> +    NWayExpansion   = 0x6A, /* MII Expansion */
>> ++   TxDmaOkLowDesc  = 0x82, /* Low 16 bit address of a Tx descriptor. */
>> +    Config5         = 0xD8, /* Config5 */
>> +    TxPoll          = 0xD9, /* Tell chip to check Tx descriptors for work */
>> +    RxMaxSize       = 0xDA, /* Max size of an Rx packet (8169 only) */
>> +@@ -341,6 +342,7 @@ struct cp_private {
>> +    unsigned                tx_tail;
>> +    struct cp_desc          *tx_ring;
>> +    struct sk_buff          *tx_skb[CP_TX_RING_SIZE];
>> ++   u32                     tx_opts[CP_TX_RING_SIZE];
>> + 
>> +    unsigned                rx_buf_sz;
>> +    unsigned                wol_enabled : 1; /* Is Wake-on-LAN enabled? */
>> +@@ -665,7 +667,7 @@ static void cp_tx (struct cp_private *cp)
>> +            BUG_ON(!skb);
>> + 
>> +            dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
>> +-                            le32_to_cpu(txd->opts1) & 0xffff,
>> ++                            cp->tx_opts[tx_tail] & 0xffff,
>> +                             PCI_DMA_TODEVICE);
>> + 
>> +            if (status & LastFrag) {
>> +@@ -733,7 +735,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> + {
>> +    struct cp_private *cp = netdev_priv(dev);
>> +    unsigned entry;
>> +-   u32 eor, flags;
>> ++   u32 eor, opts1;
>> +    unsigned long intr_flags;
>> +    __le32 opts2;
>> +    int mss = 0;
>> +@@ -753,6 +755,21 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +    mss = skb_shinfo(skb)->gso_size;
>> + 
>> +    opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
>> ++   opts1 = DescOwn;
>> ++   if (mss)
>> ++           opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
>> ++   else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> ++           const struct iphdr *ip = ip_hdr(skb);
>> ++           if (ip->protocol == IPPROTO_TCP)
>> ++                   opts1 |= IPCS | TCPCS;
>> ++           else if (ip->protocol == IPPROTO_UDP)
>> ++                   opts1 |= IPCS | UDPCS;
>> ++           else {
>> ++                   WARN_ONCE(1,
>> ++                             "Net bug: asked to checksum invalid Legacy IP 
>> packet\n");
>> ++                   goto out_dma_error;
>> ++           }
>> ++   }
>> + 
>> +    if (skb_shinfo(skb)->nr_frags == 0) {
>> +            struct cp_desc *txd = &cp->tx_ring[entry];
>> +@@ -768,31 +785,20 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +            txd->addr = cpu_to_le64(mapping);
>> +            wmb();
>> + 
>> +-           flags = eor | len | DescOwn | FirstFrag | LastFrag;
>> +-
>> +-           if (mss)
>> +-                   flags |= LargeSend | ((mss & MSSMask) << MSSShift);
>> +-           else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                   const struct iphdr *ip = ip_hdr(skb);
>> +-                   if (ip->protocol == IPPROTO_TCP)
>> +-                           flags |= IPCS | TCPCS;
>> +-                   else if (ip->protocol == IPPROTO_UDP)
>> +-                           flags |= IPCS | UDPCS;
>> +-                   else
>> +-                           WARN_ON(1);     /* we need a WARN() */
>> +-           }
>> ++           opts1 |= eor | len | FirstFrag | LastFrag;
>> + 
>> +-           txd->opts1 = cpu_to_le32(flags);
>> ++           txd->opts1 = cpu_to_le32(opts1);
>> +            wmb();
>> + 
>> +            cp->tx_skb[entry] = skb;
>> +-           entry = NEXT_TX(entry);
>> ++           cp->tx_opts[entry] = opts1;
>> ++           netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen 
>> %d\n",
>> ++                     entry, skb->len);
>> +    } else {
>> +            struct cp_desc *txd;
>> +-           u32 first_len, first_eor;
>> ++           u32 first_len, first_eor, ctrl;
>> +            dma_addr_t first_mapping;
>> +            int frag, first_entry = entry;
>> +-           const struct iphdr *ip = ip_hdr(skb);
>> + 
>> +            /* We must give this initial chunk to the device last.
>> +             * Otherwise we could race with the device.
>> +@@ -805,14 +811,14 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +                    goto out_dma_error;
>> + 
>> +            cp->tx_skb[entry] = skb;
>> +-           entry = NEXT_TX(entry);
>> + 
>> +            for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
>> +                    const skb_frag_t *this_frag = 
>> &skb_shinfo(skb)->frags[frag];
>> +                    u32 len;
>> +-                   u32 ctrl;
>> +                    dma_addr_t mapping;
>> + 
>> ++                   entry = NEXT_TX(entry);
>> ++
>> +                    len = skb_frag_size(this_frag);
>> +                    mapping = dma_map_single(&cp->pdev->dev,
>> +                                             skb_frag_address(this_frag),
>> +@@ -824,19 +830,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> + 
>> +                    eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
>> + 
>> +-                   ctrl = eor | len | DescOwn;
>> +-
>> +-                   if (mss)
>> +-                           ctrl |= LargeSend |
>> +-                                   ((mss & MSSMask) << MSSShift);
>> +-                   else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                           if (ip->protocol == IPPROTO_TCP)
>> +-                                   ctrl |= IPCS | TCPCS;
>> +-                           else if (ip->protocol == IPPROTO_UDP)
>> +-                                   ctrl |= IPCS | UDPCS;
>> +-                           else
>> +-                                   BUG();
>> +-                   }
>> ++                   ctrl = opts1 | eor | len;
>> + 
>> +                    if (frag == skb_shinfo(skb)->nr_frags - 1)
>> +                            ctrl |= LastFrag;
>> +@@ -849,8 +843,8 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +                    txd->opts1 = cpu_to_le32(ctrl);
>> +                    wmb();
>> + 
>> ++                   cp->tx_opts[entry] = ctrl;
>> +                    cp->tx_skb[entry] = skb;
>> +-                   entry = NEXT_TX(entry);
>> +            }
>> + 
>> +            txd = &cp->tx_ring[first_entry];
>> +@@ -858,27 +852,17 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +            txd->addr = cpu_to_le64(first_mapping);
>> +            wmb();
>> + 
>> +-           if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                   if (ip->protocol == IPPROTO_TCP)
>> +-                           txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                                    FirstFrag | DescOwn |
>> +-                                                    IPCS | TCPCS);
>> +-                   else if (ip->protocol == IPPROTO_UDP)
>> +-                           txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                                    FirstFrag | DescOwn |
>> +-                                                    IPCS | UDPCS);
>> +-                   else
>> +-                           BUG();
>> +-           } else
>> +-                   txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                            FirstFrag | DescOwn);
>> ++           ctrl = opts1 | first_eor | first_len | FirstFrag;
>> ++           txd->opts1 = cpu_to_le32(ctrl);
>> +            wmb();
>> ++
>> ++           cp->tx_opts[first_entry] = ctrl;
>> ++           netif_dbg(cp, tx_queued, cp->dev, "tx queued, slots %d-%d, 
>> skblen %d\n",
>> ++                     first_entry, entry, skb->len);
>> +    }
>> +-   cp->tx_head = entry;
>> ++   cp->tx_head = NEXT_TX(entry);
>> + 
>> +    netdev_sent_queue(dev, skb->len);
>> +-   netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
>> +-             entry, skb->len);
>> +    if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
>> +            netif_stop_queue(dev);
>> + 
>> +@@ -1115,6 +1099,7 @@ static int cp_init_rings (struct cp_private *cp)
>> + {
>> +    memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
>> +    cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
>> ++   memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
>> + 
>> +    cp_init_rings_index(cp);
>> + 
>> +@@ -1151,7 +1136,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> +                    desc = cp->rx_ring + i;
>> +                    dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
>> +                                     cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
>> +-                   dev_kfree_skb(cp->rx_skb[i]);
>> ++                   dev_kfree_skb_any(cp->rx_skb[i]);
>> +            }
>> +    }
>> + 
>> +@@ -1164,7 +1149,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> +                                     le32_to_cpu(desc->opts1) & 0xffff,
>> +                                     PCI_DMA_TODEVICE);
>> +                    if (le32_to_cpu(desc->opts1) & LastFrag)
>> +-                           dev_kfree_skb(skb);
>> ++                           dev_kfree_skb_any(skb);
>> +                    cp->dev->stats.tx_dropped++;
>> +            }
>> +    }
>> +@@ -1172,6 +1157,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> + 
>> +    memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
>> +    memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
>> ++   memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
>> + 
>> +    memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
>> +    memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
>> +@@ -1249,7 +1235,7 @@ static void cp_tx_timeout(struct net_device *dev)
>> + {
>> +    struct cp_private *cp = netdev_priv(dev);
>> +    unsigned long flags;
>> +-   int rc;
>> ++   int rc, i;
>> + 
>> +    netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
>> +                cpr8(Cmd), cpr16(CpCmd),
>> +@@ -1257,13 +1243,26 @@ static void cp_tx_timeout(struct net_device *dev)
>> + 
>> +    spin_lock_irqsave(&cp->lock, flags);
>> + 
>> ++   netif_dbg(cp, tx_err, cp->dev, "TX ring head %d tail %d desc %x\n",
>> ++             cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc));
>> ++   for (i = 0; i < CP_TX_RING_SIZE; i++) {
>> ++           netif_dbg(cp, tx_err, cp->dev,
>> ++                     "TX slot %d @%p: %08x (%08x) %08x %llx %p\n",
>> ++                     i, &cp->tx_ring[i], le32_to_cpu(cp->tx_ring[i].opts1),
>> ++                     cp->tx_opts[i], le32_to_cpu(cp->tx_ring[i].opts2),
>> ++                     le64_to_cpu(cp->tx_ring[i].addr),
>> ++                     cp->tx_skb[i]);
>> ++   }
>> ++
>> +    cp_stop_hw(cp);
>> +    cp_clean_rings(cp);
>> +    rc = cp_init_rings(cp);
>> +    cp_start_hw(cp);
>> +-   cp_enable_irq(cp);
>> ++   __cp_set_rx_mode(dev);
>> ++   cpw16_f(IntrMask, cp_norx_intr_mask);
>> + 
>> +    netif_wake_queue(dev);
>> ++   napi_schedule_irqoff(&cp->napi);
>> + 
>> +    spin_unlock_irqrestore(&cp->lock, flags);
>> + }
>> diff --git 
>> a/target/linux/generic/patches-4.0/761-8139cp-fixes-from-4.4.patch 
>> b/target/linux/generic/patches-4.0/761-8139cp-fixes-from-4.4.patch
>> new file mode 100644
>> index 0000000..cb605e5
>> --- /dev/null
>> +++ b/target/linux/generic/patches-4.0/761-8139cp-fixes-from-4.4.patch
>> @@ -0,0 +1,105 @@
>> +commit 8b7a7048220f86547db31de0abe1ea6dd2cfa892
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Thu Sep 24 11:38:22 2015 +0100
>> +
>> +    8139cp: Fix GSO MSS handling
>> +    
>> +    When fixing the TSO support I noticed we just mask ->gso_size with the
>> +    MSSMask value and don't care about the consequences.
>> +    
>> +    Provide a .ndo_features_check() method which drops the NETIF_F_TSO
>> +    feature for any skb which would exceed the maximum, and thus forces it
>> +    to be segmented by software.
>> +    
>> +    Then we can stop the masking in cp_start_xmit(), and just WARN if the
>> +    maximum is exceeded, which should now never happen.
>> +    
>> +    Finally, Francois Romieu noticed that we didn't even have the right
>> +    value for MSSMask anyway; it should be 0x7ff (11 bits) not 0xfff.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 5a58f227790faded5a3ef6075f3ddd65093e0f86
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:46:09 2015 +0100
>> +
>> +    8139cp: Enable offload features by default
>> +    
>> +    I fixed TSO. Hardware checksum and scatter/gather also appear to be
>> +    working correctly both on real hardware and in QEMU's emulation.
>> +    
>> +    Let's enable them by default and see if anyone screams...
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +diff --git a/drivers/net/ethernet/realtek/8139cp.c 
>> b/drivers/net/ethernet/realtek/8139cp.c
>> +index 686334f..deae10d 100644
>> +--- a/drivers/net/ethernet/realtek/8139cp.c
>> ++++ b/drivers/net/ethernet/realtek/8139cp.c
>> +@@ -175,7 +175,7 @@ enum {
>> +    LastFrag        = (1 << 28), /* Final segment of a packet */
>> +    LargeSend       = (1 << 27), /* TCP Large Send Offload (TSO) */
>> +    MSSShift        = 16,        /* MSS value position */
>> +-   MSSMask         = 0xfff,     /* MSS value: 11 bits */
>> ++   MSSMask         = 0x7ff,     /* MSS value: 11 bits */
>> +    TxError         = (1 << 23), /* Tx error summary */
>> +    RxError         = (1 << 20), /* Rx error summary */
>> +    IPCS            = (1 << 18), /* Calculate IP checksum */
>> +@@ -754,10 +754,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +    eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
>> +    mss = skb_shinfo(skb)->gso_size;
>> + 
>> ++   if (mss > MSSMask) {
>> ++           WARN_ONCE(1, "Net bug: GSO size %d too large for 8139CP\n",
>> ++                     mss);
>> ++           goto out_dma_error;
>> ++   }
>> ++
>> +    opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
>> +    opts1 = DescOwn;
>> +    if (mss)
>> +-           opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
>> ++           opts1 |= LargeSend | (mss << MSSShift);
>> +    else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +            const struct iphdr *ip = ip_hdr(skb);
>> +            if (ip->protocol == IPPROTO_TCP)
>> +@@ -1852,6 +1858,15 @@ static void cp_set_d3_state (struct cp_private *cp)
>> +    pci_set_power_state (cp->pdev, PCI_D3hot);
>> + }
>> + 
>> ++static netdev_features_t cp_features_check(struct sk_buff *skb,
>> ++                                      struct net_device *dev,
>> ++                                      netdev_features_t features)
>> ++{
>> ++   if (skb_shinfo(skb)->gso_size > MSSMask)
>> ++           features &= ~NETIF_F_TSO;
>> ++
>> ++   return vlan_features_check(skb, features);
>> ++}
>> + static const struct net_device_ops cp_netdev_ops = {
>> +    .ndo_open               = cp_open,
>> +    .ndo_stop               = cp_close,
>> +@@ -1864,6 +1879,7 @@ static const struct net_device_ops cp_netdev_ops = {
>> +    .ndo_tx_timeout         = cp_tx_timeout,
>> +    .ndo_set_features       = cp_set_features,
>> +    .ndo_change_mtu         = cp_change_mtu,
>> ++   .ndo_features_check     = cp_features_check,
>> + 
>> + #ifdef CONFIG_NET_POLL_CONTROLLER
>> +    .ndo_poll_controller    = cp_poll_controller,
>> +@@ -1983,12 +1999,12 @@ static int cp_init_one (struct pci_dev *pdev, const 
>> struct pci_device_id *ent)
>> +    dev->ethtool_ops = &cp_ethtool_ops;
>> +    dev->watchdog_timeo = TX_TIMEOUT;
>> + 
>> +-   dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
>> ++   dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
>> ++           NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
>> + 
>> +    if (pci_using_dac)
>> +            dev->features |= NETIF_F_HIGHDMA;
>> + 
>> +-   /* disabled by default until verified */
>> +    dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
>> +            NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
>> +    dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
>> diff --git 
>> a/target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch 
>> b/target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch
>> new file mode 100644
>> index 0000000..6cbcf2e
>> --- /dev/null
>> +++ b/target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch
>> @@ -0,0 +1,367 @@
>> +commit 41b976414c88016e2c9d9b2f6667ee67a998d388
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:45:31 2015 +0100
>> +
>> +    8139cp: Dump contents of descriptor ring on TX timeout
>> +    
>> +    We are seeing unexplained TX timeouts under heavy load. Let's try to get
>> +    a better idea of what's going on.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 7f4c685633e2df9ba10d49a31dda13715745db37
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:45:16 2015 +0100
>> +
>> +    8139cp: Fix DMA unmapping of transmitted buffers
>> +    
>> +    The low 16 bits of the 'opts1' field in the TX descriptor are supposed
>> +    to still contain the buffer length when the descriptor is handed back to
>> +    us. In practice, at least on my hardware, they don't. So stash the
>> +    original value of the opts1 field and get the length to unmap from
>> +    there.
>> +    
>> +    There are other ways we could have worked out the length, but I actually
>> +    want a stash of the opts1 field anyway so that I can dump it alongside
>> +    the contents of the descriptor ring when we suffer a TX timeout.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 0a5aeee0b79fa99d8e04c98dd4e87d4f52aa497b
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:57 2015 +0100
>> +
>> +    8139cp: Reduce duplicate csum/tso code in cp_start_xmit()
>> +    
>> +    We calculate the value of the opts1 descriptor field in three different
>> +    places. With two different behaviours when given an invalid packet to
>> +    be checksummed — none of them correct. Sort that out.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit a3b804043f490aeec57d8ca5baccdd35e6250857
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:38 2015 +0100
>> +
>> +    8139cp: Fix TSO/scatter-gather descriptor setup
>> +    
>> +    When sending a TSO frame in multiple buffers, we were neglecting to set
>> +    the first descriptor up in TSO mode.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 26b0bad6ac3a0167792dc4ffb276c29bc597d239
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:44:06 2015 +0100
>> +
>> +    8139cp: Fix tx_queued debug message to print correct slot numbers
>> +    
>> +    After a certain amount of staring at the debug output of this driver, I
>> +    realised it was lying to me.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit aaa0062ecf4877a26dea66bee1039c6eaf906c94
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:43:41 2015 +0100
>> +
>> +    8139cp: Do not re-enable RX interrupts in cp_tx_timeout()
>> +    
>> +    If an RX interrupt was already received but NAPI has not yet run when
>> +    the RX timeout happens, we end up in cp_tx_timeout() with RX interrupts
>> +    already disabled. Blindly re-enabling them will cause an IRQ storm.
>> +    
>> +    (This is made particularly horrid by the fact that cp_interrupt() always
>> +    returns that it's handled the interrupt, even when it hasn't actually
>> +    done anything. If it didn't do that, the core IRQ code would have
>> +    detected the storm and handled it, I'd have had a clear smoking gun
>> +    backtrace instead of just a spontaneously resetting router, and I'd have
>> +    at *least* two days of my life back. Changing the return value of
>> +    cp_interrupt() will be argued about under separate cover.)
>> +    
>> +    Unconditionally leave RX interrupts disabled after the reset, and
>> +    schedule NAPI to check the receive ring and re-enable them.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 7a8a8e75d505147358b225173e890ada43a267e2
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Fri Sep 18 00:21:54 2015 +0100
>> +
>> +    8139cp: Call __cp_set_rx_mode() from cp_tx_timeout()
>> +    
>> +    Unless we reset the RX config, on real hardware I don't seem to receive
>> +    any packets after a TX timeout.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit fc27bd115b334e3ebdc682a42a47c3aea2566dcc
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Fri Sep 18 00:19:08 2015 +0100
>> +
>> +    8139cp: Use dev_kfree_skb_any() instead of dev_kfree_skb() in 
>> cp_clean_rings()
>> +    
>> +    This can be called from cp_tx_timeout() with interrupts disabled.
>> +    Spotted by Francois Romieu <rom...@fr.zoreil.com>
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +diff --git a/drivers/net/ethernet/realtek/8139cp.c 
>> b/drivers/net/ethernet/realtek/8139cp.c
>> +index d79e33b..686334f 100644
>> +--- a/drivers/net/ethernet/realtek/8139cp.c
>> ++++ b/drivers/net/ethernet/realtek/8139cp.c
>> +@@ -157,6 +157,7 @@ enum {
>> +    NWayAdvert      = 0x66, /* MII ADVERTISE */
>> +    NWayLPAR        = 0x68, /* MII LPA */
>> +    NWayExpansion   = 0x6A, /* MII Expansion */
>> ++   TxDmaOkLowDesc  = 0x82, /* Low 16 bit address of a Tx descriptor. */
>> +    Config5         = 0xD8, /* Config5 */
>> +    TxPoll          = 0xD9, /* Tell chip to check Tx descriptors for work */
>> +    RxMaxSize       = 0xDA, /* Max size of an Rx packet (8169 only) */
>> +@@ -341,6 +342,7 @@ struct cp_private {
>> +    unsigned                tx_tail;
>> +    struct cp_desc          *tx_ring;
>> +    struct sk_buff          *tx_skb[CP_TX_RING_SIZE];
>> ++   u32                     tx_opts[CP_TX_RING_SIZE];
>> + 
>> +    unsigned                rx_buf_sz;
>> +    unsigned                wol_enabled : 1; /* Is Wake-on-LAN enabled? */
>> +@@ -665,7 +667,7 @@ static void cp_tx (struct cp_private *cp)
>> +            BUG_ON(!skb);
>> + 
>> +            dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
>> +-                            le32_to_cpu(txd->opts1) & 0xffff,
>> ++                            cp->tx_opts[tx_tail] & 0xffff,
>> +                             PCI_DMA_TODEVICE);
>> + 
>> +            if (status & LastFrag) {
>> +@@ -733,7 +735,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> + {
>> +    struct cp_private *cp = netdev_priv(dev);
>> +    unsigned entry;
>> +-   u32 eor, flags;
>> ++   u32 eor, opts1;
>> +    unsigned long intr_flags;
>> +    __le32 opts2;
>> +    int mss = 0;
>> +@@ -753,6 +755,21 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +    mss = skb_shinfo(skb)->gso_size;
>> + 
>> +    opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
>> ++   opts1 = DescOwn;
>> ++   if (mss)
>> ++           opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
>> ++   else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> ++           const struct iphdr *ip = ip_hdr(skb);
>> ++           if (ip->protocol == IPPROTO_TCP)
>> ++                   opts1 |= IPCS | TCPCS;
>> ++           else if (ip->protocol == IPPROTO_UDP)
>> ++                   opts1 |= IPCS | UDPCS;
>> ++           else {
>> ++                   WARN_ONCE(1,
>> ++                             "Net bug: asked to checksum invalid Legacy IP 
>> packet\n");
>> ++                   goto out_dma_error;
>> ++           }
>> ++   }
>> + 
>> +    if (skb_shinfo(skb)->nr_frags == 0) {
>> +            struct cp_desc *txd = &cp->tx_ring[entry];
>> +@@ -768,31 +785,20 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +            txd->addr = cpu_to_le64(mapping);
>> +            wmb();
>> + 
>> +-           flags = eor | len | DescOwn | FirstFrag | LastFrag;
>> +-
>> +-           if (mss)
>> +-                   flags |= LargeSend | ((mss & MSSMask) << MSSShift);
>> +-           else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                   const struct iphdr *ip = ip_hdr(skb);
>> +-                   if (ip->protocol == IPPROTO_TCP)
>> +-                           flags |= IPCS | TCPCS;
>> +-                   else if (ip->protocol == IPPROTO_UDP)
>> +-                           flags |= IPCS | UDPCS;
>> +-                   else
>> +-                           WARN_ON(1);     /* we need a WARN() */
>> +-           }
>> ++           opts1 |= eor | len | FirstFrag | LastFrag;
>> + 
>> +-           txd->opts1 = cpu_to_le32(flags);
>> ++           txd->opts1 = cpu_to_le32(opts1);
>> +            wmb();
>> + 
>> +            cp->tx_skb[entry] = skb;
>> +-           entry = NEXT_TX(entry);
>> ++           cp->tx_opts[entry] = opts1;
>> ++           netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen 
>> %d\n",
>> ++                     entry, skb->len);
>> +    } else {
>> +            struct cp_desc *txd;
>> +-           u32 first_len, first_eor;
>> ++           u32 first_len, first_eor, ctrl;
>> +            dma_addr_t first_mapping;
>> +            int frag, first_entry = entry;
>> +-           const struct iphdr *ip = ip_hdr(skb);
>> + 
>> +            /* We must give this initial chunk to the device last.
>> +             * Otherwise we could race with the device.
>> +@@ -805,14 +811,14 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +                    goto out_dma_error;
>> + 
>> +            cp->tx_skb[entry] = skb;
>> +-           entry = NEXT_TX(entry);
>> + 
>> +            for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
>> +                    const skb_frag_t *this_frag = 
>> &skb_shinfo(skb)->frags[frag];
>> +                    u32 len;
>> +-                   u32 ctrl;
>> +                    dma_addr_t mapping;
>> + 
>> ++                   entry = NEXT_TX(entry);
>> ++
>> +                    len = skb_frag_size(this_frag);
>> +                    mapping = dma_map_single(&cp->pdev->dev,
>> +                                             skb_frag_address(this_frag),
>> +@@ -824,19 +830,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> + 
>> +                    eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
>> + 
>> +-                   ctrl = eor | len | DescOwn;
>> +-
>> +-                   if (mss)
>> +-                           ctrl |= LargeSend |
>> +-                                   ((mss & MSSMask) << MSSShift);
>> +-                   else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                           if (ip->protocol == IPPROTO_TCP)
>> +-                                   ctrl |= IPCS | TCPCS;
>> +-                           else if (ip->protocol == IPPROTO_UDP)
>> +-                                   ctrl |= IPCS | UDPCS;
>> +-                           else
>> +-                                   BUG();
>> +-                   }
>> ++                   ctrl = opts1 | eor | len;
>> + 
>> +                    if (frag == skb_shinfo(skb)->nr_frags - 1)
>> +                            ctrl |= LastFrag;
>> +@@ -849,8 +843,8 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +                    txd->opts1 = cpu_to_le32(ctrl);
>> +                    wmb();
>> + 
>> ++                   cp->tx_opts[entry] = ctrl;
>> +                    cp->tx_skb[entry] = skb;
>> +-                   entry = NEXT_TX(entry);
>> +            }
>> + 
>> +            txd = &cp->tx_ring[first_entry];
>> +@@ -858,27 +852,17 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +            txd->addr = cpu_to_le64(first_mapping);
>> +            wmb();
>> + 
>> +-           if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +-                   if (ip->protocol == IPPROTO_TCP)
>> +-                           txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                                    FirstFrag | DescOwn |
>> +-                                                    IPCS | TCPCS);
>> +-                   else if (ip->protocol == IPPROTO_UDP)
>> +-                           txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                                    FirstFrag | DescOwn |
>> +-                                                    IPCS | UDPCS);
>> +-                   else
>> +-                           BUG();
>> +-           } else
>> +-                   txd->opts1 = cpu_to_le32(first_eor | first_len |
>> +-                                            FirstFrag | DescOwn);
>> ++           ctrl = opts1 | first_eor | first_len | FirstFrag;
>> ++           txd->opts1 = cpu_to_le32(ctrl);
>> +            wmb();
>> ++
>> ++           cp->tx_opts[first_entry] = ctrl;
>> ++           netif_dbg(cp, tx_queued, cp->dev, "tx queued, slots %d-%d, 
>> skblen %d\n",
>> ++                     first_entry, entry, skb->len);
>> +    }
>> +-   cp->tx_head = entry;
>> ++   cp->tx_head = NEXT_TX(entry);
>> + 
>> +    netdev_sent_queue(dev, skb->len);
>> +-   netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
>> +-             entry, skb->len);
>> +    if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
>> +            netif_stop_queue(dev);
>> + 
>> +@@ -1115,6 +1099,7 @@ static int cp_init_rings (struct cp_private *cp)
>> + {
>> +    memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
>> +    cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
>> ++   memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
>> + 
>> +    cp_init_rings_index(cp);
>> + 
>> +@@ -1151,7 +1136,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> +                    desc = cp->rx_ring + i;
>> +                    dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
>> +                                     cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
>> +-                   dev_kfree_skb(cp->rx_skb[i]);
>> ++                   dev_kfree_skb_any(cp->rx_skb[i]);
>> +            }
>> +    }
>> + 
>> +@@ -1164,7 +1149,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> +                                     le32_to_cpu(desc->opts1) & 0xffff,
>> +                                     PCI_DMA_TODEVICE);
>> +                    if (le32_to_cpu(desc->opts1) & LastFrag)
>> +-                           dev_kfree_skb(skb);
>> ++                           dev_kfree_skb_any(skb);
>> +                    cp->dev->stats.tx_dropped++;
>> +            }
>> +    }
>> +@@ -1172,6 +1157,7 @@ static void cp_clean_rings (struct cp_private *cp)
>> + 
>> +    memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
>> +    memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
>> ++   memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
>> + 
>> +    memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
>> +    memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
>> +@@ -1249,7 +1235,7 @@ static void cp_tx_timeout(struct net_device *dev)
>> + {
>> +    struct cp_private *cp = netdev_priv(dev);
>> +    unsigned long flags;
>> +-   int rc;
>> ++   int rc, i;
>> + 
>> +    netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
>> +                cpr8(Cmd), cpr16(CpCmd),
>> +@@ -1257,13 +1243,26 @@ static void cp_tx_timeout(struct net_device *dev)
>> + 
>> +    spin_lock_irqsave(&cp->lock, flags);
>> + 
>> ++   netif_dbg(cp, tx_err, cp->dev, "TX ring head %d tail %d desc %x\n",
>> ++             cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc));
>> ++   for (i = 0; i < CP_TX_RING_SIZE; i++) {
>> ++           netif_dbg(cp, tx_err, cp->dev,
>> ++                     "TX slot %d @%p: %08x (%08x) %08x %llx %p\n",
>> ++                     i, &cp->tx_ring[i], le32_to_cpu(cp->tx_ring[i].opts1),
>> ++                     cp->tx_opts[i], le32_to_cpu(cp->tx_ring[i].opts2),
>> ++                     le64_to_cpu(cp->tx_ring[i].addr),
>> ++                     cp->tx_skb[i]);
>> ++   }
>> ++
>> +    cp_stop_hw(cp);
>> +    cp_clean_rings(cp);
>> +    rc = cp_init_rings(cp);
>> +    cp_start_hw(cp);
>> +-   cp_enable_irq(cp);
>> ++   __cp_set_rx_mode(dev);
>> ++   cpw16_f(IntrMask, cp_norx_intr_mask);
>> + 
>> +    netif_wake_queue(dev);
>> ++   napi_schedule_irqoff(&cp->napi);
>> + 
>> +    spin_unlock_irqrestore(&cp->lock, flags);
>> + }
>> diff --git 
>> a/target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch 
>> b/target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch
>> new file mode 100644
>> index 0000000..cb605e5
>> --- /dev/null
>> +++ b/target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch
>> @@ -0,0 +1,105 @@
>> +commit 8b7a7048220f86547db31de0abe1ea6dd2cfa892
>> +Author: David Woodhouse <dw...@infradead.org>
>> +Date:   Thu Sep 24 11:38:22 2015 +0100
>> +
>> +    8139cp: Fix GSO MSS handling
>> +    
>> +    When fixing the TSO support I noticed we just mask ->gso_size with the
>> +    MSSMask value and don't care about the consequences.
>> +    
>> +    Provide a .ndo_features_check() method which drops the NETIF_F_TSO
>> +    feature for any skb which would exceed the maximum, and thus forces it
>> +    to be segmented by software.
>> +    
>> +    Then we can stop the masking in cp_start_xmit(), and just WARN if the
>> +    maximum is exceeded, which should now never happen.
>> +    
>> +    Finally, Francois Romieu noticed that we didn't even have the right
>> +    value for MSSMask anyway; it should be 0x7ff (11 bits) not 0xfff.
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +
>> +commit 5a58f227790faded5a3ef6075f3ddd65093e0f86
>> +Author: David Woodhouse <david.woodho...@intel.com>
>> +Date:   Wed Sep 23 09:46:09 2015 +0100
>> +
>> +    8139cp: Enable offload features by default
>> +    
>> +    I fixed TSO. Hardware checksum and scatter/gather also appear to be
>> +    working correctly both on real hardware and in QEMU's emulation.
>> +    
>> +    Let's enable them by default and see if anyone screams...
>> +    
>> +    Signed-off-by: David Woodhouse <david.woodho...@intel.com>
>> +    Signed-off-by: David S. Miller <da...@davemloft.net>
>> +diff --git a/drivers/net/ethernet/realtek/8139cp.c 
>> b/drivers/net/ethernet/realtek/8139cp.c
>> +index 686334f..deae10d 100644
>> +--- a/drivers/net/ethernet/realtek/8139cp.c
>> ++++ b/drivers/net/ethernet/realtek/8139cp.c
>> +@@ -175,7 +175,7 @@ enum {
>> +    LastFrag        = (1 << 28), /* Final segment of a packet */
>> +    LargeSend       = (1 << 27), /* TCP Large Send Offload (TSO) */
>> +    MSSShift        = 16,        /* MSS value position */
>> +-   MSSMask         = 0xfff,     /* MSS value: 11 bits */
>> ++   MSSMask         = 0x7ff,     /* MSS value: 11 bits */
>> +    TxError         = (1 << 23), /* Tx error summary */
>> +    RxError         = (1 << 20), /* Rx error summary */
>> +    IPCS            = (1 << 18), /* Calculate IP checksum */
>> +@@ -754,10 +754,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
>> +    eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
>> +    mss = skb_shinfo(skb)->gso_size;
>> + 
>> ++   if (mss > MSSMask) {
>> ++           WARN_ONCE(1, "Net bug: GSO size %d too large for 8139CP\n",
>> ++                     mss);
>> ++           goto out_dma_error;
>> ++   }
>> ++
>> +    opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
>> +    opts1 = DescOwn;
>> +    if (mss)
>> +-           opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
>> ++           opts1 |= LargeSend | (mss << MSSShift);
>> +    else if (skb->ip_summed == CHECKSUM_PARTIAL) {
>> +            const struct iphdr *ip = ip_hdr(skb);
>> +            if (ip->protocol == IPPROTO_TCP)
>> +@@ -1852,6 +1858,15 @@ static void cp_set_d3_state (struct cp_private *cp)
>> +    pci_set_power_state (cp->pdev, PCI_D3hot);
>> + }
>> + 
>> ++static netdev_features_t cp_features_check(struct sk_buff *skb,
>> ++                                      struct net_device *dev,
>> ++                                      netdev_features_t features)
>> ++{
>> ++   if (skb_shinfo(skb)->gso_size > MSSMask)
>> ++           features &= ~NETIF_F_TSO;
>> ++
>> ++   return vlan_features_check(skb, features);
>> ++}
>> + static const struct net_device_ops cp_netdev_ops = {
>> +    .ndo_open               = cp_open,
>> +    .ndo_stop               = cp_close,
>> +@@ -1864,6 +1879,7 @@ static const struct net_device_ops cp_netdev_ops = {
>> +    .ndo_tx_timeout         = cp_tx_timeout,
>> +    .ndo_set_features       = cp_set_features,
>> +    .ndo_change_mtu         = cp_change_mtu,
>> ++   .ndo_features_check     = cp_features_check,
>> + 
>> + #ifdef CONFIG_NET_POLL_CONTROLLER
>> +    .ndo_poll_controller    = cp_poll_controller,
>> +@@ -1983,12 +1999,12 @@ static int cp_init_one (struct pci_dev *pdev, const 
>> struct pci_device_id *ent)
>> +    dev->ethtool_ops = &cp_ethtool_ops;
>> +    dev->watchdog_timeo = TX_TIMEOUT;
>> + 
>> +-   dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
>> ++   dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
>> ++           NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
>> + 
>> +    if (pci_using_dac)
>> +            dev->features |= NETIF_F_HIGHDMA;
>> + 
>> +-   /* disabled by default until verified */
>> +    dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
>> +            NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
>> +    dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
>>
>>
>>
>> _______________________________________________
>> openwrt-devel mailing list
>> openwrt-devel@lists.openwrt.org
>> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
>>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
> 
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to