[PATCH v2] net-fq: Add WARN_ON check for null flow.

2018-06-07 Thread greearb
From: Ben Greear 

While testing an ath10k firmware that often crashed under load,
I was seeing kernel crashes as well.  One of them appeared to
be a dereference of a NULL flow object in fq_tin_dequeue.

I have since fixed the firmware flaw, but I think it would be
worth adding the WARN_ON in case the problem appears again.

BUG: unable to handle kernel NULL pointer dereference at 003c
IP: ieee80211_tx_dequeue+0xfb/0xb10 [mac80211]
PGD 8001417fe067 P4D 8001417fe067 PUD 13db41067 PMD 0
Oops:  [#1] PREEMPT SMP PTI
Modules linked in: nf_conntrack_netlink nf_conntrack nfnetlink nf_defrag_ipv4 
libcrc32c vrf 8021q garp mrp stp llc fuse macvlan wanlink(O) pktgen lm78 ]
CPU: 2 PID: 21733 Comm: ip Tainted: GW  O 4.16.8+ #35
Hardware name: _ _/, BIOS 5.11 08/26/2016
RIP: 0010:ieee80211_tx_dequeue+0xfb/0xb10 [mac80211]
RSP: 0018:880172d03c30 EFLAGS: 00010286
RAX: 88013b2c RBX: 88013b2c00b8 RCX: 0898
RDX: 0001 RSI: 88013b2c00d8 RDI: 88016ac40820
RBP: 88016ac42ba0 R08: 0020 R09: 
R10: 0010 R11: 001256c89fd8 R12: 88013b2c
R13: 88013b2c00d8 R14:  R15: 88013b2c00d8
FS:  7f04e3606700() GS:880172d0() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 003c CR3: 00013b35a005 CR4: 003606e0
DR0:  DR1:  DR2: 
DR3:  DR6: fffe0ff0 DR7: 0400
Call Trace:
 
 ? update_load_avg+0x607/0x6f0
 ath10k_mac_tx_push_txq+0x6e/0x220 [ath10k_core]
 ath10k_mac_tx_push_pending+0x151/0x1e0 [ath10k_core]
 ath10k_htt_txrx_compl_task+0x113e/0x1940 [ath10k_core]
 ? ath10k_ce_completed_send_next_nolock+0x6f/0x90 [ath10k_pci]
 ? ath10k_ce_completed_send_next+0x31/0x40 [ath10k_pci]
 ? ath10k_pci_htc_tx_cb+0x30/0xc0 [ath10k_pci]
 ? ath10k_bus_pci_write32+0x3c/0xa0 [ath10k_pci]
 ath10k_pci_napi_poll+0x44/0xf0 [ath10k_pci]
 net_rx_action+0x250/0x3b0
 __do_softirq+0xc2/0x2c2
 irq_exit+0x93/0xa0
 do_IRQ+0x45/0xc0
 common_interrupt+0xf/0xf
 

Signed-off-by: Ben Greear 
---

* v2:  Use list_first_entry_or_null as suggested.

 include/net/fq_impl.h | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h
index be7c0fa..cb911f0 100644
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -78,7 +78,10 @@ static struct sk_buff *fq_tin_dequeue(struct fq *fq,
return NULL;
}
 
-   flow = list_first_entry(head, struct fq_flow, flowchain);
+   flow = list_first_entry_or_null(head, struct fq_flow, flowchain);
+
+   if (WARN_ON_ONCE(!flow))
+   return NULL;
 
if (flow->deficit <= 0) {
flow->deficit += fq->quantum;
-- 
2.4.11



[PATCH] net-fq: Add WARN_ON check for null flow.

2018-06-07 Thread greearb
From: Ben Greear 

While testing an ath10k firmware that often crashed under load,
I was seeing kernel crashes as well.  One of them appeared to
be a dereference of a NULL flow object in fq_tin_dequeue.

I have since fixed the firmware flaw, but I think it would be
worth adding the WARN_ON in case the problem appears again.

BUG: unable to handle kernel NULL pointer dereference at 003c
IP: ieee80211_tx_dequeue+0xfb/0xb10 [mac80211]
PGD 8001417fe067 P4D 8001417fe067 PUD 13db41067 PMD 0
Oops:  [#1] PREEMPT SMP PTI
Modules linked in: nf_conntrack_netlink nf_conntrack nfnetlink nf_defrag_ipv4 
libcrc32c vrf 8021q garp mrp stp llc fuse macvlan wanlink(O) pktgen lm78 ]
CPU: 2 PID: 21733 Comm: ip Tainted: GW  O 4.16.8+ #35
Hardware name: _ _/, BIOS 5.11 08/26/2016
RIP: 0010:ieee80211_tx_dequeue+0xfb/0xb10 [mac80211]
RSP: 0018:880172d03c30 EFLAGS: 00010286
RAX: 88013b2c RBX: 88013b2c00b8 RCX: 0898
RDX: 0001 RSI: 88013b2c00d8 RDI: 88016ac40820
RBP: 88016ac42ba0 R08: 0020 R09: 
R10: 0010 R11: 001256c89fd8 R12: 88013b2c
R13: 88013b2c00d8 R14:  R15: 88013b2c00d8
FS:  7f04e3606700() GS:880172d0() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 003c CR3: 00013b35a005 CR4: 003606e0
DR0:  DR1:  DR2: 
DR3:  DR6: fffe0ff0 DR7: 0400
Call Trace:
 
 ? update_load_avg+0x607/0x6f0
 ath10k_mac_tx_push_txq+0x6e/0x220 [ath10k_core]
 ath10k_mac_tx_push_pending+0x151/0x1e0 [ath10k_core]
 ath10k_htt_txrx_compl_task+0x113e/0x1940 [ath10k_core]
 ? ath10k_ce_completed_send_next_nolock+0x6f/0x90 [ath10k_pci]
 ? ath10k_ce_completed_send_next+0x31/0x40 [ath10k_pci]
 ? ath10k_pci_htc_tx_cb+0x30/0xc0 [ath10k_pci]
 ? ath10k_bus_pci_write32+0x3c/0xa0 [ath10k_pci]
 ath10k_pci_napi_poll+0x44/0xf0 [ath10k_pci]
 net_rx_action+0x250/0x3b0
 __do_softirq+0xc2/0x2c2
 irq_exit+0x93/0xa0
 do_IRQ+0x45/0xc0
 common_interrupt+0xf/0xf
 

Signed-off-by: Ben Greear 
---
 include/net/fq_impl.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h
index be7c0fa..e40354d 100644
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -80,6 +80,9 @@ static struct sk_buff *fq_tin_dequeue(struct fq *fq,
 
flow = list_first_entry(head, struct fq_flow, flowchain);
 
+   if (WARN_ON_ONCE(!flow))
+   return NULL;
+
if (flow->deficit <= 0) {
flow->deficit += fq->quantum;
list_move_tail(>flowchain,
-- 
2.4.11



[PATCH v2 3/3] ath10k: Support ethtool gstats2 API.

2018-04-19 Thread greearb
From: Ben Greear 

Skip a firmware stats update when calling
code indicates the stats refresh is not needed.

Signed-off-by: Ben Greear 
---

v2:  Convert to new flag name, attempt to fix build
   when there is not DEBUGFS enabled for ath10k.

 drivers/net/wireless/ath/ath10k/debug.c | 18 +++---
 drivers/net/wireless/ath/ath10k/debug.h |  5 +
 drivers/net/wireless/ath/ath10k/mac.c   |  1 +
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index bac832c..235cd04 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1159,9 +1159,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw 
*hw,
return 0;
 }
 
-void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
-  struct ieee80211_vif *vif,
-  struct ethtool_stats *stats, u64 *data)
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 flags)
 {
struct ath10k *ar = hw->priv;
static const struct ath10k_fw_stats_pdev zero_stats = {};
@@ -1170,6 +1171,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
mutex_lock(>conf_mutex);
 
+   if (flags & ETHTOOL_GS2_NO_REFRESH_FW)
+   goto skip_query_fw_stats;
+
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_debug_fw_stats_request(ar);
if (ret) {
@@ -1180,6 +1184,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
}
}
 
+skip_query_fw_stats:
pdev_stats = list_first_entry_or_null(>debug.fw_stats.pdevs,
  struct ath10k_fw_stats_pdev,
  list);
@@ -1244,6 +1249,13 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH10K_SSTATS_LEN);
 }
 
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+  struct ieee80211_vif *vif,
+  struct ethtool_stats *stats, u64 *data)
+{
+   ath10k_debug_get_et_stats2(hw, vif, stats, data, 0);
+}
+
 static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 0afca5c..e953dd0 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -117,6 +117,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
 void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct ethtool_stats *stats, u64 *data);
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 level);
 
 static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
 {
@@ -195,6 +199,7 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct 
ath10k *ar)
 #define ath10k_debug_get_et_strings NULL
 #define ath10k_debug_get_et_sset_count NULL
 #define ath10k_debug_get_et_stats NULL
+#define ath10k_debug_get_et_stats2 NULL
 
 #endif /* CONFIG_ATH10K_DEBUGFS */
 #ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index bf05a36..27b793c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7734,6 +7734,7 @@ static const struct ieee80211_ops ath10k_ops = {
.ampdu_action   = ath10k_ampdu_action,
.get_et_sset_count  = ath10k_debug_get_et_sset_count,
.get_et_stats   = ath10k_debug_get_et_stats,
+   .get_et_stats2  = ath10k_debug_get_et_stats2,
.get_et_strings = ath10k_debug_get_et_strings,
.add_chanctx= ath10k_mac_op_add_chanctx,
.remove_chanctx = ath10k_mac_op_remove_chanctx,
-- 
2.4.11



[PATCH v2 1/3] ethtool: Support ETHTOOL_GSTATS2 command.

2018-04-19 Thread greearb
From: Ben Greear 

This is similar to ETHTOOL_GSTATS, but it allows you to specify
flags.  These flags can be used by the driver to decrease the
amount of stats refreshed.  In particular, this helps with ath10k
since getting the firmware stats can be slow.

Signed-off-by: Ben Greear 
---

v2:  Change flag names to ETHTOOL_GS_NO_REFRESH_FW,
 ETHTOOL_GS2_REFRESH_ALL.

 include/linux/ethtool.h  | 12 
 include/uapi/linux/ethtool.h | 11 +++
 net/core/ethtool.c   | 40 +++-
 3 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index ebe4181..c90bc6f6 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -243,6 +243,15 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
  * @get_ethtool_stats: Return extended statistics about the device.
  * This is only useful if the device maintains statistics not
  * included in  rtnl_link_stats64.
+ * @get_ethtool_stats2: Return extended statistics about the device.
+ * This is only useful if the device maintains statistics not
+ * included in  rtnl_link_stats64.
+ *  Takes a flags argument:  0 means all (same as get_ethtool_stats),
+ *  0x1 (ETHTOOL_GS2_NO_REFRESH_FW) means skip refreshing firmware stats.
+ *  Other flags are reserved for now.
+ *  Same number of stats will be returned, but some of them might
+ *  not be as accurate/refreshed.  This is to allow not querying
+ *  firmware or other expensive-to-read stats, for instance.
  * @begin: Function to be called before any other operation.  Returns a
  * negative error code or zero.
  * @complete: Function to be called after any other operation except
@@ -355,6 +364,9 @@ struct ethtool_ops {
int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
void(*get_ethtool_stats)(struct net_device *,
 struct ethtool_stats *, u64 *);
+   void(*get_ethtool_stats2)(struct net_device *dev,
+ struct ethtool_stats *gstats, u64 *data,
+ u32 flags);
int (*begin)(struct net_device *);
void(*complete)(struct net_device *);
u32 (*get_priv_flags)(struct net_device *);
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 4ca65b5..75c753d 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1396,11 +1396,22 @@ enum ethtool_fec_config_bits {
 #define ETHTOOL_PHY_STUNABLE   0x004f /* Set PHY tunable configuration */
 #define ETHTOOL_GFECPARAM  0x0050 /* Get FEC settings */
 #define ETHTOOL_SFECPARAM  0x0051 /* Set FEC settings */
+#define ETHTOOL_GSTATS20x0052 /* get NIC-specific 
statistics
+   * with ability to specify flags.
+   * See ETHTOOL_GS2* below.
+   */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET ETHTOOL_GSET
 #define SPARC_ETH_SSET ETHTOOL_SSET
 
+/* GSTATS2 flags */
+#define ETHTOOL_GS2_REFRESH_ALL (0)/* default is to update all stats */
+#define ETHTOOL_GS2_NO_REFRESH_FW   (1<<0) /* Skip refreshing stats that probe
+   * firmware, and thus are
+   * slow/expensive.
+   */
+
 /* Link mode bit indices */
 enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_10baseT_Half_BIT  = 0,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 03416e6..dd16f15 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1952,16 +1952,14 @@ static int ethtool_phys_id(struct net_device *dev, void 
__user *useraddr)
return rc;
 }
 
-static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
+static int _ethtool_get_stats(struct net_device *dev, void __user *useraddr,
+ u32 flags)
 {
struct ethtool_stats stats;
const struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret, n_stats;
 
-   if (!ops->get_ethtool_stats || !ops->get_sset_count)
-   return -EOPNOTSUPP;
-
n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
if (n_stats < 0)
return n_stats;
@@ -1976,7 +1974,10 @@ static int ethtool_get_stats(struct net_device *dev, 
void __user *useraddr)
if (n_stats && !data)
return -ENOMEM;
 
-   ops->get_ethtool_stats(dev, , data);
+   if (flags != ETHTOOL_GS2_REFRESH_ALL)
+   ops->get_ethtool_stats2(dev, , data, flags);
+   else
+   ops->get_ethtool_stats(dev, , data);
 
ret = -EFAULT;
if (copy_to_user(useraddr, , 

[PATCH v2 2/3] mac80211: Add support for ethtool gstats2 API.

2018-04-19 Thread greearb
From: Ben Greear 

This enables users to request fewer stats to be refreshed
in cases where firmware does not need to be probed.

Signed-off-by: Ben Greear 
---

v2:  No changes.

 include/net/mac80211.h|  6 ++
 net/mac80211/driver-ops.h |  9 +++--
 net/mac80211/ethtool.c| 18 +-
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d2279b2..4854f33 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3361,6 +3361,8 @@ enum ieee80211_reconfig_type {
  *
  * @get_et_stats:  Ethtool API to get a set of u64 stats.
  *
+ * @get_et_stats2:  Ethtool API to get a set of u64 stats, with flags.
+ *
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  * and perhaps other supported types of ethtool data-sets.
  *
@@ -3692,6 +3694,10 @@ struct ieee80211_ops {
void(*get_et_stats)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+   void(*get_et_stats2)(struct ieee80211_hw *hw,
+struct ieee80211_vif *vif,
+struct ethtool_stats *stats, u64 *data,
+u32 flags);
void(*get_et_strings)(struct ieee80211_hw *hw,
  struct ieee80211_vif *vif,
  u32 sset, u8 *data);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4d82fe7..519d2db 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -58,10 +58,15 @@ static inline void drv_get_et_strings(struct 
ieee80211_sub_if_data *sdata,
 
 static inline void drv_get_et_stats(struct ieee80211_sub_if_data *sdata,
struct ethtool_stats *stats,
-   u64 *data)
+   u64 *data, u32 flags)
 {
struct ieee80211_local *local = sdata->local;
-   if (local->ops->get_et_stats) {
+   if (local->ops->get_et_stats2) {
+   trace_drv_get_et_stats(local);
+   local->ops->get_et_stats2(>hw, >vif, stats, data,
+ flags);
+   trace_drv_return_void(local);
+   } else if (local->ops->get_et_stats) {
trace_drv_get_et_stats(local);
local->ops->get_et_stats(>hw, >vif, stats, data);
trace_drv_return_void(local);
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 9cc986d..b67520e 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -61,9 +61,9 @@ static int ieee80211_get_sset_count(struct net_device *dev, 
int sset)
return rv;
 }
 
-static void ieee80211_get_stats(struct net_device *dev,
-   struct ethtool_stats *stats,
-   u64 *data)
+static void ieee80211_get_stats2(struct net_device *dev,
+struct ethtool_stats *stats,
+u64 *data, u32 flags)
 {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -199,7 +199,14 @@ static void ieee80211_get_stats(struct net_device *dev,
if (WARN_ON(i != STA_STATS_LEN))
return;
 
-   drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
+   drv_get_et_stats(sdata, stats, [STA_STATS_LEN], flags);
+}
+
+static void ieee80211_get_stats(struct net_device *dev,
+   struct ethtool_stats *stats,
+   u64 *data)
+{
+   ieee80211_get_stats2(dev, stats, data, 0);
 }
 
 static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
@@ -211,7 +218,7 @@ static void ieee80211_get_strings(struct net_device *dev, 
u32 sset, u8 *data)
sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
}
-   drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
+   drv_get_et_strings(sdata, sset, [sz_sta_stats]);
 }
 
 static int ieee80211_get_regs_len(struct net_device *dev)
@@ -238,5 +245,6 @@ const struct ethtool_ops ieee80211_ethtool_ops = {
.set_ringparam = ieee80211_set_ringparam,
.get_strings = ieee80211_get_strings,
.get_ethtool_stats = ieee80211_get_stats,
+   .get_ethtool_stats2 = ieee80211_get_stats2,
.get_sset_count = ieee80211_get_sset_count,
 };
-- 
2.4.11



[PATCH] net: Work around crash in ipv6 fib-walk-continue

2018-04-19 Thread greearb
From: Ben Greear 

This keeps us from crashing in certain test cases where we
bring up many (1000, for instance) mac-vlans with IPv6
enabled in the kernel.  This bug has been around for a
very long time.

Until a real fix is found (and for stable), maybe it
is better to return an incomplete fib walk instead
of crashing.

BUG: unable to handle kernel NULL pointer dereference at 8
IP: fib6_walk_continue+0x5b/0x140 [ipv6]
PGD 8007dfc0c067 P4D 8007dfc0c067 PUD 7e66ff067 PMD 0
Oops:  [#1] PREEMPT SMP PTI
Modules linked in: nf_conntrack_netlink nf_conntrack nfnetlink nf_defrag_ipv4 
libcrc32c vrf]
CPU: 3 PID: 15117 Comm: ip Tainted: G   O 4.16.0+ #5
Hardware name: Iron_Systems,Inc CS-CAD-2U-A02/X10SRL-F, BIOS 2.0b 05/02/2017
RIP: 0010:fib6_walk_continue+0x5b/0x140 [ipv6]
RSP: 0018:c90008c3bc10 EFLAGS: 00010287
RAX: 88085ac45050 RBX: 8807e03008a0 RCX: 
RDX:  RSI: c90008c3bc48 RDI: 8232b240
RBP: 880819167600 R08: 0008 R09: 8807dff10071
R10: c90008c3bbd0 R11:  R12: 8807e03008a0
R13: 0002 R14: 8807e05744c8 R15: 8807e08ef000
FS:  7f2f04342700() GS:88087fcc() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 0008 CR3: 0007e0556002 CR4: 003606e0
DR0:  DR1:  DR2: 
DR3:  DR6: fffe0ff0 DR7: 0400
Call Trace:
 inet6_dump_fib+0x14b/0x2c0 [ipv6]
 netlink_dump+0x216/0x2a0
 netlink_recvmsg+0x254/0x400
 ? copy_msghdr_from_user+0xb5/0x110
 ___sys_recvmsg+0xe9/0x230
 ? find_held_lock+0x3b/0xb0
 ? __handle_mm_fault+0x617/0x1180
 ? __audit_syscall_entry+0xb3/0x110
 ? __sys_recvmsg+0x39/0x70
 __sys_recvmsg+0x39/0x70
 do_syscall_64+0x63/0x120
 entry_SYSCALL_64_after_hwframe+0x3d/0xa2
RIP: 0033:0x7f2f03a72030
RSP: 002b:7fffab3de508 EFLAGS: 0246 ORIG_RAX: 002f
RAX: ffda RBX: 7fffab3e641c RCX: 7f2f03a72030
RDX:  RSI: 7fffab3de570 RDI: 0004
RBP:  R08: 7e6c R09: 7fffab3e63a8
R10: 7fffab3de5b0 R11: 0246 R12: 7fffab3e6608
R13: 0066b460 R14: 7e6c R15: 
Code: 85 d2 74 17 f6 40 2a 04 74 11 8b 53 2c 85 d2 0f 84 d7 00 00 00 83 ea 01 
89 53 2c c7 4
RIP: fib6_walk_continue+0x5b/0x140 [ipv6] RSP: c90008c3bc10
CR2: 0008
---[ end trace bd03458864eb266c ]---

Signed-off-by: Ben Greear 
---

* This patch is against 4.16+, but a similar patch fixes the same issue
  older kernels.  Perhaps newer kernels will be resolved by David
  Ahern's fib6 changes, but I guess those won't be backported, so maybe
  this patch is still useful either way.

 net/ipv6/ip6_fib.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 92b8d8c..afef362 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1855,6 +1855,12 @@ static int fib6_walk_continue(struct fib6_walker *w)
if (fn == w->root)
return 0;
pn = rcu_dereference_protected(fn->parent, 1);
+   if (WARN_ON_ONCE(!pn)) {
+   pr_err("FWS-U, w: %p  fn: %p  pn: %p\n",
+  w, fn, pn);
+   /* Attempt to work around crash that has been 
here forever. --Ben */
+   return 0;
+   }
left = rcu_dereference_protected(pn->left, 1);
right = rcu_dereference_protected(pn->right, 1);
w->node = pn;
-- 
2.4.11



[PATCH 2/3] mac80211: Add support for ethtool gstats2 API.

2018-04-17 Thread greearb
From: Ben Greear 

This enables users to request fewer stats to be refreshed
in cases where firmware does not need to be probed.

Signed-off-by: Ben Greear 
---
 include/net/mac80211.h|  6 ++
 net/mac80211/driver-ops.h |  9 +++--
 net/mac80211/ethtool.c| 18 +-
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d2279b2..4854f33 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3361,6 +3361,8 @@ enum ieee80211_reconfig_type {
  *
  * @get_et_stats:  Ethtool API to get a set of u64 stats.
  *
+ * @get_et_stats2:  Ethtool API to get a set of u64 stats, with flags.
+ *
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  * and perhaps other supported types of ethtool data-sets.
  *
@@ -3692,6 +3694,10 @@ struct ieee80211_ops {
void(*get_et_stats)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+   void(*get_et_stats2)(struct ieee80211_hw *hw,
+struct ieee80211_vif *vif,
+struct ethtool_stats *stats, u64 *data,
+u32 flags);
void(*get_et_strings)(struct ieee80211_hw *hw,
  struct ieee80211_vif *vif,
  u32 sset, u8 *data);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4d82fe7..519d2db 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -58,10 +58,15 @@ static inline void drv_get_et_strings(struct 
ieee80211_sub_if_data *sdata,
 
 static inline void drv_get_et_stats(struct ieee80211_sub_if_data *sdata,
struct ethtool_stats *stats,
-   u64 *data)
+   u64 *data, u32 flags)
 {
struct ieee80211_local *local = sdata->local;
-   if (local->ops->get_et_stats) {
+   if (local->ops->get_et_stats2) {
+   trace_drv_get_et_stats(local);
+   local->ops->get_et_stats2(>hw, >vif, stats, data,
+ flags);
+   trace_drv_return_void(local);
+   } else if (local->ops->get_et_stats) {
trace_drv_get_et_stats(local);
local->ops->get_et_stats(>hw, >vif, stats, data);
trace_drv_return_void(local);
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 9cc986d..b67520e 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -61,9 +61,9 @@ static int ieee80211_get_sset_count(struct net_device *dev, 
int sset)
return rv;
 }
 
-static void ieee80211_get_stats(struct net_device *dev,
-   struct ethtool_stats *stats,
-   u64 *data)
+static void ieee80211_get_stats2(struct net_device *dev,
+struct ethtool_stats *stats,
+u64 *data, u32 flags)
 {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -199,7 +199,14 @@ static void ieee80211_get_stats(struct net_device *dev,
if (WARN_ON(i != STA_STATS_LEN))
return;
 
-   drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
+   drv_get_et_stats(sdata, stats, [STA_STATS_LEN], flags);
+}
+
+static void ieee80211_get_stats(struct net_device *dev,
+   struct ethtool_stats *stats,
+   u64 *data)
+{
+   ieee80211_get_stats2(dev, stats, data, 0);
 }
 
 static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
@@ -211,7 +218,7 @@ static void ieee80211_get_strings(struct net_device *dev, 
u32 sset, u8 *data)
sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
}
-   drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
+   drv_get_et_strings(sdata, sset, [sz_sta_stats]);
 }
 
 static int ieee80211_get_regs_len(struct net_device *dev)
@@ -238,5 +245,6 @@ const struct ethtool_ops ieee80211_ethtool_ops = {
.set_ringparam = ieee80211_set_ringparam,
.get_strings = ieee80211_get_strings,
.get_ethtool_stats = ieee80211_get_stats,
+   .get_ethtool_stats2 = ieee80211_get_stats2,
.get_sset_count = ieee80211_get_sset_count,
 };
-- 
2.4.11



[PATCH] ethtool: Support ETHTOOL_GSTATS2 API.

2018-04-17 Thread greearb
From: Ben Greear 

This allows users to specify flags to the get-stats
API, potentially saving expensive stats queries when
they are not desired.

Signed-off-by: Ben Greear 
---
 ethtool-copy.h |  9 +
 ethtool.c  | 25 -
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/ethtool-copy.h b/ethtool-copy.h
index 8cc61e9..11ce456 100644
--- a/ethtool-copy.h
+++ b/ethtool-copy.h
@@ -1390,11 +1390,20 @@ enum ethtool_fec_config_bits {
 #define ETHTOOL_PHY_STUNABLE   0x004f /* Set PHY tunable configuration */
 #define ETHTOOL_GFECPARAM  0x0050 /* Get FEC settings */
 #define ETHTOOL_SFECPARAM  0x0051 /* Set FEC settings */
+#define ETHTOOL_GSTATS20x0052 /* get NIC-specific 
statistics
+   * with ability to specify flags.
+   * See ETHTOOL_GS2* below.
+   */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET ETHTOOL_GSET
 #define SPARC_ETH_SSET ETHTOOL_SSET
 
+/* GSTATS2 flags */
+#define ETHTOOL_GS2_SKIP_NONE (0)/* default is to update all stats */
+#define ETHTOOL_GS2_SKIP_FW   (1<<0) /* Skip reading stats that probe firmware,
+ * and thus are slow/expensive.
+ */
 /* Link mode bit indices */
 enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_10baseT_Half_BIT  = 0,
diff --git a/ethtool.c b/ethtool.c
index 3289e0f..6a11077 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -3440,14 +3440,14 @@ static int do_phys_id(struct cmd_context *ctx)
 }
 
 static int do_gstats(struct cmd_context *ctx, int cmd, int stringset,
-   const char *name)
+const char *name, u32 flags)
 {
struct ethtool_gstrings *strings;
struct ethtool_stats *stats;
unsigned int n_stats, sz_stats, i;
int err;
 
-   if (ctx->argc != 0)
+   if ((ctx->argc != 0) && (flags == ETHTOOL_GS2_SKIP_NONE))
exit_bad_args();
 
strings = get_stringset(ctx, stringset,
@@ -3475,7 +3475,10 @@ static int do_gstats(struct cmd_context *ctx, int cmd, 
int stringset,
}
 
stats->cmd = cmd;
-   stats->n_stats = n_stats;
+   if (cmd == ETHTOOL_GSTATS2)
+   stats->n_stats = flags;
+   else
+   stats->n_stats = n_stats;
err = send_ioctl(ctx, stats);
if (err < 0) {
perror("Cannot get stats information");
@@ -3500,12 +3503,22 @@ static int do_gstats(struct cmd_context *ctx, int cmd, 
int stringset,
 
 static int do_gnicstats(struct cmd_context *ctx)
 {
-   return do_gstats(ctx, ETHTOOL_GSTATS, ETH_SS_STATS, "NIC");
+   return do_gstats(ctx, ETHTOOL_GSTATS, ETH_SS_STATS, "NIC", 
ETHTOOL_GS2_SKIP_NONE);
+}
+
+static int do_gnicstats2(struct cmd_context *ctx)
+{
+   u32 flags = ETHTOOL_GS2_SKIP_NONE;
+   if (ctx->argc >= 1)
+   if (strcmp(ctx->argp[0], "nofw") == 0)
+   flags |= ETHTOOL_GS2_SKIP_FW;
+   return do_gstats(ctx, ETHTOOL_GSTATS2, ETH_SS_STATS, "NIC", flags);
 }
 
 static int do_gphystats(struct cmd_context *ctx)
 {
-   return do_gstats(ctx, ETHTOOL_GPHYSTATS, ETH_SS_PHY_STATS, "PHY");
+   return do_gstats(ctx, ETHTOOL_GPHYSTATS, ETH_SS_PHY_STATS, "PHY",
+ETHTOOL_GS2_SKIP_NONE);
 }
 
 static int do_srxntuple(struct cmd_context *ctx,
@@ -5118,6 +5131,8 @@ static const struct option {
{ "-t|--test", 1, do_test, "Execute adapter self test",
  "   [ online | offline | external_lb ]\n" },
{ "-S|--statistics", 1, do_gnicstats, "Show adapter statistics" },
+   { "-2|--S2", 1, do_gnicstats2, "Show adapter statistics with flags",
+ "   [ nofw ]\n" },
{ "--phy-statistics", 1, do_gphystats,
  "Show phy statistics" },
{ "-n|-u|--show-nfc|--show-ntuple", 1, do_grxclass,
-- 
2.4.11



[PATCH 3/3] ath10k: Support ethtool gstats2 API.

2018-04-17 Thread greearb
From: Ben Greear 

Skip a firmware stats update when calling
code indicates the stats refresh is not needed.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 18 +++---
 drivers/net/wireless/ath/ath10k/debug.h |  4 
 drivers/net/wireless/ath/ath10k/mac.c   |  1 +
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index bac832c..d559a3f 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1159,9 +1159,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw 
*hw,
return 0;
 }
 
-void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
-  struct ieee80211_vif *vif,
-  struct ethtool_stats *stats, u64 *data)
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 flags)
 {
struct ath10k *ar = hw->priv;
static const struct ath10k_fw_stats_pdev zero_stats = {};
@@ -1170,6 +1171,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
mutex_lock(>conf_mutex);
 
+   if (flags & ETHTOOL_GS2_SKIP_FW)
+   goto skip_query_fw_stats;
+
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_debug_fw_stats_request(ar);
if (ret) {
@@ -1180,6 +1184,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
}
}
 
+skip_query_fw_stats:
pdev_stats = list_first_entry_or_null(>debug.fw_stats.pdevs,
  struct ath10k_fw_stats_pdev,
  list);
@@ -1244,6 +1249,13 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH10K_SSTATS_LEN);
 }
 
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+  struct ieee80211_vif *vif,
+  struct ethtool_stats *stats, u64 *data)
+{
+   ath10k_debug_get_et_stats2(hw, vif, stats, data, 0);
+}
+
 static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 0afca5c..595d964 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -117,6 +117,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
 void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct ethtool_stats *stats, u64 *data);
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 level);
 
 static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index bf05a36..27b793c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7734,6 +7734,7 @@ static const struct ieee80211_ops ath10k_ops = {
.ampdu_action   = ath10k_ampdu_action,
.get_et_sset_count  = ath10k_debug_get_et_sset_count,
.get_et_stats   = ath10k_debug_get_et_stats,
+   .get_et_stats2  = ath10k_debug_get_et_stats2,
.get_et_strings = ath10k_debug_get_et_strings,
.add_chanctx= ath10k_mac_op_add_chanctx,
.remove_chanctx = ath10k_mac_op_remove_chanctx,
-- 
2.4.11



[PATCH 1/3] ethtool: Support ETHTOOL_GSTATS2 command.

2018-04-17 Thread greearb
From: Ben Greear 

This is similar to ETHTOOL_GSTATS, but it allows you to specify
flags.  These flags can be used by the driver to decrease the
amount of stats refreshed.  In particular, this helps with ath10k
since getting the firmware stats can be slow.

Signed-off-by: Ben Greear 
---
 include/linux/ethtool.h  | 12 
 include/uapi/linux/ethtool.h | 10 ++
 net/core/ethtool.c   | 40 +++-
 3 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index ebe4181..a4aa11f 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -243,6 +243,15 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
  * @get_ethtool_stats: Return extended statistics about the device.
  * This is only useful if the device maintains statistics not
  * included in  rtnl_link_stats64.
+ * @get_ethtool_stats2: Return extended statistics about the device.
+ * This is only useful if the device maintains statistics not
+ * included in  rtnl_link_stats64.
+ *  Takes a flags argument:  0 means all (same as get_ethtool_stats),
+ *  0x1 (ETHTOOL_GS2_SKIP_FW) means skip firmware stats.
+ *  Other flags are reserved for now.
+ *  Same number of stats will be returned, but some of them might
+ *  not be as accurate/refreshed.  This is to allow not querying
+ *  firmware or other expensive-to-read stats, for instance.
  * @begin: Function to be called before any other operation.  Returns a
  * negative error code or zero.
  * @complete: Function to be called after any other operation except
@@ -355,6 +364,9 @@ struct ethtool_ops {
int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
void(*get_ethtool_stats)(struct net_device *,
 struct ethtool_stats *, u64 *);
+   void(*get_ethtool_stats2)(struct net_device *dev,
+ struct ethtool_stats *gstats, u64 *data,
+ u32 flags);
int (*begin)(struct net_device *);
void(*complete)(struct net_device *);
u32 (*get_priv_flags)(struct net_device *);
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 4ca65b5..1c74f3e 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1396,11 +1396,21 @@ enum ethtool_fec_config_bits {
 #define ETHTOOL_PHY_STUNABLE   0x004f /* Set PHY tunable configuration */
 #define ETHTOOL_GFECPARAM  0x0050 /* Get FEC settings */
 #define ETHTOOL_SFECPARAM  0x0051 /* Set FEC settings */
+#define ETHTOOL_GSTATS20x0052 /* get NIC-specific 
statistics
+   * with ability to specify flags.
+   * See ETHTOOL_GS2* below.
+   */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET ETHTOOL_GSET
 #define SPARC_ETH_SSET ETHTOOL_SSET
 
+/* GSTATS2 flags */
+#define ETHTOOL_GS2_SKIP_NONE (0)/* default is to update all stats */
+#define ETHTOOL_GS2_SKIP_FW   (1<<0) /* Skip reading stats that probe firmware,
+ * and thus are slow/expensive.
+ */
+
 /* Link mode bit indices */
 enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_10baseT_Half_BIT  = 0,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 03416e6..6ec3413 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1952,16 +1952,14 @@ static int ethtool_phys_id(struct net_device *dev, void 
__user *useraddr)
return rc;
 }
 
-static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
+static int _ethtool_get_stats(struct net_device *dev, void __user *useraddr,
+ u32 flags)
 {
struct ethtool_stats stats;
const struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret, n_stats;
 
-   if (!ops->get_ethtool_stats || !ops->get_sset_count)
-   return -EOPNOTSUPP;
-
n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
if (n_stats < 0)
return n_stats;
@@ -1976,7 +1974,10 @@ static int ethtool_get_stats(struct net_device *dev, 
void __user *useraddr)
if (n_stats && !data)
return -ENOMEM;
 
-   ops->get_ethtool_stats(dev, , data);
+   if (flags != ETHTOOL_GS2_SKIP_NONE)
+   ops->get_ethtool_stats2(dev, , data, flags);
+   else
+   ops->get_ethtool_stats(dev, , data);
 
ret = -EFAULT;
if (copy_to_user(useraddr, , sizeof(stats)))
@@ -1991,6 +1992,31 @@ static int ethtool_get_stats(struct net_device *dev, 
void __user *useraddr)
return ret;
 }
 
+static int ethtool_get_stats(struct 

[RFC] ethtool: Support ETHTOOL_GSTATS2 command.

2018-03-07 Thread greearb
From: Ben Greear 

This is similar to ETHTOOL_GSTATS, but it allows you to specify
a 'level'.  This level can be used by the driver to decrease the
amount of stats refreshed.  In particular, this helps with ath10k
since getting the firmware stats can be slow.

Signed-off-by: Ben Greear 
---

NOTE:  I know to make it upstream I would need to split the patch and
remove the #define for 'backporting' that I added.  But, is the
feature in general wanted?  If so, I'll do the patch split and
other tweaks that might be suggested.

 drivers/net/wireless/ath/ath10k/debug.c | 18 ++--
 drivers/net/wireless/ath/ath10k/debug.h |  3 ++
 drivers/net/wireless/ath/ath10k/mac.c   |  3 ++
 include/linux/ethtool.h | 10 +++
 include/net/mac80211.h  |  6 
 include/uapi/linux/ethtool.h|  4 +++
 net/core/ethtool.c  | 52 +
 net/mac80211/driver-ops.h   |  9 --
 net/mac80211/ethtool.c  | 16 +++---
 9 files changed, 112 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 65e0a33..2545c24 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2389,9 +2389,9 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw 
*hw,
return 0;
 }
 
-void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
-  struct ieee80211_vif *vif,
-  struct ethtool_stats *stats, u64 *data)
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data, u32 
level)
 {
struct ath10k *ar = hw->priv;
static const struct ath10k_fw_stats_pdev zero_stats = {};
@@ -2401,6 +2401,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
mutex_lock(>conf_mutex);
 
+   if (level && level < 5)
+   goto skip_query_fw_stats;
+
if (ar->state == ATH10K_STATE_ON) {
ath10k_refresh_target_regs(ar); /* Request some CT FW stats. */
ret = ath10k_debug_fw_stats_request(ar);
@@ -2412,6 +2415,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
}
}
 
+skip_query_fw_stats:
pdev_stats = list_first_entry_or_null(>debug.fw_stats.pdevs,
  struct ath10k_fw_stats_pdev,
  list);
@@ -2497,6 +2501,14 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH10K_SSTATS_LEN);
 }
 
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+  struct ieee80211_vif *vif,
+  struct ethtool_stats *stats, u64 *data)
+{
+   ath10k_debug_get_et_stats2(hw, vif, stats, data, 0);
+}
+
+
 static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 74d1728..f33c88f 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -108,6 +108,9 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
 void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct ethtool_stats *stats, u64 *data);
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data, u32 
level);
 
 static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index e962c0e..eed0a9f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8472,6 +8472,9 @@ static const struct ieee80211_ops ath10k_ops = {
.ampdu_action   = ath10k_ampdu_action,
.get_et_sset_count  = ath10k_debug_get_et_sset_count,
.get_et_stats   = ath10k_debug_get_et_stats,
+#ifdef MAC80211_HAS_ET_STATS2
+   .get_et_stats2  = ath10k_debug_get_et_stats2,
+#endif
.get_et_strings = ath10k_debug_get_et_strings,
.add_chanctx= ath10k_mac_op_add_chanctx,
.remove_chanctx = ath10k_mac_op_remove_chanctx,
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 83cc986..9745175 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -221,6 +221,14 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
  * 

[PATCH v2] ethtool: Do not return error code if no changes were attempted.

2017-10-19 Thread greearb
From: Ben Greear 

This makes it easier to properly handle errors when calling this
from scripts, etc.

Old behaviour:

$ ethtool -L eth3 combined 1
combined unmodified, ignoring
no channel parameters changed, aborting
current values: tx 0 rx 0 other 1 combined 1
[root@lf0313-6477 ethtool]# echo $?
1

New behaviour:

$ ./ethtool -L eth3 combined 1
combined unmodified, ignoring
no channel parameters changed.
current values: tx 0 rx 0 other 1 combined 1
[root@lf0313-6477 ethtool]# echo $?
0

Signed-off-by: Ben Greear 
---

v2:  Fix comments, the # ./ethtool  was removed by git of course.

 ethtool.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index ad18704..224efdb 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1994,12 +1994,12 @@ static int do_schannels(struct cmd_context *ctx)
);
 
if (!changed) {
-   fprintf(stderr, "no channel parameters changed, aborting\n");
+   fprintf(stderr, "no channel parameters changed.\n");
fprintf(stderr, "current values: tx %u rx %u other %u"
" combined %u\n", echannels.rx_count,
echannels.tx_count, echannels.other_count,
echannels.combined_count);
-   return 1;
+   return 0;
}
 
echannels.cmd = ETHTOOL_SCHANNELS;
-- 
2.7.5



[PATCH] ethtool: Do not return error code if no changes were attempted.

2017-10-19 Thread greearb
From: Ben Greear 

This makes it easier to properly handle errors when calling this
from scripts, etc.

Old behaviour:

combined unmodified, ignoring
no channel parameters changed, aborting
current values: tx 0 rx 0 other 1 combined 1
[root@lf0313-6477 ethtool]# echo $?
1

New behaviour:

combined unmodified, ignoring
no channel parameters changed.
current values: tx 0 rx 0 other 1 combined 1
[root@lf0313-6477 ethtool]# echo $?
0

Signed-off-by: Ben Greear 
---
 ethtool.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index ad18704..224efdb 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1994,12 +1994,12 @@ static int do_schannels(struct cmd_context *ctx)
);
 
if (!changed) {
-   fprintf(stderr, "no channel parameters changed, aborting\n");
+   fprintf(stderr, "no channel parameters changed.\n");
fprintf(stderr, "current values: tx %u rx %u other %u"
" combined %u\n", echannels.rx_count,
echannels.tx_count, echannels.other_count,
echannels.combined_count);
-   return 1;
+   return 0;
}
 
echannels.cmd = ETHTOOL_SCHANNELS;
-- 
2.7.5



[PATCH] Fix build on fedora-14 (and other older systems)

2017-09-02 Thread greearb
From: Ben Greear 

Seems Fedora-20 and below fail, hopefully this fixes
them.

Signed-off-by: Ben Greear 
---
 include/linux/sysinfo.h | 8 
 ip/ipxfrm.c | 1 +
 ip/xfrm_policy.c| 1 +
 ip/xfrm_state.c | 1 +
 4 files changed, 11 insertions(+)

diff --git a/include/linux/sysinfo.h b/include/linux/sysinfo.h
index 934335a..3596b02 100644
--- a/include/linux/sysinfo.h
+++ b/include/linux/sysinfo.h
@@ -3,6 +3,14 @@
 
 #include 
 
+/* So we can compile on older OSs, hopefully this is correct. --Ben */
+#ifndef __kernel_long_t
+typedef long __kernel_long_t;
+#endif
+#ifndef __kernel_ulong_t
+typedef unsigned long __kernel_ulong_t;
+#endif
+
 #define SI_LOAD_SHIFT  16
 struct sysinfo {
__kernel_long_t uptime; /* Seconds since boot */
diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c
index 12c2f72..492a6af 100644
--- a/ip/ipxfrm.c
+++ b/ip/ipxfrm.c
@@ -38,6 +38,7 @@
 #include "utils.h"
 #include "xfrm.h"
 #include "ip_common.h"
+#include "xtables.h"
 
 #define STRBUF_SIZE(128)
 
diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
index de689c4..0f957c1 100644
--- a/ip/xfrm_policy.c
+++ b/ip/xfrm_policy.c
@@ -32,6 +32,7 @@
 #include "utils.h"
 #include "xfrm.h"
 #include "ip_common.h"
+#include "xtables.h"
 
 /* #define NLMSG_DELETEALL_BUF_SIZE (4096-512) */
 #define NLMSG_DELETEALL_BUF_SIZE 8192
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index 4483fb8..5a6a895 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -31,6 +31,7 @@
 #include "utils.h"
 #include "xfrm.h"
 #include "ip_common.h"
+#include "xtables.h"
 
 /* #define NLMSG_DELETEALL_BUF_SIZE (4096-512) */
 #define NLMSG_DELETEALL_BUF_SIZE 8192
-- 
2.4.11



[PATCH] igb: add module param to set max-rss-queues.

2017-03-24 Thread greearb
From: Ben Greear 

In systems where you may have a very large number of network
adapters, certain drivers may consume an unfair amount of
IRQ resources.  So, allow a module param that will limit the
number of IRQs at driver load time.  This way, other drivers
(40G Ethernet, for instance), which probably will need the
multiple IRQs more, will not be starved of IRQ resources.

Signed-off-by: Ben Greear 
---
 drivers/net/ethernet/intel/igb/igb_main.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/ethernet/intel/igb/igb_main.c 
b/drivers/net/ethernet/intel/igb/igb_main.c
index f9f2874..fdb12e0 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -218,6 +218,10 @@ module_param(max_vfs, uint, 0);
 MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate per 
physical function");
 #endif /* CONFIG_PCI_IOV */
 
+static unsigned int max_rss_qs;
+module_param(max_rss_qs, uint, 0);
+MODULE_PARM_DESC(max_rss_qs, "Maximum number of RSS queues.  Forcing lower 
will use less IRQ resources.");
+
 static pci_ers_result_t igb_io_error_detected(struct pci_dev *,
 pci_channel_state_t);
 static pci_ers_result_t igb_io_slot_reset(struct pci_dev *);
@@ -2993,6 +2997,9 @@ static void igb_init_queue_configuration(struct 
igb_adapter *adapter)
break;
}
 
+   if (max_rss_qs && max_rss_qs < max_rss_queues)
+   max_rss_queues = max_rss_qs;
+
adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus());
 
igb_set_flag_queue_pairs(adapter, max_rss_queues);
-- 
2.4.11



[PATCH-v2 2/2] mac80211: ensure association req uses configured ratemask.

2015-10-20 Thread greearb
From: Ben Greear 

When sending the association request, pay attention to the
legacy rates configured by the user, and do not advertise support
for any that are not configured.

This makes the assoc request packet look more correct when
making modern hardware act like a /b mode station, for instance.

Signed-off-by: Ben Greear 
---
 net/mac80211/ieee80211_i.h |  2 +-
 net/mac80211/mlme.c| 49 --
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5e43e99..e9fcdc2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -383,7 +383,7 @@ struct ieee80211_mgd_auth_data {
 
 struct ieee80211_mgd_assoc_data {
struct cfg80211_bss *bss;
-   const u8 *supp_rates;
+   u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 
unsigned long timeout;
int tries;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9651e92..fdcf863 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -635,6 +635,8 @@ static void ieee80211_send_assoc(struct 
ieee80211_sub_if_data *sdata)
 assoc_data->supp_rates_len,
 );
} else {
+   u32 msk = 
sdata->cfg_advert_bitrate_mask.control[chan->band].legacy;
+
/*
 * In case AP not provide any supported rates information
 * before association, we send information element(s) with
@@ -645,6 +647,9 @@ static void ieee80211_send_assoc(struct 
ieee80211_sub_if_data *sdata)
if ((rate_flags & sband->bitrates[i].flags)
!= rate_flags)
continue;
+   if (sdata->cfg_advert_bitrate_mask_set &&
+   (!(msk & (1 << i
+   continue;
rates |= BIT(i);
rates_len++;
}
@@ -4840,8 +4845,48 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data 
*sdata,
sdata->smps_mode = ifmgd->req_smps;
 
assoc_data->capability = req->bss->capability;
-   assoc_data->supp_rates = bss->supp_rates;
-   assoc_data->supp_rates_len = bss->supp_rates_len;
+   if (sdata->cfg_advert_bitrate_mask_set) {
+   int band = req->bss->channel->band;
+   u32 msk = sdata->cfg_advert_bitrate_mask.control[band].legacy;
+   u8 all_rates[12] = { 2, 4, 11, 22,
+12, 18, 24, 36, 48, 72, 96, 108 };
+   int i;
+   int q = 0;
+
+   /* Skip CCK rates for 5Ghz band */
+   if (band == IEEE80211_BAND_5GHZ)
+   msk = msk << 4;
+
+#if 0
+   pr_err("mgt-assoc, band: %d msk: 0x%x  bss-rates-len: %d\n",
+  band, msk, (int)(bss->supp_rates_len));
+   for (i = 0; i < bss->supp_rates_len; i++) {
+   pr_err("bss rate[%d] = %d (0x%x)\n",
+  i, bss->supp_rates[i], bss->supp_rates[i]);
+   }
+#endif
+   for (i = 0; i < 12; i++) {
+   int j;
+
+   if (!(msk & (1 << i)))
+   break;
+
+   for (j = 0; j < bss->supp_rates_len; j++) {
+   /* Mask out the 'basic-rate' flag, 0x80 */
+   if ((bss->supp_rates[j] & 0x7f) == 
all_rates[i]) {
+   assoc_data->supp_rates[q] =
+   bss->supp_rates[j];
+   q++;
+   break;
+   }
+   }
+   }
+   assoc_data->supp_rates_len = q;
+   } else {
+   memcpy(assoc_data->supp_rates, bss->supp_rates,
+  bss->supp_rates_len);
+   assoc_data->supp_rates_len = bss->supp_rates_len;
+   }
 
rcu_read_lock();
ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH-v2 1/2] mac80211: Take bitrates into account when building IEs.

2015-10-20 Thread greearb
From: Ben Greear 

If a user restricts the rateset for some reason, then the
probe requests should not advertise rates that are not
selected by the user.

To implement this, we save the requested bitrates at
the mac80211 level and take it into account when building
the IEs.

This allows one to create a more realistic /b mode
station on modern hardware, for instance.  Good for
testing, and likely good for other things as well.

Signed-off-by: Ben Greear 
---
v2:  Only save rates when given explicit flag from user-space.

 drivers/net/wireless/ath/ath6kl/cfg80211.c |  3 +-
 drivers/net/wireless/mwifiex/cfg80211.c|  3 +-
 include/net/cfg80211.h |  3 +-
 include/net/mac80211.h |  4 ++
 include/uapi/linux/nl80211.h   |  2 +
 net/mac80211/cfg.c |  9 ++-
 net/mac80211/ieee80211_i.h | 18 +-
 net/mac80211/scan.c| 26 +++-
 net/mac80211/util.c| 97 +++---
 net/wireless/nl80211.c |  5 +-
 net/wireless/rdev-ops.h|  6 +-
 net/wireless/wext-compat.c |  2 +-
 12 files changed, 160 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c 
b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index a511ef3..5b3d79e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3354,7 +3354,8 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
 static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
   struct net_device *dev,
   const u8 *addr,
-  const struct cfg80211_bitrate_mask *mask)
+  const struct cfg80211_bitrate_mask *mask,
+  bool is_advert_mask)
 {
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c 
b/drivers/net/wireless/mwifiex/cfg80211.c
index b15e4c7..7888916 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1542,7 +1542,8 @@ mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = {
 static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer,
-   const struct cfg80211_bitrate_mask *mask)
+   const struct cfg80211_bitrate_mask *mask,
+   bool is_advert_mask)
 {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 038de33..0804268 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2594,7 +2594,8 @@ struct cfg80211_ops {
int (*set_bitrate_mask)(struct wiphy *wiphy,
struct net_device *dev,
const u8 *peer,
-   const struct cfg80211_bitrate_mask *mask);
+   const struct cfg80211_bitrate_mask *mask,
+   bool is_advert_bitmask);
 
int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev,
int idx, struct survey_info *info);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6b1077c..970372d 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2073,10 +2073,14 @@ static inline void _ieee80211_hw_set(struct 
ieee80211_hw *hw,
  * struct ieee80211_scan_request - hw scan request
  *
  * @ies: pointers different parts of IEs (in req.ie)
+ * @disable_ht: Ensure nothing related to HT is in the probe request
+ * @disable_vht: Ensure nothing related to VHT is in the probe request
  * @req: cfg80211 request.
  */
 struct ieee80211_scan_request {
struct ieee80211_scan_ies ies;
+   bool disable_ht[IEEE80211_NUM_BANDS];
+   bool disable_vht[IEEE80211_NUM_BANDS];
 
/* Keep last */
struct cfg80211_scan_request req;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c0ab6b0..4573f87 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2130,6 +2130,8 @@ enum nl80211_attrs {
 
NL80211_ATTR_REG_INDOOR,
 
+   NL80211_ATTR_TX_ADVERT_RATEMASK,
+
/* add attributes here, update the policy in nl80211.c */
 
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bf7023f..0c0c5cf 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2457,12 +2457,19 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy 
*wiphy,
 static int