Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[sfrench/cifs-2.6.git] / drivers / net / tun.c
index 8f95a562b8d0c471c44591629e04809f7faef9b2..be37235af55d2d282b162adcd9d0e599cd5e6b3e 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/if_tun.h>
 #include <linux/if_vlan.h>
 #include <linux/crc32.h>
+#include <linux/math.h>
 #include <linux/nsproxy.h>
 #include <linux/virtio_net.h>
 #include <linux/rcupdate.h>
@@ -523,8 +524,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
 static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb)
 {
        struct tun_flow_entry *e;
-       u32 txq = 0;
-       u32 numqueues = 0;
+       u32 txq, numqueues;
 
        numqueues = READ_ONCE(tun->numqueues);
 
@@ -534,8 +534,7 @@ static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb)
                tun_flow_save_rps_rxhash(e, txq);
                txq = e->queue_index;
        } else {
-               /* use multiply and shift instead of expensive divide */
-               txq = ((u64)txq * numqueues) >> 32;
+               txq = reciprocal_scale(txq, numqueues);
        }
 
        return txq;
@@ -1928,7 +1927,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                rcu_read_lock();
                xdp_prog = rcu_dereference(tun->xdp_prog);
                if (xdp_prog) {
-                       ret = do_xdp_generic(xdp_prog, skb);
+                       ret = do_xdp_generic(xdp_prog, &skb);
                        if (ret != XDP_PASS) {
                                rcu_read_unlock();
                                local_bh_enable();
@@ -2518,7 +2517,7 @@ build:
        skb_record_rx_queue(skb, tfile->queue_index);
 
        if (skb_xdp) {
-               ret = do_xdp_generic(xdp_prog, skb);
+               ret = do_xdp_generic(xdp_prog, &skb);
                if (ret != XDP_PASS) {
                        ret = 0;
                        goto out;
@@ -3645,12 +3644,22 @@ static int tun_set_coalesce(struct net_device *dev,
        return 0;
 }
 
+static void tun_get_channels(struct net_device *dev,
+                            struct ethtool_channels *channels)
+{
+       struct tun_struct *tun = netdev_priv(dev);
+
+       channels->combined_count = tun->numqueues;
+       channels->max_combined = tun->flags & IFF_MULTI_QUEUE ? MAX_TAP_QUEUES : 1;
+}
+
 static const struct ethtool_ops tun_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_RX_MAX_FRAMES,
        .get_drvinfo    = tun_get_drvinfo,
        .get_msglevel   = tun_get_msglevel,
        .set_msglevel   = tun_set_msglevel,
        .get_link       = ethtool_op_get_link,
+       .get_channels   = tun_get_channels,
        .get_ts_info    = ethtool_op_get_ts_info,
        .get_coalesce   = tun_get_coalesce,
        .set_coalesce   = tun_set_coalesce,