Merge tag 'linux-can-next-for-4.6-20160226' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Tue, 1 Mar 2016 20:18:58 +0000 (15:18 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Mar 2016 20:18:58 +0000 (15:18 -0500)
Marc Kleine-Budde says:

====================
pull-request: can-next 2016-02-26

this is a pull request of 3 patch for net-next/master.

There are two patches by Simon Horman, in which the device tree support
for the rcar_can driver is improved. One patch by me fixes the bad
coding style of the ems_usb driver which was introduced recently.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
48 files changed:
MAINTAINERS
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/e1000_hw.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/igbvf/vf.h
drivers/net/ethernet/rocker/rocker_ofdpa.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c
drivers/net/usb/lan78xx.c
drivers/net/usb/lan78xx.h
include/net/codel.h
include/net/l3mdev.h
include/net/sch_generic.h
net/ipv4/devinet.c
net/ipv4/gre_offload.c
net/ipv4/udp_offload.c
net/ipv6/udp_offload.c
net/l3mdev/l3mdev.c
net/sched/sch_api.c
net/sched/sch_cbq.c
net/sched/sch_choke.c
net/sched/sch_codel.c
net/sched/sch_drr.c
net/sched/sch_dsmark.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_hfsc.c
net/sched/sch_hhf.c
net/sched/sch_htb.c
net/sched/sch_multiq.c
net/sched/sch_netem.c
net/sched/sch_pie.c
net/sched/sch_prio.c
net/sched/sch_qfq.c
net/sched/sch_red.c
net/sched/sch_sfb.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c

index 27393cf..12b764f 100644 (file)
@@ -11332,6 +11332,13 @@ S:     Maintained
 F:     drivers/usb/host/isp116x*
 F:     include/linux/usb/isp116x.h
 
+USB LAN78XX ETHERNET DRIVER
+M:     Woojung Huh <woojung.huh@microchip.com>
+M:     Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/usb/lan78xx.*
+
 USB MASS STORAGE DRIVER
 M:     Matthew Dharm <mdharm-usb@one-eyed-alien.net>
 L:     linux-usb@vger.kernel.org
index c377607..7b881ed 100644 (file)
@@ -1602,7 +1602,7 @@ vortex_up(struct net_device *dev)
        }
 
        setup_timer(&vp->timer, vortex_timer, (unsigned long)dev);
-       vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+       mod_timer(&vp->timer, RUN_AT(media_tbl[dev->if_port].wait));
        setup_timer(&vp->rx_oom_timer, rx_oom_timer, (unsigned long)dev);
 
        if (vortex_debug > 1)
index b3949d5..4e733bf 100644 (file)
@@ -92,6 +92,10 @@ struct e1000_hw;
 #define E1000_DEV_ID_PCH_SPT_I219_LM2          0x15B7  /* SPT-H PCH */
 #define E1000_DEV_ID_PCH_SPT_I219_V2           0x15B8  /* SPT-H PCH */
 #define E1000_DEV_ID_PCH_LBG_I219_LM3          0x15B9  /* LBG PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_LM4          0x15D7
+#define E1000_DEV_ID_PCH_SPT_I219_V4           0x15D8
+#define E1000_DEV_ID_PCH_SPT_I219_LM5          0x15E3
+#define E1000_DEV_ID_PCH_SPT_I219_V5           0x15D6
 
 #define E1000_REVISION_4       4
 
index a049e30..c0f4887 100644 (file)
@@ -1252,9 +1252,9 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
                        ew32(H2ME, mac_reg);
                }
 
-               /* Poll up to 100msec for ME to clear ULP_CFG_DONE */
+               /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */
                while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
-                       if (i++ == 10) {
+                       if (i++ == 30) {
                                ret_val = -E1000_ERR_PHY;
                                goto out;
                        }
@@ -1328,6 +1328,8 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
                     I218_ULP_CONFIG1_RESET_TO_SMBUS |
                     I218_ULP_CONFIG1_WOL_HOST |
                     I218_ULP_CONFIG1_INBAND_EXIT |
+                    I218_ULP_CONFIG1_EN_ULP_LANPHYPC |
+                    I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST |
                     I218_ULP_CONFIG1_DISABLE_SMB_PERST);
        e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
 
@@ -1433,6 +1435,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                        emi_addr = I217_RX_CONFIG;
                ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
 
+               if (hw->mac.type == e1000_pch_lpt ||
+                   hw->mac.type == e1000_pch_spt) {
+                       u16 phy_reg;
+
+                       e1e_rphy_locked(hw, I217_PLL_CLOCK_GATE_REG, &phy_reg);
+                       phy_reg &= ~I217_PLL_CLOCK_GATE_MASK;
+                       if (speed == SPEED_100 || speed == SPEED_10)
+                               phy_reg |= 0x3E8;
+                       else
+                               phy_reg |= 0xFA;
+                       e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg);
+               }
                hw->phy.ops.release(hw);
 
                if (ret_val)
@@ -1467,6 +1481,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                                hw->phy.ops.release(hw);
                                if (ret_val)
                                        return ret_val;
+                       } else {
+                               ret_val = hw->phy.ops.acquire(hw);
+                               if (ret_val)
+                                       return ret_val;
+
+                               ret_val = e1e_wphy_locked(hw,
+                                                         PHY_REG(776, 20),
+                                                         0xC023);
+                               hw->phy.ops.release(hw);
+                               if (ret_val)
+                                       return ret_val;
+
                        }
                }
        }
index 34c551e..2311f60 100644 (file)
 #define I218_ULP_CONFIG1_INBAND_EXIT   0x0020  /* Inband on ULP exit */
 #define I218_ULP_CONFIG1_WOL_HOST      0x0040  /* WoL Host on ULP exit */
 #define I218_ULP_CONFIG1_RESET_TO_SMBUS        0x0100  /* Reset to SMBus mode */
+/* enable ULP even if when phy powered down via lanphypc */
+#define I218_ULP_CONFIG1_EN_ULP_LANPHYPC       0x0400
+/* disable clear of sticky ULP on PERST */
+#define I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST       0x0800
 #define I218_ULP_CONFIG1_DISABLE_SMB_PERST     0x1000  /* Disable on PERST# */
 
 /* SMBus Address Phy Register */
 #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
 #define HV_PM_CTRL_K1_ENABLE           0x4000
 
+#define I217_PLL_CLOCK_GATE_REG        PHY_REG(772, 28)
+#define I217_PLL_CLOCK_GATE_MASK       0x07FF
+
 #define SW_FLAG_TIMEOUT                1000    /* SW Semaphore flag timeout in ms */
 
 /* Inband Control */
index c71ba1b..9b4ec13 100644 (file)
@@ -7452,6 +7452,10 @@ static const struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM2), board_pch_spt },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V2), board_pch_spt },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LBG_I219_LM3), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM4), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V4), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM5), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V5), board_pch_spt },
 
        { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
 };
index 9a1a9c7..a23aa67 100644 (file)
@@ -2920,7 +2920,7 @@ static struct e1000_mac_operations e1000_mac_ops_82575 = {
 #endif
 };
 
-static struct e1000_phy_operations e1000_phy_ops_82575 = {
+static const struct e1000_phy_operations e1000_phy_ops_82575 = {
        .acquire              = igb_acquire_phy_82575,
        .get_cfg_done         = igb_get_cfg_done_82575,
        .release              = igb_release_phy_82575,
index 2154aea..de8805a 100644 (file)
@@ -56,10 +56,10 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr,
 #define E1000_SRRCTL_TIMESTAMP                          0x40000000
 
 
-#define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
+#define E1000_MRQC_ENABLE_RSS_MQ            0x00000002
 #define E1000_MRQC_ENABLE_VMDQ              0x00000003
 #define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
-#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005
+#define E1000_MRQC_ENABLE_VMDQ_RSS_MQ       0x00000005
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
 
index f0c416e..2fb2213 100644 (file)
@@ -372,7 +372,7 @@ struct e1000_thermal_sensor_data {
 struct e1000_info {
        s32 (*get_invariants)(struct e1000_hw *);
        struct e1000_mac_operations *mac_ops;
-       struct e1000_phy_operations *phy_ops;
+       const struct e1000_phy_operations *phy_ops;
        struct e1000_nvm_operations *nvm_ops;
 };
 
index 707ae5c..9413fa6 100644 (file)
@@ -510,6 +510,8 @@ enum igb_boards {
 extern char igb_driver_name[];
 extern char igb_driver_version[];
 
+int igb_open(struct net_device *netdev);
+int igb_close(struct net_device *netdev);
 int igb_up(struct igb_adapter *);
 void igb_down(struct igb_adapter *);
 void igb_reinit_locked(struct igb_adapter *);
index 1d329f1..7982243 100644 (file)
@@ -2017,7 +2017,7 @@ static void igb_diag_test(struct net_device *netdev,
 
                if (if_running)
                        /* indicate we're in test mode */
-                       dev_close(netdev);
+                       igb_close(netdev);
                else
                        igb_reset(adapter);
 
@@ -2050,7 +2050,7 @@ static void igb_diag_test(struct net_device *netdev,
 
                clear_bit(__IGB_TESTING, &adapter->state);
                if (if_running)
-                       dev_open(netdev);
+                       igb_open(netdev);
        } else {
                dev_info(&adapter->pdev->dev, "online testing starting\n");
 
index af46fcf..834b1b6 100644 (file)
@@ -122,8 +122,8 @@ static void igb_setup_mrqc(struct igb_adapter *);
 static int igb_probe(struct pci_dev *, const struct pci_device_id *);
 static void igb_remove(struct pci_dev *pdev);
 static int igb_sw_init(struct igb_adapter *);
-static int igb_open(struct net_device *);
-static int igb_close(struct net_device *);
+int igb_open(struct net_device *);
+int igb_close(struct net_device *);
 static void igb_configure(struct igb_adapter *);
 static void igb_configure_tx(struct igb_adapter *);
 static void igb_configure_rx(struct igb_adapter *);
@@ -2372,27 +2372,35 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * assignment.
         */
        netdev->features |= NETIF_F_SG |
-                           NETIF_F_IP_CSUM |
-                           NETIF_F_IPV6_CSUM |
                            NETIF_F_TSO |
                            NETIF_F_TSO6 |
                            NETIF_F_RXHASH |
                            NETIF_F_RXCSUM |
+                           NETIF_F_HW_CSUM |
                            NETIF_F_HW_VLAN_CTAG_RX |
                            NETIF_F_HW_VLAN_CTAG_TX;
 
+       if (hw->mac.type >= e1000_82576)
+               netdev->features |= NETIF_F_SCTP_CRC;
+
        /* copy netdev features into list of user selectable features */
        netdev->hw_features |= netdev->features;
        netdev->hw_features |= NETIF_F_RXALL;
 
+       if (hw->mac.type >= e1000_i350)
+               netdev->hw_features |= NETIF_F_NTUPLE;
+
        /* set this bit last since it cannot be part of hw_features */
        netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
-       netdev->vlan_features |= NETIF_F_TSO |
+       netdev->vlan_features |= NETIF_F_SG |
+                                NETIF_F_TSO |
                                 NETIF_F_TSO6 |
-                                NETIF_F_IP_CSUM |
-                                NETIF_F_IPV6_CSUM |
-                                NETIF_F_SG;
+                                NETIF_F_HW_CSUM |
+                                NETIF_F_SCTP_CRC;
+
+       netdev->mpls_features |= NETIF_F_HW_CSUM;
+       netdev->hw_enc_features |= NETIF_F_HW_CSUM;
 
        netdev->priv_flags |= IFF_SUPP_NOFCS;
 
@@ -2401,11 +2409,6 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                netdev->vlan_features |= NETIF_F_HIGHDMA;
        }
 
-       if (hw->mac.type >= e1000_82576) {
-               netdev->hw_features |= NETIF_F_SCTP_CRC;
-               netdev->features |= NETIF_F_SCTP_CRC;
-       }
-
        netdev->priv_flags |= IFF_UNICAST_FLT;
 
        adapter->en_mng_pt = igb_enable_mng_pass_thru(hw);
@@ -2538,6 +2541,26 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                adapter->wol = 0;
        }
 
+       /* Some vendors want the ability to Use the EEPROM setting as
+        * enable/disable only, and not for capability
+        */
+       if (((hw->mac.type == e1000_i350) ||
+            (hw->mac.type == e1000_i354)) &&
+           (pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)) {
+               adapter->flags |= IGB_FLAG_WOL_SUPPORTED;
+               adapter->wol = 0;
+       }
+       if (hw->mac.type == e1000_i350) {
+               if (((pdev->subsystem_device == 0x5001) ||
+                    (pdev->subsystem_device == 0x5002)) &&
+                               (hw->bus.func == 0)) {
+                       adapter->flags |= IGB_FLAG_WOL_SUPPORTED;
+                       adapter->wol = 0;
+               }
+               if (pdev->subsystem_device == 0x1F52)
+                       adapter->flags |= IGB_FLAG_WOL_SUPPORTED;
+       }
+
        device_set_wakeup_enable(&adapter->pdev->dev,
                                 adapter->flags & IGB_FLAG_WOL_SUPPORTED);
 
@@ -3149,7 +3172,7 @@ err_setup_tx:
        return err;
 }
 
-static int igb_open(struct net_device *netdev)
+int igb_open(struct net_device *netdev)
 {
        return __igb_open(netdev, false);
 }
@@ -3186,7 +3209,7 @@ static int __igb_close(struct net_device *netdev, bool suspending)
        return 0;
 }
 
-static int igb_close(struct net_device *netdev)
+int igb_close(struct net_device *netdev)
 {
        return __igb_close(netdev, false);
 }
@@ -3477,12 +3500,12 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
                        wr32(E1000_VT_CTL, vtctl);
                }
                if (adapter->rss_queues > 1)
-                       mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_2Q;
+                       mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_MQ;
                else
                        mrqc |= E1000_MRQC_ENABLE_VMDQ;
        } else {
                if (hw->mac.type != e1000_i211)
-                       mrqc |= E1000_MRQC_ENABLE_RSS_4Q;
+                       mrqc |= E1000_MRQC_ENABLE_RSS_MQ;
        }
        igb_vmm_control(adapter);
 
@@ -3566,6 +3589,28 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
        return 0;
 }
 
+static inline void igb_set_vf_vlan_strip(struct igb_adapter *adapter,
+                                        int vfn, bool enable)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 val, reg;
+
+       if (hw->mac.type < e1000_82576)
+               return;
+
+       if (hw->mac.type == e1000_i350)
+               reg = E1000_DVMOLR(vfn);
+       else
+               reg = E1000_VMOLR(vfn);
+
+       val = rd32(reg);
+       if (enable)
+               val |= E1000_VMOLR_STRVLAN;
+       else
+               val &= ~(E1000_VMOLR_STRVLAN);
+       wr32(reg, val);
+}
+
 static inline void igb_set_vmolr(struct igb_adapter *adapter,
                                 int vfn, bool aupe)
 {
@@ -3579,14 +3624,6 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter,
                return;
 
        vmolr = rd32(E1000_VMOLR(vfn));
-       vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
-       if (hw->mac.type == e1000_i350) {
-               u32 dvmolr;
-
-               dvmolr = rd32(E1000_DVMOLR(vfn));
-               dvmolr |= E1000_DVMOLR_STRVLAN;
-               wr32(E1000_DVMOLR(vfn), dvmolr);
-       }
        if (aupe)
                vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
        else
@@ -4357,6 +4394,7 @@ static void igb_watchdog_task(struct work_struct *work)
        u32 link;
        int i;
        u32 connsw;
+       u16 phy_data, retry_count = 20;
 
        link = igb_has_link(adapter);
 
@@ -4435,6 +4473,25 @@ static void igb_watchdog_task(struct work_struct *work)
                                break;
                        }
 
+                       if (adapter->link_speed != SPEED_1000)
+                               goto no_wait;
+
+                       /* wait for Remote receiver status OK */
+retry_read_status:
+                       if (!igb_read_phy_reg(hw, PHY_1000T_STATUS,
+                                             &phy_data)) {
+                               if (!(phy_data & SR_1000T_REMOTE_RX_STATUS) &&
+                                   retry_count) {
+                                       msleep(100);
+                                       retry_count--;
+                                       goto retry_read_status;
+                               } else if (!retry_count) {
+                                       dev_err(&adapter->pdev->dev, "exceed max 2 second\n");
+                               }
+                       } else {
+                               dev_err(&adapter->pdev->dev, "read 1000Base-T Status Reg\n");
+                       }
+no_wait:
                        netif_carrier_on(netdev);
 
                        igb_ping_all_vfs(adapter);
@@ -4843,70 +4900,57 @@ static int igb_tso(struct igb_ring *tx_ring,
        return 1;
 }
 
+static inline bool igb_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+       unsigned int offset = 0;
+
+       ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+       return offset == skb_checksum_start_offset(skb);
+}
+
 static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
 {
        struct sk_buff *skb = first->skb;
        u32 vlan_macip_lens = 0;
-       u32 mss_l4len_idx = 0;
        u32 type_tucmd = 0;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL) {
+csum_failed:
                if (!(first->tx_flags & IGB_TX_FLAGS_VLAN))
                        return;
-       } else {
-               u8 l4_hdr = 0;
-
-               switch (first->protocol) {
-               case htons(ETH_P_IP):
-                       vlan_macip_lens |= skb_network_header_len(skb);
-                       type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
-                       l4_hdr = ip_hdr(skb)->protocol;
-                       break;
-               case htons(ETH_P_IPV6):
-                       vlan_macip_lens |= skb_network_header_len(skb);
-                       l4_hdr = ipv6_hdr(skb)->nexthdr;
-                       break;
-               default:
-                       if (unlikely(net_ratelimit())) {
-                               dev_warn(tx_ring->dev,
-                                        "partial checksum but proto=%x!\n",
-                                        first->protocol);
-                       }
-                       break;
-               }
+               goto no_csum;
+       }
 
-               switch (l4_hdr) {
-               case IPPROTO_TCP:
-                       type_tucmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
-                       mss_l4len_idx = tcp_hdrlen(skb) <<
-                                       E1000_ADVTXD_L4LEN_SHIFT;
-                       break;
-               case IPPROTO_SCTP:
-                       type_tucmd |= E1000_ADVTXD_TUCMD_L4T_SCTP;
-                       mss_l4len_idx = sizeof(struct sctphdr) <<
-                                       E1000_ADVTXD_L4LEN_SHIFT;
-                       break;
-               case IPPROTO_UDP:
-                       mss_l4len_idx = sizeof(struct udphdr) <<
-                                       E1000_ADVTXD_L4LEN_SHIFT;
-                       break;
-               default:
-                       if (unlikely(net_ratelimit())) {
-                               dev_warn(tx_ring->dev,
-                                        "partial checksum but l4 proto=%x!\n",
-                                        l4_hdr);
-                       }
+       switch (skb->csum_offset) {
+       case offsetof(struct tcphdr, check):
+               type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
+               /* fall through */
+       case offsetof(struct udphdr, check):
+               break;
+       case offsetof(struct sctphdr, checksum):
+               /* validate that this is actually an SCTP request */
+               if (((first->protocol == htons(ETH_P_IP)) &&
+                    (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+                   ((first->protocol == htons(ETH_P_IPV6)) &&
+                    igb_ipv6_csum_is_sctp(skb))) {
+                       type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
                        break;
                }
-
-               /* update TX checksum flag */
-               first->tx_flags |= IGB_TX_FLAGS_CSUM;
+       default:
+               skb_checksum_help(skb);
+               goto csum_failed;
        }
 
+       /* update TX checksum flag */
+       first->tx_flags |= IGB_TX_FLAGS_CSUM;
+       vlan_macip_lens = skb_checksum_start_offset(skb) -
+                         skb_network_offset(skb);
+no_csum:
        vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
        vlan_macip_lens |= first->tx_flags & IGB_TX_FLAGS_VLAN_MASK;
 
-       igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, mss_l4len_idx);
+       igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
 }
 
 #define IGB_SET_FLAG(_input, _flag, _result) \
@@ -6069,6 +6113,7 @@ static int igb_enable_port_vlan(struct igb_adapter *adapter, int vf,
 
        adapter->vf_data[vf].pf_vlan = vlan;
        adapter->vf_data[vf].pf_qos = qos;
+       igb_set_vf_vlan_strip(adapter, vf, true);
        dev_info(&adapter->pdev->dev,
                 "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
        if (test_bit(__IGB_DOWN, &adapter->state)) {
@@ -6096,6 +6141,7 @@ static int igb_disable_port_vlan(struct igb_adapter *adapter, int vf)
 
        adapter->vf_data[vf].pf_vlan = 0;
        adapter->vf_data[vf].pf_qos = 0;
+       igb_set_vf_vlan_strip(adapter, vf, false);
 
        return 0;
 }
@@ -6116,6 +6162,7 @@ static int igb_set_vf_vlan_msg(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
 {
        int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
        int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
+       int ret;
 
        if (adapter->vf_data[vf].pf_vlan)
                return -1;
@@ -6124,7 +6171,10 @@ static int igb_set_vf_vlan_msg(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
        if (!vid && !add)
                return 0;
 
-       return igb_set_vf_vlan(adapter, vid, !!add, vf);
+       ret = igb_set_vf_vlan(adapter, vid, !!add, vf);
+       if (!ret)
+               igb_set_vf_vlan_strip(adapter, vf, !!vid);
+       return ret;
 }
 
 static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
@@ -6141,6 +6191,7 @@ static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
        igb_set_vmvir(adapter, vf_data->pf_vlan |
                               (vf_data->pf_qos << VLAN_PRIO_SHIFT), vf);
        igb_set_vmolr(adapter, vf, !vf_data->pf_vlan);
+       igb_set_vf_vlan_strip(adapter, vf, !!(vf_data->pf_vlan));
 
        /* reset multicast table array for vf */
        adapter->vf_data[vf].num_vf_mc_hashes = 0;
@@ -7293,6 +7344,8 @@ static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features)
                ctrl &= ~E1000_CTRL_VME;
                wr32(E1000_CTRL, ctrl);
        }
+
+       igb_set_vf_vlan_strip(adapter, adapter->vfs_allocated_count, enable);
 }
 
 static int igb_vlan_rx_add_vid(struct net_device *netdev,
index c44df87..22a8a29 100644 (file)
@@ -525,7 +525,8 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
                ts.tv_nsec = rq->perout.period.nsec;
                ns = timespec64_to_ns(&ts);
                ns = ns >> 1;
-               if (on && ns <= 70000000LL) {
+               if (on && ((ns <= 70000000LL) || (ns == 125000000LL) ||
+                          (ns == 250000000LL) || (ns == 500000000LL))) {
                        if (ns < 8LL)
                                return -EINVAL;
                        use_freq = 1;
index 297af80..c124422 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 #include <linux/prefetch.h>
+#include <linux/sctp.h>
 
 #include "igbvf.h"
 
@@ -876,7 +877,6 @@ static irqreturn_t igbvf_msix_other(int irq, void *data)
 
        adapter->int_counter1++;
 
-       netif_carrier_off(netdev);
        hw->mac.get_link_status = 1;
        if (!test_bit(__IGBVF_DOWN, &adapter->state))
                mod_timer(&adapter->watchdog_timer, jiffies + 1);
@@ -1908,6 +1908,31 @@ static void igbvf_watchdog_task(struct work_struct *work)
 #define IGBVF_TX_FLAGS_VLAN_MASK       0xffff0000
 #define IGBVF_TX_FLAGS_VLAN_SHIFT      16
 
+static void igbvf_tx_ctxtdesc(struct igbvf_ring *tx_ring, u32 vlan_macip_lens,
+                             u32 type_tucmd, u32 mss_l4len_idx)
+{
+       struct e1000_adv_tx_context_desc *context_desc;
+       struct igbvf_buffer *buffer_info;
+       u16 i = tx_ring->next_to_use;
+
+       context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
+       buffer_info = &tx_ring->buffer_info[i];
+
+       i++;
+       tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
+
+       /* set bits to identify this as an advanced context descriptor */
+       type_tucmd |= E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
+
+       context_desc->vlan_macip_lens   = cpu_to_le32(vlan_macip_lens);
+       context_desc->seqnum_seed       = 0;
+       context_desc->type_tucmd_mlhl   = cpu_to_le32(type_tucmd);
+       context_desc->mss_l4len_idx     = cpu_to_le32(mss_l4len_idx);
+
+       buffer_info->time_stamp = jiffies;
+       buffer_info->dma = 0;
+}
+
 static int igbvf_tso(struct igbvf_adapter *adapter,
                     struct igbvf_ring *tx_ring,
                     struct sk_buff *skb, u32 tx_flags, u8 *hdr_len,
@@ -1987,65 +2012,56 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
        return true;
 }
 
-static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
-                                struct igbvf_ring *tx_ring,
-                                struct sk_buff *skb, u32 tx_flags,
-                                __be16 protocol)
+static inline bool igbvf_ipv6_csum_is_sctp(struct sk_buff *skb)
 {
-       struct e1000_adv_tx_context_desc *context_desc;
-       unsigned int i;
-       struct igbvf_buffer *buffer_info;
-       u32 info = 0, tu_cmd = 0;
-
-       if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
-           (tx_flags & IGBVF_TX_FLAGS_VLAN)) {
-               i = tx_ring->next_to_use;
-               buffer_info = &tx_ring->buffer_info[i];
-               context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
+       unsigned int offset = 0;
 
-               if (tx_flags & IGBVF_TX_FLAGS_VLAN)
-                       info |= (tx_flags & IGBVF_TX_FLAGS_VLAN_MASK);
+       ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
 
-               info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
-               if (skb->ip_summed == CHECKSUM_PARTIAL)
-                       info |= (skb_transport_header(skb) -
-                                skb_network_header(skb));
+       return offset == skb_checksum_start_offset(skb);
+}
 
-               context_desc->vlan_macip_lens = cpu_to_le32(info);
+static bool igbvf_tx_csum(struct igbvf_ring *tx_ring, struct sk_buff *skb,
+                         u32 tx_flags, __be16 protocol)
+{
+       u32 vlan_macip_lens = 0;
+       u32 type_tucmd = 0;
 
-               tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
+csum_failed:
+               if (!(tx_flags & IGBVF_TX_FLAGS_VLAN))
+                       return false;
+               goto no_csum;
+       }
 
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       switch (protocol) {
-                       case htons(ETH_P_IP):
-                               tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
-                               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-                                       tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
-                               break;
-                       case htons(ETH_P_IPV6):
-                               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
-                                       tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
-                               break;
-                       default:
-                               break;
-                       }
+       switch (skb->csum_offset) {
+       case offsetof(struct tcphdr, check):
+               type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
+               /* fall through */
+       case offsetof(struct udphdr, check):
+               break;
+       case offsetof(struct sctphdr, checksum):
+               /* validate that this is actually an SCTP request */
+               if (((protocol == htons(ETH_P_IP)) &&
+                    (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+                   ((protocol == htons(ETH_P_IPV6)) &&
+                    igbvf_ipv6_csum_is_sctp(skb))) {
+                       type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
+                       break;
                }
-
-               context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
-               context_desc->seqnum_seed = 0;
-               context_desc->mss_l4len_idx = 0;
-
-               buffer_info->time_stamp = jiffies;
-               buffer_info->dma = 0;
-               i++;
-               if (i == tx_ring->count)
-                       i = 0;
-               tx_ring->next_to_use = i;
-
-               return true;
+       default:
+               skb_checksum_help(skb);
+               goto csum_failed;
        }
 
-       return false;
+       vlan_macip_lens = skb_checksum_start_offset(skb) -
+                         skb_network_offset(skb);
+no_csum:
+       vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
+       vlan_macip_lens |= tx_flags & IGBVF_TX_FLAGS_VLAN_MASK;
+
+       igbvf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
+       return true;
 }
 
 static int igbvf_maybe_stop_tx(struct net_device *netdev, int size)
@@ -2264,7 +2280,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
 
        if (tso)
                tx_flags |= IGBVF_TX_FLAGS_TSO;
-       else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags, protocol) &&
+       else if (igbvf_tx_csum(tx_ring, skb, tx_flags, protocol) &&
                 (skb->ip_summed == CHECKSUM_PARTIAL))
                tx_flags |= IGBVF_TX_FLAGS_CSUM;
 
@@ -2717,11 +2733,11 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->bd_number = cards_found++;
 
        netdev->hw_features = NETIF_F_SG |
-                          NETIF_F_IP_CSUM |
-                          NETIF_F_IPV6_CSUM |
-                          NETIF_F_TSO |
-                          NETIF_F_TSO6 |
-                          NETIF_F_RXCSUM;
+                             NETIF_F_TSO |
+                             NETIF_F_TSO6 |
+                             NETIF_F_RXCSUM |
+                             NETIF_F_HW_CSUM |
+                             NETIF_F_SCTP_CRC;
 
        netdev->features = netdev->hw_features |
                           NETIF_F_HW_VLAN_CTAG_TX |
@@ -2731,11 +2747,14 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
 
-       netdev->vlan_features |= NETIF_F_TSO;
-       netdev->vlan_features |= NETIF_F_TSO6;
-       netdev->vlan_features |= NETIF_F_IP_CSUM;
-       netdev->vlan_features |= NETIF_F_IPV6_CSUM;
-       netdev->vlan_features |= NETIF_F_SG;
+       netdev->vlan_features |= NETIF_F_SG |
+                                NETIF_F_TSO |
+                                NETIF_F_TSO6 |
+                                NETIF_F_HW_CSUM |
+                                NETIF_F_SCTP_CRC;
+
+       netdev->mpls_features |= NETIF_F_HW_CSUM;
+       netdev->hw_enc_features |= NETIF_F_HW_CSUM;
 
        /*reset the controller to put the device in a known good state */
        err = hw->mac.ops.reset_hw(hw);
index 0f1eca6..f00a41d 100644 (file)
@@ -126,6 +126,7 @@ struct e1000_adv_tx_context_desc {
 #define E1000_ADVTXD_MACLEN_SHIFT      9  /* Adv ctxt desc mac len shift */
 #define E1000_ADVTXD_TUCMD_IPV4                0x00000400 /* IP Packet Type: 1=IPv4 */
 #define E1000_ADVTXD_TUCMD_L4T_TCP     0x00000800 /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_TUCMD_L4T_SCTP    0x00001000 /* L4 packet TYPE of SCTP */
 #define E1000_ADVTXD_L4LEN_SHIFT       8  /* Adv ctxt L4LEN shift */
 #define E1000_ADVTXD_MSS_SHIFT         16 /* Adv ctxt MSS shift */
 
index 099008a..07218c3 100644 (file)
@@ -1449,7 +1449,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port,
        if (!n) {
                n = neigh_create(&arp_tbl, &ip_addr, dev);
                if (IS_ERR(n))
-                       return IS_ERR(n);
+                       return PTR_ERR(n);
        }
 
        /* If the neigh is already resolved, then go ahead and
index fcb92c0..b4c6878 100644 (file)
@@ -658,6 +658,10 @@ struct net_device_context {
 
        struct netvsc_stats __percpu *tx_stats;
        struct netvsc_stats __percpu *rx_stats;
+
+       /* Ethtool settings */
+       u8 duplex;
+       u32 speed;
 };
 
 /* Per netvsc device */
index 2b6595e..0860849 100644 (file)
@@ -799,6 +799,58 @@ static int netvsc_set_channels(struct net_device *net,
        goto do_set;
 }
 
+static bool netvsc_validate_ethtool_ss_cmd(const struct ethtool_cmd *cmd)
+{
+       struct ethtool_cmd diff1 = *cmd;
+       struct ethtool_cmd diff2 = {};
+
+       ethtool_cmd_speed_set(&diff1, 0);
+       diff1.duplex = 0;
+       /* advertising and cmd are usually set */
+       diff1.advertising = 0;
+       diff1.cmd = 0;
+       /* We set port to PORT_OTHER */
+       diff2.port = PORT_OTHER;
+
+       return !memcmp(&diff1, &diff2, sizeof(diff1));
+}
+
+static void netvsc_init_settings(struct net_device *dev)
+{
+       struct net_device_context *ndc = netdev_priv(dev);
+
+       ndc->speed = SPEED_UNKNOWN;
+       ndc->duplex = DUPLEX_UNKNOWN;
+}
+
+static int netvsc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct net_device_context *ndc = netdev_priv(dev);
+
+       ethtool_cmd_speed_set(cmd, ndc->speed);
+       cmd->duplex = ndc->duplex;
+       cmd->port = PORT_OTHER;
+
+       return 0;
+}
+
+static int netvsc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct net_device_context *ndc = netdev_priv(dev);
+       u32 speed;
+
+       speed = ethtool_cmd_speed(cmd);
+       if (!ethtool_validate_speed(speed) ||
+           !ethtool_validate_duplex(cmd->duplex) ||
+           !netvsc_validate_ethtool_ss_cmd(cmd))
+               return -EINVAL;
+
+       ndc->speed = speed;
+       ndc->duplex = cmd->duplex;
+
+       return 0;
+}
+
 static int netvsc_change_mtu(struct net_device *ndev, int mtu)
 {
        struct net_device_context *ndevctx = netdev_priv(ndev);
@@ -923,6 +975,8 @@ static const struct ethtool_ops ethtool_ops = {
        .get_channels   = netvsc_get_channels,
        .set_channels   = netvsc_set_channels,
        .get_ts_info    = ethtool_op_get_ts_info,
+       .get_settings   = netvsc_get_settings,
+       .set_settings   = netvsc_set_settings,
 };
 
 static const struct net_device_ops device_ops = {
@@ -1115,6 +1169,8 @@ static int netvsc_probe(struct hv_device *dev,
        netif_set_real_num_tx_queues(net, nvdev->num_chn);
        netif_set_real_num_rx_queues(net, nvdev->num_chn);
 
+       netvsc_init_settings(net);
+
        ret = register_netdev(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
index 1c299b8..705c180 100644 (file)
@@ -36,7 +36,7 @@
 #define DRIVER_AUTHOR  "WOOJUNG HUH <woojung.huh@microchip.com>"
 #define DRIVER_DESC    "LAN78XX USB 3.0 Gigabit Ethernet Devices"
 #define DRIVER_NAME    "lan78xx"
-#define DRIVER_VERSION "1.0.2"
+#define DRIVER_VERSION "1.0.3"
 
 #define TX_TIMEOUT_JIFFIES             (5 * HZ)
 #define THROTTLE_JIFFIES               (HZ / 8)
@@ -278,8 +278,12 @@ struct lan78xx_net {
        int                     link_on;
        u8                      mdix_ctrl;
 
-       u32                     devid;
+       u32                     chipid;
+       u32                     chiprev;
        struct mii_bus          *mdiobus;
+
+       int                     fc_autoneg;
+       u8                      fc_request_control;
 };
 
 /* use ethtool to change the level for any given device */
@@ -471,7 +475,7 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset,
         */
        ret = lan78xx_read_reg(dev, HW_CFG, &val);
        saved = val;
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) {
+       if (dev->chipid == ID_REV_CHIP_ID_7800_) {
                val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_);
                ret = lan78xx_write_reg(dev, HW_CFG, val);
        }
@@ -505,7 +509,7 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset,
 
        retval = 0;
 exit:
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000)
+       if (dev->chipid == ID_REV_CHIP_ID_7800_)
                ret = lan78xx_write_reg(dev, HW_CFG, saved);
 
        return retval;
@@ -539,7 +543,7 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset,
         */
        ret = lan78xx_read_reg(dev, HW_CFG, &val);
        saved = val;
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) {
+       if (dev->chipid == ID_REV_CHIP_ID_7800_) {
                val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_);
                ret = lan78xx_write_reg(dev, HW_CFG, val);
        }
@@ -587,7 +591,7 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset,
 
        retval = 0;
 exit:
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000)
+       if (dev->chipid == ID_REV_CHIP_ID_7800_)
                ret = lan78xx_write_reg(dev, HW_CFG, saved);
 
        return retval;
@@ -901,11 +905,15 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
 {
        u32 flow = 0, fct_flow = 0;
        int ret;
+       u8 cap;
 
-       u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+       if (dev->fc_autoneg)
+               cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+       else
+               cap = dev->fc_request_control;
 
        if (cap & FLOW_CTRL_TX)
-               flow = (FLOW_CR_TX_FCEN_ | 0xFFFF);
+               flow |= (FLOW_CR_TX_FCEN_ | 0xFFFF);
 
        if (cap & FLOW_CTRL_RX)
                flow |= FLOW_CR_RX_FCEN_;
@@ -1385,6 +1393,62 @@ static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
        return ret;
 }
 
+static void lan78xx_get_pause(struct net_device *net,
+                             struct ethtool_pauseparam *pause)
+{
+       struct lan78xx_net *dev = netdev_priv(net);
+       struct phy_device *phydev = net->phydev;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+
+       phy_ethtool_gset(phydev, &ecmd);
+
+       pause->autoneg = dev->fc_autoneg;
+
+       if (dev->fc_request_control & FLOW_CTRL_TX)
+               pause->tx_pause = 1;
+
+       if (dev->fc_request_control & FLOW_CTRL_RX)
+               pause->rx_pause = 1;
+}
+
+static int lan78xx_set_pause(struct net_device *net,
+                            struct ethtool_pauseparam *pause)
+{
+       struct lan78xx_net *dev = netdev_priv(net);
+       struct phy_device *phydev = net->phydev;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+       int ret;
+
+       phy_ethtool_gset(phydev, &ecmd);
+
+       if (pause->autoneg && !ecmd.autoneg) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       dev->fc_request_control = 0;
+       if (pause->rx_pause)
+               dev->fc_request_control |= FLOW_CTRL_RX;
+
+       if (pause->tx_pause)
+               dev->fc_request_control |= FLOW_CTRL_TX;
+
+       if (ecmd.autoneg) {
+               u32 mii_adv;
+
+               ecmd.advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+               mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
+               ecmd.advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+               phy_ethtool_sset(phydev, &ecmd);
+       }
+
+       dev->fc_autoneg = pause->autoneg;
+
+       ret = 0;
+exit:
+       return ret;
+}
+
 static const struct ethtool_ops lan78xx_ethtool_ops = {
        .get_link       = lan78xx_get_link,
        .nway_reset     = lan78xx_nway_reset,
@@ -1403,6 +1467,8 @@ static const struct ethtool_ops lan78xx_ethtool_ops = {
        .set_wol        = lan78xx_set_wol,
        .get_eee        = lan78xx_get_eee,
        .set_eee        = lan78xx_set_eee,
+       .get_pauseparam = lan78xx_get_pause,
+       .set_pauseparam = lan78xx_set_pause,
 };
 
 static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -1555,9 +1621,9 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
        snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
                 dev->udev->bus->busnum, dev->udev->devnum);
 
-       switch (dev->devid & ID_REV_CHIP_ID_MASK_) {
-       case 0x78000000:
-       case 0x78500000:
+       switch (dev->chipid) {
+       case ID_REV_CHIP_ID_7800_:
+       case ID_REV_CHIP_ID_7850_:
                /* set to internal PHY id */
                dev->mdiobus->phy_mask = ~(1 << 1);
                break;
@@ -1590,6 +1656,7 @@ static void lan78xx_link_status_change(struct net_device *net)
 static int lan78xx_phy_init(struct lan78xx_net *dev)
 {
        int ret;
+       u32 mii_adv;
        struct phy_device *phydev = dev->net->phydev;
 
        phydev = phy_find_first(dev->mdiobus);
@@ -1622,14 +1689,17 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
 
        /* MAC doesn't support 1000T Half */
        phydev->supported &= ~SUPPORTED_1000baseT_Half;
-       phydev->supported |= (SUPPORTED_10baseT_Half |
-                             SUPPORTED_10baseT_Full |
-                             SUPPORTED_100baseT_Half |
-                             SUPPORTED_100baseT_Full |
-                             SUPPORTED_1000baseT_Full |
-                             SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+
+       /* support both flow controls */
+       dev->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
+       phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+       mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
+       phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+
        genphy_config_aneg(phydev);
 
+       dev->fc_autoneg = phydev->autoneg;
+
        phy_start(phydev);
 
        netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
@@ -1918,7 +1988,8 @@ static int lan78xx_reset(struct lan78xx_net *dev)
 
        /* save DEVID for later usage */
        ret = lan78xx_read_reg(dev, ID_REV, &buf);
-       dev->devid = buf;
+       dev->chipid = (buf & ID_REV_CHIP_ID_MASK_) >> 16;
+       dev->chiprev = buf & ID_REV_CHIP_REV_MASK_;
 
        /* Respond to the IN token with a NAK */
        ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
index a93fb65..4092790 100644 (file)
 #define ID_REV_CHIP_ID_MASK_           (0xFFFF0000)
 #define ID_REV_CHIP_REV_MASK_          (0x0000FFFF)
 #define ID_REV_CHIP_ID_7800_           (0x7800)
+#define ID_REV_CHIP_ID_7850_           (0x7850)
 
 #define FPGA_REV                       (0x04)
 #define FPGA_REV_MINOR_MASK_           (0x0000FF00)
index 267e702..d168aca 100644 (file)
@@ -162,12 +162,14 @@ struct codel_vars {
  * struct codel_stats - contains codel shared variables and stats
  * @maxpacket: largest packet we've seen so far
  * @drop_count:        temp count of dropped packets in dequeue()
+ * @drop_len:  bytes of dropped packets in dequeue()
  * ecn_mark:   number of packets we ECN marked instead of dropping
  * ce_mark:    number of packets CE marked because sojourn time was above ce_threshold
  */
 struct codel_stats {
        u32             maxpacket;
        u32             drop_count;
+       u32             drop_len;
        u32             ecn_mark;
        u32             ce_mark;
 };
@@ -308,6 +310,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                                                                  vars->rec_inv_sqrt);
                                        goto end;
                                }
+                               stats->drop_len += qdisc_pkt_len(skb);
                                qdisc_drop(skb, sch);
                                stats->drop_count++;
                                skb = dequeue_func(vars, sch);
@@ -330,6 +333,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                if (params->ecn && INET_ECN_set_ce(skb)) {
                        stats->ecn_mark++;
                } else {
+                       stats->drop_len += qdisc_pkt_len(skb);
                        qdisc_drop(skb, sch);
                        stats->drop_count++;
 
index 5567d46..c43a9c7 100644 (file)
@@ -39,7 +39,7 @@ struct l3mdev_ops {
 
 #ifdef CONFIG_NET_L3_MASTER_DEV
 
-int l3mdev_master_ifindex_rcu(struct net_device *dev);
+int l3mdev_master_ifindex_rcu(const struct net_device *dev);
 static inline int l3mdev_master_ifindex(struct net_device *dev)
 {
        int ifindex;
@@ -179,7 +179,7 @@ struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net,
 
 #else
 
-static inline int l3mdev_master_ifindex_rcu(struct net_device *dev)
+static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
 {
        return 0;
 }
index 636a362..e5bba89 100644 (file)
@@ -396,7 +396,8 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
                              struct Qdisc *qdisc);
 void qdisc_reset(struct Qdisc *qdisc);
 void qdisc_destroy(struct Qdisc *qdisc);
-void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
+void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n,
+                              unsigned int len);
 struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
                          const struct Qdisc_ops *ops);
 struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
@@ -707,6 +708,23 @@ static inline void qdisc_reset_queue(struct Qdisc *sch)
        sch->qstats.backlog = 0;
 }
 
+static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
+                                         struct Qdisc **pold)
+{
+       struct Qdisc *old;
+
+       sch_tree_lock(sch);
+       old = *pold;
+       *pold = new;
+       if (old != NULL) {
+               qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
+               qdisc_reset(old);
+       }
+       sch_tree_unlock(sch);
+
+       return old;
+}
+
 static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
                                              struct sk_buff_head *list)
 {
index 29b8d3a..8c3df2c 100644 (file)
@@ -1194,6 +1194,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
        __be32 addr = 0;
        struct in_device *in_dev;
        struct net *net = dev_net(dev);
+       int master_idx;
 
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(dev);
@@ -1214,12 +1215,33 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
        if (addr)
                goto out_unlock;
 no_in_dev:
+       master_idx = l3mdev_master_ifindex_rcu(dev);
+
+       /* For VRFs, the VRF device takes the place of the loopback device,
+        * with addresses on it being preferred.  Note in such cases the
+        * loopback device will be among the devices that fail the master_idx
+        * equality check in the loop below.
+        */
+       if (master_idx &&
+           (dev = dev_get_by_index_rcu(net, master_idx)) &&
+           (in_dev = __in_dev_get_rcu(dev))) {
+               for_primary_ifa(in_dev) {
+                       if (ifa->ifa_scope != RT_SCOPE_LINK &&
+                           ifa->ifa_scope <= scope) {
+                               addr = ifa->ifa_local;
+                               goto out_unlock;
+                       }
+               } endfor_ifa(in_dev);
+       }
 
        /* Not loopback addresses on loopback should be preferred
           in this case. It is important that lo is the first interface
           in dev_base list.
         */
        for_each_netdev_rcu(net, dev) {
+               if (l3mdev_master_ifindex_rcu(dev) != master_idx)
+                       continue;
+
                in_dev = __in_dev_get_rcu(dev);
                if (!in_dev)
                        continue;
index 003b0eb..47f4c54 100644 (file)
@@ -24,7 +24,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
        __be16 protocol = skb->protocol;
        u16 mac_len = skb->mac_len;
        int gre_offset, outer_hlen;
-       bool need_csum;
+       bool need_csum, ufo;
 
        if (unlikely(skb_shinfo(skb)->gso_type &
                                ~(SKB_GSO_TCPV4 |
@@ -58,8 +58,20 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
        need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM);
        skb->encap_hdr_csum = need_csum;
 
+       ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
+
        features &= skb->dev->hw_enc_features;
 
+       /* The only checksum offload we care about from here on out is the
+        * outer one so strip the existing checksum feature flags based
+        * on the fact that we will be computing our checksum in software.
+        */
+       if (ufo) {
+               features &= ~NETIF_F_CSUM_MASK;
+               if (!need_csum)
+                       features |= NETIF_F_HW_CSUM;
+       }
+
        /* segment inner packet. */
        segs = skb_mac_gso_segment(skb, features);
        if (IS_ERR_OR_NULL(segs)) {
@@ -75,8 +87,11 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
                struct gre_base_hdr *greh;
                __be32 *pcsum;
 
-               skb_reset_inner_headers(skb);
-               skb->encapsulation = 1;
+               /* Set up inner headers if we are offloading inner checksum */
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       skb_reset_inner_headers(skb);
+                       skb->encapsulation = 1;
+               }
 
                skb->mac_len = mac_len;
                skb->protocol = protocol;
index 56c4c8b..f5abb1a 100644 (file)
@@ -33,8 +33,8 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        __be16 new_protocol, bool is_ipv6)
 {
        int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+       bool remcsum, need_csum, offload_csum, ufo;
        struct sk_buff *segs = ERR_PTR(-EINVAL);
-       bool remcsum, need_csum, offload_csum;
        struct udphdr *uh = udp_hdr(skb);
        u16 mac_offset = skb->mac_header;
        __be16 protocol = skb->protocol;
@@ -62,6 +62,8 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        remcsum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM);
        skb->remcsum_offload = remcsum;
 
+       ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
+
        /* Try to offload checksum if possible */
        offload_csum = !!(need_csum &&
                          (skb->dev->features &
@@ -74,9 +76,9 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
         * outer one so strip the existing checksum feature flags and
         * instead set the flag based on our outer checksum offload value.
         */
-       if (remcsum) {
+       if (remcsum || ufo) {
                features &= ~NETIF_F_CSUM_MASK;
-               if (offload_csum)
+               if (!need_csum || offload_csum)
                        features |= NETIF_F_HW_CSUM;
        }
 
@@ -230,6 +232,13 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
 
        skb->ip_summed = CHECKSUM_NONE;
 
+       /* If there is no outer header we can fake a checksum offload
+        * due to the fact that we have already done the checksum in
+        * software prior to segmenting the frame.
+        */
+       if (!skb->encap_hdr_csum)
+               features |= NETIF_F_HW_CSUM;
+
        /* Fragment the skb. IP headers of the fragments are updated in
         * inet_gso_segment()
         */
index 7441e1e..2b0fbe6 100644 (file)
@@ -81,12 +81,18 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                csum = skb_checksum(skb, 0, skb->len, 0);
                uh->check = udp_v6_check(skb->len, &ipv6h->saddr,
                                          &ipv6h->daddr, csum);
-
                if (uh->check == 0)
                        uh->check = CSUM_MANGLED_0;
 
                skb->ip_summed = CHECKSUM_NONE;
 
+               /* If there is no outer header we can fake a checksum offload
+                * due to the fact that we have already done the checksum in
+                * software prior to segmenting the frame.
+                */
+               if (!skb->encap_hdr_csum)
+                       features |= NETIF_F_HW_CSUM;
+
                /* Check if there is enough headroom to insert fragment header. */
                tnl_hlen = skb_tnl_header_len(skb);
                if (skb->mac_header < (tnl_hlen + frag_hdr_sz)) {
index 8e5ead3..e925037 100644 (file)
@@ -17,7 +17,7 @@
  *     @dev: targeted interface
  */
 
-int l3mdev_master_ifindex_rcu(struct net_device *dev)
+int l3mdev_master_ifindex_rcu(const struct net_device *dev)
 {
        int ifindex = 0;
 
@@ -28,8 +28,15 @@ int l3mdev_master_ifindex_rcu(struct net_device *dev)
                ifindex = dev->ifindex;
        } else if (netif_is_l3_slave(dev)) {
                struct net_device *master;
+               struct net_device *_dev = (struct net_device *)dev;
 
-               master = netdev_master_upper_dev_get_rcu(dev);
+               /* netdev_master_upper_dev_get_rcu calls
+                * list_first_or_null_rcu to walk the upper dev list.
+                * list_first_or_null_rcu does not handle a const arg. We aren't
+                * making changes, just want the master device from that list so
+                * typecast to remove the const
+                */
+               master = netdev_master_upper_dev_get_rcu(_dev);
                if (master)
                        ifindex = master->ifindex;
        }
index de1e176..3b180ff 100644 (file)
@@ -744,14 +744,15 @@ static u32 qdisc_alloc_handle(struct net_device *dev)
        return 0;
 }
 
-void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
+void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
+                              unsigned int len)
 {
        const struct Qdisc_class_ops *cops;
        unsigned long cl;
        u32 parentid;
        int drops;
 
-       if (n == 0)
+       if (n == 0 && len == 0)
                return;
        drops = max_t(int, n, 0);
        rcu_read_lock();
@@ -774,11 +775,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
                        cops->put(sch, cl);
                }
                sch->q.qlen -= n;
+               sch->qstats.backlog -= len;
                __qdisc_qstats_drop(sch, drops);
        }
        rcu_read_unlock();
 }
-EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
+EXPORT_SYMBOL(qdisc_tree_reduce_backlog);
 
 static void notify_and_destroy(struct net *net, struct sk_buff *skb,
                               struct nlmsghdr *n, u32 clid,
index c538d9e..baafddf 100644 (file)
@@ -1624,13 +1624,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                        new->reshape_fail = cbq_reshape_fail;
 #endif
        }
-       sch_tree_lock(sch);
-       *old = cl->q;
-       cl->q = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
 
+       *old = qdisc_replace(sch, new, &cl->q);
        return 0;
 }
 
@@ -1914,7 +1909,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
 {
        struct cbq_sched_data *q = qdisc_priv(sch);
        struct cbq_class *cl = (struct cbq_class *)arg;
-       unsigned int qlen;
+       unsigned int qlen, backlog;
 
        if (cl->filters || cl->children || cl == &q->link)
                return -EBUSY;
@@ -1922,8 +1917,9 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
        sch_tree_lock(sch);
 
        qlen = cl->q->q.qlen;
+       backlog = cl->q->qstats.backlog;
        qdisc_reset(cl->q);
-       qdisc_tree_decrease_qlen(cl->q, qlen);
+       qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
 
        if (cl->next_alive)
                cbq_deactivate_class(cl);
index 5ffb8b8..0a08c86 100644 (file)
@@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx)
                choke_zap_tail_holes(q);
 
        qdisc_qstats_backlog_dec(sch, skb);
+       qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
        qdisc_drop(skb, sch);
-       qdisc_tree_decrease_qlen(sch, 1);
        --sch->q.qlen;
 }
 
@@ -456,6 +456,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
                old = q->tab;
                if (old) {
                        unsigned int oqlen = sch->q.qlen, tail = 0;
+                       unsigned dropped = 0;
 
                        while (q->head != q->tail) {
                                struct sk_buff *skb = q->tab[q->head];
@@ -467,11 +468,12 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
                                        ntab[tail++] = skb;
                                        continue;
                                }
+                               dropped += qdisc_pkt_len(skb);
                                qdisc_qstats_backlog_dec(sch, skb);
                                --sch->q.qlen;
                                qdisc_drop(skb, sch);
                        }
-                       qdisc_tree_decrease_qlen(sch, oqlen - sch->q.qlen);
+                       qdisc_tree_reduce_backlog(sch, oqlen - sch->q.qlen, dropped);
                        q->head = 0;
                        q->tail = tail;
                }
index 535007d..9b7e298 100644 (file)
@@ -79,12 +79,13 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
 
        skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue);
 
-       /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+       /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
         * or HTB crashes. Defer it for next round.
         */
        if (q->stats.drop_count && sch->q.qlen) {
-               qdisc_tree_decrease_qlen(sch, q->stats.drop_count);
+               qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
                q->stats.drop_count = 0;
+               q->stats.drop_len = 0;
        }
        if (skb)
                qdisc_bstats_update(sch, skb);
@@ -116,7 +117,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct codel_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_CODEL_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        int err;
 
        if (!opt)
@@ -156,10 +157,11 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
+               dropped += qdisc_pkt_len(skb);
                qdisc_qstats_backlog_dec(sch, skb);
                qdisc_drop(skb, sch);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        sch_tree_unlock(sch);
        return 0;
index a1cd778..a63e879 100644 (file)
@@ -53,9 +53,10 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
 static void drr_purge_queue(struct drr_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
@@ -226,11 +227,7 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       drr_purge_queue(cl);
-       *old = cl->qdisc;
-       cl->qdisc = new;
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->qdisc);
        return 0;
 }
 
index f357f34..d0dff0c 100644 (file)
@@ -73,13 +73,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       *old = p->q;
-       p->q = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &p->q);
        return 0;
 }
 
@@ -264,6 +258,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
        }
 
+       qdisc_qstats_backlog_inc(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
@@ -286,6 +281,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
                return NULL;
 
        qdisc_bstats_update(sch, skb);
+       qdisc_qstats_backlog_dec(sch, skb);
        sch->q.qlen--;
 
        index = skb->tc_index & (p->indices - 1);
@@ -401,6 +397,7 @@ static void dsmark_reset(struct Qdisc *sch)
 
        pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
        qdisc_reset(p->q);
+       sch->qstats.backlog = 0;
        sch->q.qlen = 0;
 }
 
index 109b232..3c6a47d 100644 (file)
@@ -662,6 +662,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
        struct fq_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_FQ_MAX + 1];
        int err, drop_count = 0;
+       unsigned drop_len = 0;
        u32 fq_log;
 
        if (!opt)
@@ -736,10 +737,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 
                if (!skb)
                        break;
+               drop_len += qdisc_pkt_len(skb);
                kfree_skb(skb);
                drop_count++;
        }
-       qdisc_tree_decrease_qlen(sch, drop_count);
+       qdisc_tree_reduce_backlog(sch, drop_count, drop_len);
 
        sch_tree_unlock(sch);
        return err;
index 4c834e9..d3fc8f9 100644 (file)
@@ -175,7 +175,7 @@ static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch)
 static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
-       unsigned int idx;
+       unsigned int idx, prev_backlog;
        struct fq_codel_flow *flow;
        int uninitialized_var(ret);
 
@@ -203,6 +203,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
+       prev_backlog = sch->qstats.backlog;
        q->drop_overlimit++;
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
@@ -211,7 +212,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
        return NET_XMIT_SUCCESS;
 }
 
@@ -241,6 +242,7 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
        struct fq_codel_flow *flow;
        struct list_head *head;
        u32 prev_drop_count, prev_ecn_mark;
+       unsigned int prev_backlog;
 
 begin:
        head = &q->new_flows;
@@ -259,6 +261,7 @@ begin:
 
        prev_drop_count = q->cstats.drop_count;
        prev_ecn_mark = q->cstats.ecn_mark;
+       prev_backlog = sch->qstats.backlog;
 
        skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats,
                            dequeue);
@@ -276,12 +279,14 @@ begin:
        }
        qdisc_bstats_update(sch, skb);
        flow->deficit -= qdisc_pkt_len(skb);
-       /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+       /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
         * or HTB crashes. Defer it for next round.
         */
        if (q->cstats.drop_count && sch->q.qlen) {
-               qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+               qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
+                                         q->cstats.drop_len);
                q->cstats.drop_count = 0;
+               q->cstats.drop_len = 0;
        }
        return skb;
 }
@@ -372,11 +377,13 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_codel_dequeue(sch);
 
+               q->cstats.drop_len += qdisc_pkt_len(skb);
                kfree_skb(skb);
                q->cstats.drop_count++;
        }
-       qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+       qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len);
        q->cstats.drop_count = 0;
+       q->cstats.drop_len = 0;
 
        sch_tree_unlock(sch);
        return 0;
index b7ebe2c..d783d7c 100644 (file)
@@ -895,9 +895,10 @@ static void
 hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static void
@@ -1215,11 +1216,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       hfsc_purge_queue(sch, cl);
-       *old = cl->qdisc;
-       cl->qdisc = new;
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->qdisc);
        return 0;
 }
 
index 86b04e3..13d6f83 100644 (file)
@@ -382,6 +382,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        struct hhf_sched_data *q = qdisc_priv(sch);
        enum wdrr_bucket_idx idx;
        struct wdrr_bucket *bucket;
+       unsigned int prev_backlog;
 
        idx = hhf_classify(skb, sch);
 
@@ -409,6 +410,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
+       prev_backlog = sch->qstats.backlog;
        q->drop_overlimit++;
        /* Return Congestion Notification only if we dropped a packet from this
         * bucket.
@@ -417,7 +419,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this. */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
        return NET_XMIT_SUCCESS;
 }
 
@@ -527,7 +529,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct hhf_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_HHF_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, prev_backlog;
        int err;
        u64 non_hh_quantum;
        u32 new_quantum = q->quantum;
@@ -577,12 +579,14 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
        }
 
        qlen = sch->q.qlen;
+       prev_backlog = sch->qstats.backlog;
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = hhf_dequeue(sch);
 
                kfree_skb(skb);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen,
+                                 prev_backlog - sch->qstats.backlog);
 
        sch_tree_unlock(sch);
        return 0;
index 15ccd7f..87b02ed 100644 (file)
@@ -600,6 +600,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                htb_activate(q, cl);
        }
 
+       qdisc_qstats_backlog_inc(sch, skb);
        sch->q.qlen++;
        return NET_XMIT_SUCCESS;
 }
@@ -889,6 +890,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 ok:
                qdisc_bstats_update(sch, skb);
                qdisc_unthrottled(sch);
+               qdisc_qstats_backlog_dec(sch, skb);
                sch->q.qlen--;
                return skb;
        }
@@ -955,6 +957,7 @@ static unsigned int htb_drop(struct Qdisc *sch)
                        unsigned int len;
                        if (cl->un.leaf.q->ops->drop &&
                            (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) {
+                               sch->qstats.backlog -= len;
                                sch->q.qlen--;
                                if (!cl->un.leaf.q->q.qlen)
                                        htb_deactivate(q, cl);
@@ -984,12 +987,12 @@ static void htb_reset(struct Qdisc *sch)
                        }
                        cl->prio_activity = 0;
                        cl->cmode = HTB_CAN_SEND;
-
                }
        }
        qdisc_watchdog_cancel(&q->watchdog);
        __skb_queue_purge(&q->direct_queue);
        sch->q.qlen = 0;
+       sch->qstats.backlog = 0;
        memset(q->hlevel, 0, sizeof(q->hlevel));
        memset(q->row_mask, 0, sizeof(q->row_mask));
        for (i = 0; i < TC_HTB_NUMPRIO; i++)
@@ -1163,14 +1166,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                                     cl->common.classid)) == NULL)
                return -ENOBUFS;
 
-       sch_tree_lock(sch);
-       *old = cl->un.leaf.q;
-       cl->un.leaf.q = new;
-       if (*old != NULL) {
-               qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-               qdisc_reset(*old);
-       }
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->un.leaf.q);
        return 0;
 }
 
@@ -1272,7 +1268,6 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
 {
        struct htb_sched *q = qdisc_priv(sch);
        struct htb_class *cl = (struct htb_class *)arg;
-       unsigned int qlen;
        struct Qdisc *new_q = NULL;
        int last_child = 0;
 
@@ -1292,9 +1287,11 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
        sch_tree_lock(sch);
 
        if (!cl->level) {
-               qlen = cl->un.leaf.q->q.qlen;
+               unsigned int qlen = cl->un.leaf.q->q.qlen;
+               unsigned int backlog = cl->un.leaf.q->qstats.backlog;
+
                qdisc_reset(cl->un.leaf.q);
-               qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen);
+               qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog);
        }
 
        /* delete from hash and active; remainder in destroy_class */
@@ -1428,10 +1425,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                sch_tree_lock(sch);
                if (parent && !parent->level) {
                        unsigned int qlen = parent->un.leaf.q->q.qlen;
+                       unsigned int backlog = parent->un.leaf.q->qstats.backlog;
 
                        /* turn parent into inner node */
                        qdisc_reset(parent->un.leaf.q);
-                       qdisc_tree_decrease_qlen(parent->un.leaf.q, qlen);
+                       qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog);
                        qdisc_destroy(parent->un.leaf.q);
                        if (parent->prio_activity)
                                htb_deactivate(q, parent);
index 4e904ca..bcdd54b 100644 (file)
@@ -218,7 +218,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
                if (q->queues[i] != &noop_qdisc) {
                        struct Qdisc *child = q->queues[i];
                        q->queues[i] = &noop_qdisc;
-                       qdisc_tree_decrease_qlen(child, child->q.qlen);
+                       qdisc_tree_reduce_backlog(child, child->q.qlen,
+                                                 child->qstats.backlog);
                        qdisc_destroy(child);
                }
        }
@@ -238,8 +239,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
                                q->queues[i] = child;
 
                                if (old != &noop_qdisc) {
-                                       qdisc_tree_decrease_qlen(old,
-                                                                old->q.qlen);
+                                       qdisc_tree_reduce_backlog(old,
+                                                                 old->q.qlen,
+                                                                 old->qstats.backlog);
                                        qdisc_destroy(old);
                                }
                                sch_tree_unlock(sch);
@@ -303,13 +305,7 @@ static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->queues[band];
-       q->queues[band] = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->queues[band]);
        return 0;
 }
 
index 5abd1d9..9640bb3 100644 (file)
@@ -598,7 +598,8 @@ deliver:
                                if (unlikely(err != NET_XMIT_SUCCESS)) {
                                        if (net_xmit_drop_count(err)) {
                                                qdisc_qstats_drop(sch);
-                                               qdisc_tree_decrease_qlen(sch, 1);
+                                               qdisc_tree_reduce_backlog(sch, 1,
+                                                                         qdisc_pkt_len(skb));
                                        }
                                }
                                goto tfifo_dequeue;
@@ -1037,15 +1038,7 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 {
        struct netem_sched_data *q = qdisc_priv(sch);
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       if (*old) {
-               qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-               qdisc_reset(*old);
-       }
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index b783a44..71ae3b9 100644 (file)
@@ -183,7 +183,7 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct pie_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_PIE_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        int err;
 
        if (!opt)
@@ -232,10 +232,11 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
+               dropped += qdisc_pkt_len(skb);
                qdisc_qstats_backlog_dec(sch, skb);
                qdisc_drop(skb, sch);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        sch_tree_unlock(sch);
        return 0;
index ba6487f..fee1b15 100644 (file)
@@ -191,7 +191,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
                struct Qdisc *child = q->queues[i];
                q->queues[i] = &noop_qdisc;
                if (child != &noop_qdisc) {
-                       qdisc_tree_decrease_qlen(child, child->q.qlen);
+                       qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog);
                        qdisc_destroy(child);
                }
        }
@@ -210,8 +210,9 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
                                q->queues[i] = child;
 
                                if (old != &noop_qdisc) {
-                                       qdisc_tree_decrease_qlen(old,
-                                                                old->q.qlen);
+                                       qdisc_tree_reduce_backlog(old,
+                                                                 old->q.qlen,
+                                                                 old->qstats.backlog);
                                        qdisc_destroy(old);
                                }
                                sch_tree_unlock(sch);
@@ -268,13 +269,7 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->queues[band];
-       q->queues[band] = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->queues[band]);
        return 0;
 }
 
index 3dc3a6e..8d2d8d9 100644 (file)
@@ -220,9 +220,10 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
 static void qfq_purge_queue(struct qfq_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
@@ -617,11 +618,7 @@ static int qfq_graft_class(struct Qdisc *sch, unsigned long arg,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       qfq_purge_queue(cl);
-       *old = cl->qdisc;
-       cl->qdisc = new;
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->qdisc);
        return 0;
 }
 
index 6c0534c..8c0508c 100644 (file)
@@ -210,7 +210,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt)
        q->flags = ctl->flags;
        q->limit = ctl->limit;
        if (child) {
-               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+               qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                         q->qdisc->qstats.backlog);
                qdisc_destroy(q->qdisc);
                q->qdisc = child;
        }
@@ -313,12 +314,7 @@ static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index 5bbb633..c696116 100644 (file)
@@ -510,7 +510,8 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt)
 
        sch_tree_lock(sch);
 
-       qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+       qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                 q->qdisc->qstats.backlog);
        qdisc_destroy(q->qdisc);
        q->qdisc = child;
 
@@ -606,12 +607,7 @@ static int sfb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index 3abab53..498f0a2 100644 (file)
@@ -346,7 +346,7 @@ static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned int hash;
+       unsigned int hash, dropped;
        sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
@@ -461,7 +461,7 @@ enqueue:
                return NET_XMIT_SUCCESS;
 
        qlen = slot->qlen;
-       sfq_drop(sch);
+       dropped = sfq_drop(sch);
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
         */
@@ -469,7 +469,7 @@ enqueue:
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, dropped);
        return NET_XMIT_SUCCESS;
 }
 
@@ -537,6 +537,7 @@ static void sfq_rehash(struct Qdisc *sch)
        struct sfq_slot *slot;
        struct sk_buff_head list;
        int dropped = 0;
+       unsigned int drop_len = 0;
 
        __skb_queue_head_init(&list);
 
@@ -565,6 +566,7 @@ static void sfq_rehash(struct Qdisc *sch)
                        if (x >= SFQ_MAX_FLOWS) {
 drop:
                                qdisc_qstats_backlog_dec(sch, skb);
+                               drop_len += qdisc_pkt_len(skb);
                                kfree_skb(skb);
                                dropped++;
                                continue;
@@ -594,7 +596,7 @@ drop:
                }
        }
        sch->q.qlen -= dropped;
-       qdisc_tree_decrease_qlen(sch, dropped);
+       qdisc_tree_reduce_backlog(sch, dropped, drop_len);
 }
 
 static void sfq_perturbation(unsigned long arg)
@@ -618,7 +620,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        struct sfq_sched_data *q = qdisc_priv(sch);
        struct tc_sfq_qopt *ctl = nla_data(opt);
        struct tc_sfq_qopt_v1 *ctl_v1 = NULL;
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        struct red_parms *p = NULL;
 
        if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
@@ -667,8 +669,8 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
 
        qlen = sch->q.qlen;
        while (sch->q.qlen > q->limit)
-               sfq_drop(sch);
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+               dropped += sfq_drop(sch);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        del_timer(&q->perturb_timer);
        if (q->perturb_period) {
index a4afde1..c2fbde7 100644 (file)
@@ -160,6 +160,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
        struct tbf_sched_data *q = qdisc_priv(sch);
        struct sk_buff *segs, *nskb;
        netdev_features_t features = netif_skb_features(skb);
+       unsigned int len = 0, prev_len = qdisc_pkt_len(skb);
        int ret, nb;
 
        segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
@@ -172,6 +173,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
                nskb = segs->next;
                segs->next = NULL;
                qdisc_skb_cb(segs)->pkt_len = segs->len;
+               len += segs->len;
                ret = qdisc_enqueue(segs, q->qdisc);
                if (ret != NET_XMIT_SUCCESS) {
                        if (net_xmit_drop_count(ret))
@@ -183,7 +185,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
        }
        sch->q.qlen += nb;
        if (nb > 1)
-               qdisc_tree_decrease_qlen(sch, 1 - nb);
+               qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len);
        consume_skb(skb);
        return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
 }
@@ -399,7 +401,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
 
        sch_tree_lock(sch);
        if (child) {
-               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+               qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                         q->qdisc->qstats.backlog);
                qdisc_destroy(q->qdisc);
                q->qdisc = child;
        }
@@ -502,13 +505,7 @@ static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }