Netdev List
 help / color / mirror / Atom feed
* [PATCH V2 net 10/10] net: hns: bug fix about the overflow of mss
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Daode Huang <huangdaode@hisilicon.com>

When set MTU to the minimum value 68, there are increasing number
of error packets occur, which is caused by the overflowed value of
mss. This patch fix the bug.

Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index ef517af..71aa37b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -48,7 +48,6 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct sk_buff *skb;
-	int skb_tmp_len;
 	__be16 protocol;
 	u8 bn_pid = 0;
 	u8 rrcfv = 0;
@@ -94,13 +93,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 				hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
 
 				/* check for tcp/udp header */
-				if (iphdr->protocol == IPPROTO_TCP) {
+				if (iphdr->protocol == IPPROTO_TCP &&
+				    skb_is_gso(skb)) {
 					hnae_set_bit(tvsvsn,
 						     HNSV2_TXD_TSE_B, 1);
-					skb_tmp_len = SKB_TMP_LEN(skb);
 					l4_len = tcp_hdrlen(skb);
-					mss = mtu - skb_tmp_len - ETH_FCS_LEN;
-					paylen = skb->len - skb_tmp_len;
+					mss = skb_shinfo(skb)->gso_size;
+					paylen = skb->len - SKB_TMP_LEN(skb);
 				}
 			} else if (skb->protocol == htons(ETH_P_IPV6)) {
 				hnae_set_bit(tvsvsn, HNSV2_TXD_IPV6_B, 1);
@@ -108,13 +107,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 				hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
 
 				/* check for tcp/udp header */
-				if (ipv6hdr->nexthdr == IPPROTO_TCP) {
+				if (ipv6hdr->nexthdr == IPPROTO_TCP &&
+				    skb_is_gso(skb) && skb_is_gso_v6(skb)) {
 					hnae_set_bit(tvsvsn,
 						     HNSV2_TXD_TSE_B, 1);
-					skb_tmp_len = SKB_TMP_LEN(skb);
 					l4_len = tcp_hdrlen(skb);
-					mss = mtu - skb_tmp_len - ETH_FCS_LEN;
-					paylen = skb->len - skb_tmp_len;
+					mss = skb_shinfo(skb)->gso_size;
+					paylen = skb->len - SKB_TMP_LEN(skb);
 				}
 			}
 			desc->tx.ip_offset = ip_offset;
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 06/10] net: hns: fix return value of the function about rss
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Kejian Yan <yankejian@huawei.com>

Both .get_rxfh and .set_rxfh are always return 0, it should return result
from hardware when getting or setting rss. And the rss function should
return the correct data type.

Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
change log:
 PATCH V2:
  - fix the wrong casts:
    1) .get_rxfh_key_size and .get_rxfh_indir_size should return zero if
       not supported
    2) .get_rxfh and .set_rxfh should return negative error if not support

 PATCH V1:
  - first submit

 Link: https://lkml.org/lkml/2016/3/21/222
---
 drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c |  2 +-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c |  2 +-
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c  | 24 ++++++-----------------
 3 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index a7427b8..648b31a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -803,7 +803,7 @@ static int hns_ae_set_rss(struct hnae_handle *handle, const u32 *indir,
 
 	/* set the RSS Hash Key if specififed by the user */
 	if (key)
-		hns_ppe_set_rss_key(ppe_cb, (int *)key);
+		hns_ppe_set_rss_key(ppe_cb, (u32 *)key);
 
 	/* update the shadow RSS table with user specified qids */
 	memcpy(ppe_cb->rss_indir_table, indir, HNS_PPEV2_RSS_IND_TBL_SIZE);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index f302ef9..06422c2 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -27,7 +27,7 @@ void hns_ppe_set_tso_enable(struct hns_ppe_cb *ppe_cb, u32 value)
 void hns_ppe_set_rss_key(struct hns_ppe_cb *ppe_cb,
 			 const u32 rss_key[HNS_PPEV2_RSS_KEY_NUM])
 {
-	int key_item = 0;
+	u32 key_item;
 
 	for (key_item = 0; key_item < HNS_PPEV2_RSS_KEY_NUM; key_item++)
 		dsaf_write_dev(ppe_cb, PPEV2_RSS_KEY_REG + key_item * 0x4,
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index 3c4a3bc..2229905 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -1173,18 +1173,15 @@ hns_get_rss_key_size(struct net_device *netdev)
 {
 	struct hns_nic_priv *priv = netdev_priv(netdev);
 	struct hnae_ae_ops *ops;
-	u32 ret;
 
 	if (AE_IS_VER1(priv->enet_ver)) {
 		netdev_err(netdev,
 			   "RSS feature is not supported on this hardware\n");
-		return -EOPNOTSUPP;
+		return 0;
 	}
 
 	ops = priv->ae_handle->dev->ops;
-	ret = ops->get_rss_key_size(priv->ae_handle);
-
-	return ret;
+	return ops->get_rss_key_size(priv->ae_handle);
 }
 
 static u32
@@ -1192,18 +1189,15 @@ hns_get_rss_indir_size(struct net_device *netdev)
 {
 	struct hns_nic_priv *priv = netdev_priv(netdev);
 	struct hnae_ae_ops *ops;
-	u32 ret;
 
 	if (AE_IS_VER1(priv->enet_ver)) {
 		netdev_err(netdev,
 			   "RSS feature is not supported on this hardware\n");
-		return -EOPNOTSUPP;
+		return 0;
 	}
 
 	ops = priv->ae_handle->dev->ops;
-	ret = ops->get_rss_indir_size(priv->ae_handle);
-
-	return ret;
+	return ops->get_rss_indir_size(priv->ae_handle);
 }
 
 static int
@@ -1211,7 +1205,6 @@ hns_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
 {
 	struct hns_nic_priv *priv = netdev_priv(netdev);
 	struct hnae_ae_ops *ops;
-	int ret;
 
 	if (AE_IS_VER1(priv->enet_ver)) {
 		netdev_err(netdev,
@@ -1224,9 +1217,7 @@ hns_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
 	if (!indir)
 		return 0;
 
-	ret = ops->get_rss(priv->ae_handle, indir, key, hfunc);
-
-	return 0;
+	return ops->get_rss(priv->ae_handle, indir, key, hfunc);
 }
 
 static int
@@ -1235,7 +1226,6 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
 {
 	struct hns_nic_priv *priv = netdev_priv(netdev);
 	struct hnae_ae_ops *ops;
-	int ret;
 
 	if (AE_IS_VER1(priv->enet_ver)) {
 		netdev_err(netdev,
@@ -1252,9 +1242,7 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
 	if (!indir)
 		return 0;
 
-	ret = ops->set_rss(priv->ae_handle, indir, key, hfunc);
-
-	return 0;
+	return ops->set_rss(priv->ae_handle, indir, key, hfunc);
 }
 
 static struct ethtool_ops hns_ethtool_ops = {
-- 
1.9.1

^ permalink raw reply related

* Re: [patch iproute2 2/2] add devlink tool
From: Jiri Pirko @ 2016-03-22  7:15 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: netdev, davem, idosch, eladr, yotamg, ogerlitz, yishaih, dledford,
	sean.hefty, hal.rosenstock, eugenia, roopa, nikolay, hadarh, jhs,
	john.fastabend, jeffrey.t.kirsher, brouer, ivecera, rami.rosen,
	hannes, gospo
In-Reply-To: <20160321122040.0f0788ff@xeon-e3>

Mon, Mar 21, 2016 at 08:20:40PM CET, stephen@networkplumber.org wrote:
>On Tue, 15 Mar 2016 15:43:49 +0100
>Jiri Pirko <jiri@resnulli.us> wrote:
>
>> From: Jiri Pirko <jiri@mellanox.com>
>> 
>> Add new tool called devlink which is userspace counterpart of devlink
>> Netlink socket.
>> 
>> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
>
>Lots of checkpatch issues.

Oops, I didn't realize you have that in iproute2 as well. Will fix.
Thanks.


>
>
>ERROR: code indent should use tabs where possible
>#509: FILE: devlink/devlink.c:161:
>+                return -1;$
>
>WARNING: please, no spaces at the start of a line
>#509: FILE: devlink/devlink.c:161:
>+                return -1;$
>
>ERROR: open brace '{' following function declarations go on the next line
>#854: FILE: devlink/devlink.c:506:
>+static void cmd_dev_help(void) {
>
>WARNING: else is not generally useful after a break or return
>#911: FILE: devlink/devlink.c:563:
>+		return cmd_dev_show(dl);
>+	} else {
>
>ERROR: open brace '{' following function declarations go on the next line
>#918: FILE: devlink/devlink.c:570:
>+static void cmd_port_help(void) {
>
>WARNING: line over 100 characters
>#945: FILE: devlink/devlink.c:597:
>+			uint16_t des_port_type = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]);
>
>WARNING: else is not generally useful after a break or return
>#1059: FILE: devlink/devlink.c:711:
>+		return cmd_port_unsplit(dl);
>+	} else {
>
>WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
>#1108: FILE: devlink/devlink.c:760:
>+	unsigned index = 0;
>
>WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
>#1159: FILE: devlink/devlink.c:811:
>+	unsigned index = 0;
>
>ERROR: open brace '{' following function declarations go on the next line
>#1179: FILE: devlink/devlink.c:831:
>+static void cmd_mon_help(void) {
>
>WARNING: else is not generally useful after a break or return
>#1192: FILE: devlink/devlink.c:844:
>+		return cmd_mon_show(dl);
>+	} else {
>
>ERROR: open brace '{' following function declarations go on the next line
>#1199: FILE: devlink/devlink.c:851:
>+static void help(void) {
>
>WARNING: else is not generally useful after a break or return
>#1219: FILE: devlink/devlink.c:871:
>+		return cmd_mon(dl);
>+	} else {
>
>ERROR: space required before the open parenthesis '('
>#1286: FILE: devlink/devlink.c:938:
>+		switch(opt) {
>
>ERROR: space required before the open parenthesis '('
>#1426: FILE: devlink/mnlg.c:93:
>+	switch(type) {
>
>WARNING: 'splitted' may be misspelled - perhaps 'split'?
>#1909: FILE: man/man8/devlink-port.8:79:
>+.SS devlink port unsplit - unsplit previously splitted devlink port
>
>WARNING: 'splitted' may be misspelled - perhaps 'split'?
>#1910: FILE: man/man8/devlink-port.8:80:
>+Could be performed on any splitted port of the same split group.
>
>WARNING: 'splitted' may be misspelled - perhaps 'split'?
>#1947: FILE: man/man8/devlink-port.8:117:
>+Unplit the specified previously splitted devlink port.

^ permalink raw reply

* [PATCH] ath9k: fix checkpatch.pl identation and sapce errors.
From: Ashwini Singh @ 2016-03-22  6:53 UTC (permalink / raw)
  To: ath9k-devel-A+ZNKFmMK5xy9aJCnZT0Uw, kvalo-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	ath9k-devel-juf53994utBLZpfksSYvnA, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Rajeev_Kumar-nmGgyN9QBj3QT0dZR+AlfA, Ashwini Singh

Signed-off-by: Ashwini Singh <Ashwini_Singh-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org>
---
 drivers/net/wireless/ath/ath9k/ani.c            |    2 +-
 drivers/net/wireless/ath/ath9k/antenna.c        |    2 +-
 drivers/net/wireless/ath/ath9k/ar9002_hw.c      |    2 +-
 drivers/net/wireless/ath/ath9k/ar9002_phy.c     |    2 +-
 drivers/net/wireless/ath/ath9k/ar9003_aic.c     |    2 +-
 drivers/net/wireless/ath/ath9k/ar9003_calib.c   |   20 ++++++++++----------
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c  |    8 ++++----
 drivers/net/wireless/ath/ath9k/ar9003_mci.c     |    2 +-
 drivers/net/wireless/ath/ath9k/ar9003_phy.c     |    4 ++--
 drivers/net/wireless/ath/ath9k/ar9003_rtt.c     |    2 +-
 drivers/net/wireless/ath/ath9k/ar9003_wow.c     |   12 ++++++------
 drivers/net/wireless/ath/ath9k/ath9k.h          |    6 +++---
 drivers/net/wireless/ath/ath9k/beacon.c         |    6 +++---
 drivers/net/wireless/ath/ath9k/common-init.c    |    2 +-
 drivers/net/wireless/ath/ath9k/common.c         |    2 +-
 drivers/net/wireless/ath/ath9k/eeprom.c         |    4 ++--
 drivers/net/wireless/ath/ath9k/eeprom_4k.c      |    2 +-
 drivers/net/wireless/ath/ath9k/eeprom_def.c     |    4 ++--
 drivers/net/wireless/ath/ath9k/htc_drv_beacon.c |    2 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c   |    2 +-
 drivers/net/wireless/ath/ath9k/hw.c             |    9 ++++-----
 drivers/net/wireless/ath/ath9k/init.c           |    4 ++--
 drivers/net/wireless/ath/ath9k/reg_mci.h        |   14 +++++++-------
 drivers/net/wireless/ath/ath9k/reg_wow.h        |   14 +++++++-------
 drivers/net/wireless/ath/ath9k/xmit.c           |   12 ++++++------
 25 files changed, 70 insertions(+), 71 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 815efe9..6bbf80b 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -432,7 +432,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
 			aniState->ofdmsTurn = true;
 		} else
 			return;
-			
+
 		ath9k_ani_restart(ah);
 	}
 }
diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c
index a366843..c6b4ec7 100644
--- a/drivers/net/wireless/ath/ath9k/antenna.c
+++ b/drivers/net/wireless/ath/ath9k/antenna.c
@@ -314,7 +314,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
 		antcomb->rssi_first = main_rssi_avg;
 		antcomb->rssi_third = alt_rssi_avg;
 
-		switch(antcomb->second_quick_scan_conf) {
+		switch (antcomb->second_quick_scan_conf) {
 		case ATH_ANT_DIV_COMB_LNA1:
 			antcomb->rssi_lna1 = alt_rssi_avg;
 			break;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index d480d2f..b5db5f1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -92,7 +92,7 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
 
 		if (!AR_SREV_5416_22_OR_LATER(ah)) {
 			/* override CLKDRV value */
-			INI_RA(addac, 31,1) = 0;
+			INI_RA(addac, 31, 1) = 0;
 		}
 	}
 	if (AR_SREV_9287_11_OR_LATER(ah)) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index db66245..298e621 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -458,7 +458,7 @@ static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
 
 	regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
 	regval &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
-        /*
+	/*
 	 * Clear ant_fast_div_bias [14:9] since for WB195,
 	 * the main LNA is always LNA1.
 	 */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index 547cd46..e12a712 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -363,7 +363,7 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
 				(start_idx - end_idx) +
 				aic_sram[start_idx].quad_path_gain_lin;
 
-		} else if (start_idx >= 0){
+		} else if (start_idx >= 0) {
 			/* interpolation */
 			aic_sram[i].dir_path_gain_lin =
 				(((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) +
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 0c39199..1ff5424 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -700,15 +700,15 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
 	}
 
 	if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) ||
-            (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
-            (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
-            (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
-            (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
-            (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
-            (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
-            (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
-            (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
-            (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
+	    (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
+	    (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
+	    (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
+	    (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
+	    (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
+	    (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
+	    (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
+	    (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
+	    (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
 		return false;
 	}
 
@@ -1327,7 +1327,7 @@ static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah,
 		set_bit(SW_PKDET_DONE, &caldata->cal_flags);
 
 	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) {
-		if (IS_CHAN_2GHZ(chan)){
+		if (IS_CHAN_2GHZ(chan)) {
 			caldata->caldac[0] = REG_READ_FIELD(ah,
 						    AR_PHY_65NM_RXRF_AGC(0),
 						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 54ed2f7..18e17771 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -2080,7 +2080,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
 		.tempSlopeLow = 72,
 		.tempSlopeHigh = 105,
 		.xatten1DBLow = {0x10, 0x14, 0x10},
-		.xatten1MarginLow = {0x19, 0x19 , 0x19},
+		.xatten1MarginLow = {0x19, 0x19, 0x19},
 		.xatten1DBHigh = {0x1d, 0x20, 0x24},
 		.xatten1MarginHigh = {0x10, 0x10, 0x10}
 	},
@@ -4441,9 +4441,9 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
 		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
 	    );
 
-        /* Write the power for duplicated frames - HT40 */
+	/* Write the power for duplicated frames - HT40 */
 
-        /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
+	/* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
 	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8),
 		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
 		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
@@ -5340,7 +5340,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
 	unsigned int i = 0, paprd_scale_factor = 0;
 	u8 pwr_idx, min_pwridx = 0;
 
-	memset(targetPowerValT2, 0 , sizeof(targetPowerValT2));
+	memset(targetPowerValT2, 0, sizeof(targetPowerValT2));
 
 	/*
 	 * Get target powers from EEPROM - our baseline for TX Power
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index af5ee41..99bc134 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -890,7 +890,7 @@ static void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah)
 {
 	u32 regval;
 
-        regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
+	regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
 		 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
 		 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
 		 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 06c1ca6..5495d0e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -518,7 +518,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
 
 	} else {
 		spur_subchannel_sd = 0;
-		spur_freq_sd = (freq_offset << 9) /11;
+		spur_freq_sd = (freq_offset << 9) / 11;
 		spur_delta_phase = (freq_offset << 18) / 5;
 	}
 
@@ -2087,7 +2087,7 @@ bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah)
 {
 	u32 val;
 
-	switch(ah->bb_watchdog_last_status) {
+	switch (ah->bb_watchdog_last_status) {
 	case 0x04000539:
 		val = REG_READ(ah, AR_PHY_RADAR_0);
 		val &= (~AR_PHY_RADAR_0_FIRPWR);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
index e4d11fa..e07d20a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
@@ -211,7 +211,7 @@ bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
 		return false;
 
 	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) {
-		if (IS_CHAN_2GHZ(chan)){
+		if (IS_CHAN_2GHZ(chan)) {
 			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
 				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
 				      ah->caldata->caldac[0]);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
index bea41df9..44d65f5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
@@ -52,7 +52,7 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
 	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
 		if (!REG_READ(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL))
 			REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE);
-	} else if (AR_SREV_9485(ah)){
+	} else if (AR_SREV_9485(ah)) {
 		if (!(REG_READ(ah, AR_NDP2_TIMER_MODE) &
 		      AR_GEN_TIMERS2_MODE_ENABLE_MASK))
 			REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE);
@@ -310,9 +310,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
 	 * to generate next wow signal.
 	 */
 	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_HOST_PME_EN |
-		    			 AR_PMCTRL_PWR_PM_CTRL_ENA |
-		    			 AR_PMCTRL_AUX_PWR_DET |
-		    			 AR_PMCTRL_WOW_PME_CLR);
+					 AR_PMCTRL_PWR_PM_CTRL_ENA |
+					 AR_PMCTRL_AUX_PWR_DET |
+					 AR_PMCTRL_WOW_PME_CLR);
 	REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR);
 
 	/*
@@ -330,8 +330,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
 	 * AIFS time, Slot time, Keep Alive count.
 	 */
 	REG_SET_BIT(ah, AR_WOW_COUNT, AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
-		    		      AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
-		    		      AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT));
+				      AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
+				      AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT));
 	/*
 	 * Beacon timeout.
 	 */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5294595..9fef8b5 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -139,8 +139,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 
 /* returns delimiter padding required given the packet length */
 #define ATH_AGGR_GET_NDELIM(_len)					\
-       (((_len) >= ATH_AGGR_MINPLEN) ? 0 :                             \
-        DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ))
+	(((_len) >= ATH_AGGR_MINPLEN) ? 0 :                             \
+	DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ))
 
 #define BAW_WITHIN(_start, _bawsz, _seqno) \
 	((((_seqno) - (_start)) & 4095) < (_bawsz))
@@ -661,7 +661,7 @@ void ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif);
 #define ATH_DEFAULT_BINTVAL     	100 /* TU */
 #define ATH_DEFAULT_BMISS_LIMIT 	10
 
-#define TSF_TO_TU(_h,_l) \
+#define TSF_TO_TU(_h, _l) \
 	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
 struct ath_beacon {
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 5cf0cd7..8c066f7 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -265,7 +265,7 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
 	intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
 	tsf = ath9k_hw_gettsf64(sc->sc_ah);
 	tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
-	tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
+	tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >> 32, tsf * ATH_BCBUF);
 	slot = (tsftu % (intval * ATH_BCBUF)) / intval;
 
 	ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
@@ -586,8 +586,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
 			 u32 changed)
 {
 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-        struct ath_hw *ah = sc->sc_ah;
-        struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
 	struct ath_chanctx *ctx = avp->chanctx;
 	struct ath_beacon_config *cur_conf;
diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c
index a006c14..f010ab2 100644
--- a/drivers/net/wireless/ath/ath9k/common-init.c
+++ b/drivers/net/wireless/ath/ath9k/common-init.c
@@ -90,7 +90,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
 
 /* Atheros hardware rate code addition for short premble */
 #define SHPCHECK(__hw_rate, __flags) \
-	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
 
 #define RATE(_bitrate, _hw_rate, _flags) {              \
 	.bitrate        = (_bitrate),                   \
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index e8c6994..15c4084 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -142,7 +142,7 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
 	 * not try to remove padding from short control frames that do
 	 * not have payload. */
 	padsize = padpos & 3;
-	if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+	if (padsize && skb->len >= padpos+padsize+FCS_LEN) {
 		memmove(skb->data + padsize, skb->data, padpos);
 		skb_pull(skb, padsize);
 	}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index a794157..5444fa5 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -18,9 +18,9 @@
 
 void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
 {
-        REG_WRITE(ah, reg, val);
+	REG_WRITE(ah, reg, val);
 
-        if (ah->config.analog_shiftreg)
+	if (ah->config.analog_shiftreg)
 		udelay(100);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 5da0826..10d16f8 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -415,7 +415,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
 						 u16 powerLimit)
 {
 #define CMP_TEST_GRP \
-	(((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) ==	\
+	(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) ==	\
 	 pEepData->ctlIndex[i])						\
 	|| (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
 	    ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 959682f..52d41cb 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -454,7 +454,7 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah,
 			      pModal->xatten2Db[i]);
 		} else {
 			REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
-				SM(pModal-> bswMargin[i], AR_PHY_GAIN_2GHZ_BSW_MARGIN),
+				SM(pModal->bswMargin[i], AR_PHY_GAIN_2GHZ_BSW_MARGIN),
 				AR_PHY_GAIN_2GHZ_BSW_MARGIN);
 			REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
 				SM(pModal->bswAtten[i], AR_PHY_GAIN_2GHZ_BSW_ATTEN),
@@ -759,7 +759,7 @@ static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
 	if (AR_SREV_9280_20_OR_LATER(ah)) {
 		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
 			/* shift the table to start at the new offset */
-			for (k = 0; k < (u16)NUM_PDADC(diff); k++ ) {
+			for (k = 0; k < (u16)NUM_PDADC(diff); k++) {
 				pdadcValues[k] = pdadcValues[k + diff];
 			}
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index e6bcb4c..df8efa7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -149,7 +149,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
 
 	skb = ieee80211_get_buffered_bc(priv->hw, vif);
 
-	while(skb) {
+	while (skb) {
 		hdr = (struct ieee80211_hdr *) skb->data;
 
 		padpos = ieee80211_hdrlen(hdr->frame_control);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 8647ab7..833a7c4 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -267,7 +267,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
        }
 
        ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
-			   (u8 *)tmpaddr , sizeof(u32) * count,
+			   (u8 *)tmpaddr, sizeof(u32) * count,
 			   (u8 *)tmpval, sizeof(u32) * count,
 			   100);
 	if (unlikely(ret)) {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index e7a3101..7698478 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2909,7 +2909,7 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah)
 		tsf_upper1 = tsf_upper2;
 	}
 
-	WARN_ON( i == ATH9K_MAX_TSF_READ );
+	WARN_ON(i == ATH9K_MAX_TSF_READ);
 
 	return (((u64)tsf_upper1 << 32) | tsf_lower);
 }
@@ -2956,8 +2956,7 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan)
 
 /* HW Generic timers configuration */
 
-static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
-{
+static const struct ath_gen_timer_configuration gen_tmr_configuration[] = {
 	{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
 	{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
 	{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
@@ -3216,7 +3215,7 @@ static const char *ath9k_hw_mac_bb_name(u32 mac_bb_version)
 {
 	int i;
 
-	for (i=0; i<ARRAY_SIZE(ath_mac_bb_names); i++) {
+	for (i = 0; i < ARRAY_SIZE(ath_mac_bb_names); i++) {
 		if (ath_mac_bb_names[i].version == mac_bb_version) {
 			return ath_mac_bb_names[i].name;
 		}
@@ -3233,7 +3232,7 @@ static const char *ath9k_hw_rf_name(u16 rf_version)
 {
 	int i;
 
-	for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) {
+	for (i = 0; i < ARRAY_SIZE(ath_rf_names); i++) {
 		if (ath_rf_names[i].version == rf_version) {
 			return ath_rf_names[i].name;
 		}
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1c226d6..adce9c0 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -142,7 +142,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
 }
 
 static void ath9k_multi_ioread32(void *hw_priv, u32 *addr,
-                                u32 *val, u16 count)
+				 u32 *val, u16 count)
 {
 	int i;
 
@@ -785,7 +785,7 @@ static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 	ieee80211_hw_set(hw, QUEUE_CONTROL);
 	hw->queues = ATH9K_NUM_TX_QUEUES;
 	hw->offchannel_tx_hw_queue = hw->queues - 1;
-	hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
+	hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_WDS);
 	hw->wiphy->iface_combinations = if_comb_multi;
 	hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
 	hw->wiphy->max_scan_ssids = 255;
diff --git a/drivers/net/wireless/ath/ath9k/reg_mci.h b/drivers/net/wireless/ath/ath9k/reg_mci.h
index 6251310..83c9a9c 100644
--- a/drivers/net/wireless/ath/ath9k/reg_mci.h
+++ b/drivers/net/wireless/ath/ath9k/reg_mci.h
@@ -290,9 +290,9 @@
 				  AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)
 
 #define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \
-                                        AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \
-                                        AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \
-                                        AR_MCI_INTERRUPT_TX_SW_MSG_FAIL)
+					AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \
+					AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \
+					AR_MCI_INTERRUPT_TX_SW_MSG_FAIL)
 
 #define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO   | \
 					 AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \
@@ -302,9 +302,9 @@
 					 AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
 
 #define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM           | \
-                                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET  | \
-                                         AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING    | \
-                                         AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING  | \
-                                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
+					 AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET  | \
+					 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING    | \
+					 AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING  | \
+					 AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
 
 #endif /* REG_MCI_H */
diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h
index 4530540..58f7569 100644
--- a/drivers/net/wireless/ath/ath9k/reg_wow.h
+++ b/drivers/net/wireless/ath/ath9k/reg_wow.h
@@ -81,14 +81,14 @@
 #define AR_WOW_BEACON_FAIL              0x00200000
 
 #define AR_WOW_STATUS(x)                (x & (AR_WOW_PATTERN_FOUND_MASK | \
-                                              AR_WOW_MAGIC_PAT_FOUND    | \
-                                              AR_WOW_KEEP_ALIVE_FAIL    | \
-                                              AR_WOW_BEACON_FAIL))
+					      AR_WOW_MAGIC_PAT_FOUND    | \
+					      AR_WOW_KEEP_ALIVE_FAIL    | \
+					      AR_WOW_BEACON_FAIL))
 #define AR_WOW_CLEAR_EVENTS(x)          (x & ~(AR_WOW_PATTERN_EN(0xff) | \
-                                               AR_WOW_MAGIC_EN |	\
-                                               AR_WOW_MAC_INTR_EN |	\
-                                               AR_WOW_BEACON_FAIL |	\
-                                               AR_WOW_KEEP_ALIVE_FAIL))
+					       AR_WOW_MAGIC_EN |	\
+					       AR_WOW_MAC_INTR_EN |	\
+					       AR_WOW_BEACON_FAIL |	\
+					       AR_WOW_KEEP_ALIVE_FAIL))
 
 #define AR_WOW2_PATTERN_EN(x)           ((x & 0xff) << 0)
 #define AR_WOW2_PATTERN_FOUND_SHIFT     8
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index fe795fc..7efbdf0 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -393,8 +393,8 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
 }
 
 static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
-			        struct ath_tx_status *ts, int txok,
-			        int *nframes, int *nbad)
+				struct ath_tx_status *ts, int txok,
+				int *nframes, int *nbad)
 {
 	struct ath_frame_info *fi;
 	u16 seq_st = 0;
@@ -2259,7 +2259,7 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
 	ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb);
 
 	if ((vif && vif->type != NL80211_IFTYPE_AP &&
-	            vif->type != NL80211_IFTYPE_AP_VLAN) ||
+		    vif->type != NL80211_IFTYPE_AP_VLAN) ||
 	    !ieee80211_is_data(hdr->frame_control))
 		info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
 
@@ -2443,7 +2443,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			break;
 
 		skb = ieee80211_get_buffered_bc(hw, vif);
-	} while(skb);
+	} while (skb);
 
 	if (skb)
 		ieee80211_free_txskb(hw, skb);
@@ -2494,7 +2494,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 
 	padpos = ieee80211_hdrlen(hdr->frame_control);
 	padsize = padpos & 3;
-	if (padsize && skb->len>padpos+padsize) {
+	if (padsize && skb->len > padpos+padsize) {
 		/*
 		 * Remove MAC header padding before giving the frame back to
 		 * mac80211.
@@ -2604,7 +2604,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
 		 * This itself should also alleviate congestion on the bus.
 		 */
 		if (unlikely(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
-		                             ATH9K_TX_DELIM_UNDERRUN)) &&
+					     ATH9K_TX_DELIM_UNDERRUN)) &&
 		    ieee80211_is_data(hdr->frame_control) &&
 		    ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
 			tx_info->status.rates[tx_rateindex].count =
-- 
1.7.9.5

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

^ permalink raw reply related

* Re: [Make-wifi-fast] [RFCv2 1/3] mac80211: implement fq_codel for software queuing
From: Michal Kazior @ 2016-03-22  6:51 UTC (permalink / raw)
  To: David Lang
  Cc: Emmanuel Grumbach, Network Development, linux-wireless,
	ath10k@lists.infradead.org, codel, make-wifi-fast, Johannes Berg,
	Tim Shepard
In-Reply-To: <alpine.DEB.2.02.1603211830000.26766@nftneq.ynat.uz>

On 22 March 2016 at 02:35, David Lang <david@lang.hm> wrote:
> On Wed, 16 Mar 2016, Michal Kazior wrote:
>
>> Since 11n aggregation become important to get the
>> best out of txops. However aggregation inherently
>> requires buffering and queuing. Once variable
>> medium conditions to different associated stations
>> is considered it became apparent that bufferbloat
>> can't be simply fought with qdiscs for wireless
>> drivers.
>
> If the network is quiet enough, don't do any buffering, but in almost all
> situations you are going to need to buffer starting no later than the second
> packet you try to send.
>
> Don't try to make queueing occur, just deal with the queues that form
> naturally because you can't transmit data any faster (and work to keep them
> under some semblence of control)
[...]

This is what already happens. Queues typically start to build up when
hardware tx fifos/queues become busy so by the time they become
available you might have a bunch of frames you can aggregate.

The patch is more about getting rid of qdiscs because it's inherently
hard to teach them how 802.11 aggregation works (per-station per-tid)
and the ever-changing nature of per-station tx conditions.

I'll update the commit log to better reflect what is being done.


Michał
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel

^ permalink raw reply

* Re: [PATCH] ipv6: Fix the pmtu path for connected UDP socket
From: Martin KaFai Lau @ 2016-03-22  6:02 UTC (permalink / raw)
  To: Wei Wang
  Cc: Cong Wang, Wei Wang, Eric Dumazet, David Miller, Eric Dumazet,
	Linux Kernel Network Developers
In-Reply-To: <CAC15z3ikqBc3CcgNaUJkaD1ZiBbwqZFkjEsgR7_F9Q1dvZ2Zvw@mail.gmail.com>

On Mon, Mar 21, 2016 at 10:13:41AM -0700, Wei Wang wrote:
> Hey Cong,
>
> This solution probably will not work.
> First of all, if you look into __ip6_rt_update_pmtu(), it creates a
> new dst and this dst does not get passed back to its caller. So unless
> we tweak this function to pass the new dst back, we can only update
> sk->sk_dst_cache inside the function itself.
> Secondly, ip6_update_pmtu is called in multiple places. Not only here.
> I am not sure how many places need to be changed like this. It seems
> not a good thing to do.
>
> Thanks.
> Wei
>
> On Fri, Mar 18, 2016 at 3:09 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> > On Fri, Mar 18, 2016 at 2:26 PM, Wei Wang <tracywwnj@gmail.com> wrote:
> >> I don't think ip6_sk_update_pmtu() is a good place to put it as all it
> >> does is to call ip6_update_pmtu(). And ip6_update_pmtu() does the
> >> route lookup and call __ip6_rt_update_pmtu.
> >> We can put it in ip6_update_pmtu(). But that still means we need to
> >> pass sk to ip6_update_pmtu() and I don't think it makes any difference
> >> compared to the current fix.
I think Cong Wang is suggesting, in ip6_sk_update_pmtu():
1. call ip6_upate_pmtu() as it is
2. do a dst_check()
3. re-lookup() if it is invalid
4. and then do a ip6_dst_store()/dst_set

The above is exactly what inet6_csk_update_pmtu(), which was also used in the
first patch, is doing.

In term of difference, AFAICT, the current patch is an optimization in the
sense that the update_pmtu() code path does not have to do a dst_check to
discover its sk->sk_dst_cache is invalid, and then do a relookup to find out
that the just created RTF_CACHE clone should be used.  To get this, it may
make more sense to remove all the relookup code together during update_pmtu().
Even if this slow path was to be optimized, should it be put in a
separate patch where net-next is a better candidate?

I think fixing it in __udp6_lib_err() or what Cong Wang is suggesting makes
more sense for a net branch fix.  If there is logic specific to connected-udp,
I would do it in the __udp6_lib_err() instead.  After looking at
udpv6_sendmsg() and how it calls ip6_dst_store(), may also need to be careful
what daddr and saddr should be passed to ip6_dst_store(), or at least a commit
message.  The first patch is essentially passing NULL to daddr and saddr
while the second patch seems passing something else.

> >>
> >
> > Well, your patch touches all the callers of ip6_update_pmtu() , if you just
> > fix ip6_sk_update_pmtu() as I suggested, you only need to change one
> > function, ideally. And the ipv4 code is there, although I am not sure, it
> > looks like we can just mimic the logic here:
> >
> > diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> > index ed44663..b88c2ff 100644
> > --- a/net/ipv6/route.c
> > +++ b/net/ipv6/route.c
> > @@ -1417,8 +1417,28 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu);
> >
> >  void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
> >  {
> > -       ip6_update_pmtu(skb, sock_net(sk), mtu,
> > -                       sk->sk_bound_dev_if, sk->sk_mark);
> > +       const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
> > +       struct net *net = sock_net(sk);
> > +       struct dst_entry *dst;
> > +       struct flowi6 fl6;
> > +
> > +       bh_lock_sock(sk);
> > +
> > +       memset(&fl6, 0, sizeof(fl6));
> > +       fl6.flowi6_oif = sk->sk_bound_dev_if;
> > +       fl6.flowi6_mark = sk->sk_mark ? : IP6_REPLY_MARK(net, skb->mark);
> > +       fl6.daddr = iph->daddr;
> > +       fl6.saddr = iph->saddr;
> > +       fl6.flowlabel = ip6_flowinfo(iph);
> > +
> > +       dst = ip6_route_output(net, NULL, &fl6);
> > +       if (!dst->error)
> > +               __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
> > +
> > +       sk_dst_set(sk, &rt->dst);
> > +       bh_unlock_sock(sk);
> > +
> > +       dst_release(dst);
> >  }
> >
> >
> > Please don't judge me on the code, it could still miss a lot of things,
> > but it can show my idea...

^ permalink raw reply

* Re: [PATCH v2] mwifiex: advertise low priority scan feature
From: Wei-Ning Huang @ 2016-03-22  4:12 UTC (permalink / raw)
  To: Linux Wireless
  Cc: LKML, Amitkumar Karwar, Daniel Kurtz, Wei-Ning Huang,
	Nishant Sarmukadam, Kalle Valo, netdev
In-Reply-To: <1458619796-7694-1-git-send-email-wnhuang@chromium.org>

Tested-by: Wei-Ning Huang <wnhuang@chromium.org>

On Tue, Mar 22, 2016 at 12:09 PM, Wei-Ning Huang <wnhuang@chromium.org> wrote:
> From: Amitkumar Karwar <akarwar@marvell.com>
>
> Low priority scan handling code which delays or aborts scan
> operation based on Tx traffic is removed recently. The reason
> is firmware already takes care of it in our new feature scan
> channel gap. Hence we should advertise low priority scan
> support to cfg80211.
>
> This patch fixes a problem in which OBSS scan request from
> wpa_supplicant was being rejected by cfg80211.
>
> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> Signed-off-by: Wei-Ning Huang <wnhuang@chromium.org>
> ---
>  drivers/net/wireless/marvell/mwifiex/cfg80211.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> index bb7235e..7dafc5b 100644
> --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> @@ -4086,6 +4086,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
>
>         wiphy->features |= NL80211_FEATURE_HT_IBSS |
>                            NL80211_FEATURE_INACTIVITY_TIMER |
> +                          NL80211_FEATURE_LOW_PRIORITY_SCAN |
>                            NL80211_FEATURE_NEED_OBSS_SCAN;
>
>         if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
> --
> 2.8.0.rc3.226.g39d4020
>



-- 
Wei-Ning Huang, 黃偉寧 | Software Engineer, Google Inc., Taiwan |
wnhuang@google.com | Cell: +886 910-380678

^ permalink raw reply

* Re: [PATCH] mwifiex: advertise low priority scan feature
From: Wei-Ning Huang @ 2016-03-22  4:12 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Linux Wireless, LKML, Amitkumar Karwar, Daniel Kurtz,
	Nishant Sarmukadam, netdev
In-Reply-To: <87d1qogm50.fsf@kamboji.qca.qualcomm.com>

Hi Kalle,

Thanks for the review. I accidentally removed the s-o-b line from
akarwar in this version.
The original patch can be found at:
https://chromium-review.googlesource.com/#/c/246052/
I've resent a new one.

Wei-Ning

On Mon, Mar 21, 2016 at 6:28 PM, Kalle Valo <kvalo@codeaurora.org> wrote:
> Wei-Ning Huang <wnhuang@chromium.org> writes:
>
>> From: Amitkumar Karwar <akarwar@marvell.com>
>>
>> Low priority scan handling code which delays or aborts scan
>> operation based on Tx traffic is removed recently. The reason
>> is firmware already takes care of it in our new feature scan
>> channel gap. Hence we should advertise low priority scan
>> support to cfg80211.
>>
>> This patch fixes a problem in which OBSS scan request from
>> wpa_supplicant was being rejected by cfg80211.
>>
>> Signed-off-by: Wei-Ning Huang <wnhuang@chromium.org>
>
> The From line states that this is written by Amitkumar but there's no
> Signed-off-By line from him. I can't take this without that, please
> resend.
>
> (Wei-Ning's s-o-b line is correct, I just need also Amitkumar's line.)
>
> --
> Kalle Valo



-- 
Wei-Ning Huang, 黃偉寧 | Software Engineer, Google Inc., Taiwan |
wnhuang@google.com | Cell: +886 910-380678

^ permalink raw reply

* [PATCH v2] mwifiex: advertise low priority scan feature
From: Wei-Ning Huang @ 2016-03-22  4:09 UTC (permalink / raw)
  To: Linux Wireless
  Cc: LKML, akarwar, djkurtz, Wei-Ning Huang, nishants, kvalo, netdev

From: Amitkumar Karwar <akarwar@marvell.com>

Low priority scan handling code which delays or aborts scan
operation based on Tx traffic is removed recently. The reason
is firmware already takes care of it in our new feature scan
channel gap. Hence we should advertise low priority scan
support to cfg80211.

This patch fixes a problem in which OBSS scan request from
wpa_supplicant was being rejected by cfg80211.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Wei-Ning Huang <wnhuang@chromium.org>
---
 drivers/net/wireless/marvell/mwifiex/cfg80211.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index bb7235e..7dafc5b 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4086,6 +4086,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
 
 	wiphy->features |= NL80211_FEATURE_HT_IBSS |
 			   NL80211_FEATURE_INACTIVITY_TIMER |
+			   NL80211_FEATURE_LOW_PRIORITY_SCAN |
 			   NL80211_FEATURE_NEED_OBSS_SCAN;
 
 	if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* Re: [PATCH 2/2] igmp: Document sysctl_igmp_max_msf
From: David Miller @ 2016-03-22  2:58 UTC (permalink / raw)
  To: bpoirier; +Cc: netdev, corbet
In-Reply-To: <1458591700-5547-2-git-send-email-bpoirier@suse.com>

From: Benjamin Poirier <bpoirier@suse.com>
Date: Mon, 21 Mar 2016 13:21:40 -0700

> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>

Applied.

^ permalink raw reply

* Re: [PATCH 1/2] net: Fix indentation of the conf/ documentation block
From: David Miller @ 2016-03-22  2:58 UTC (permalink / raw)
  To: bpoirier; +Cc: netdev, corbet, jeder
In-Reply-To: <1458591700-5547-1-git-send-email-bpoirier@suse.com>

From: Benjamin Poirier <bpoirier@suse.com>
Date: Mon, 21 Mar 2016 13:21:39 -0700

> Commit d67ef35fff67 ("clarify documentation for
> net.ipv4.igmp_max_memberships") mistakenly indented a block of
> documentation such that it now looks like it belongs to a specific sysctl.
> Restore that block's original position.
> 
> Cc: Jeremy Eder <jeder@redhat.com>
> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>

Applied.

^ permalink raw reply

* Re: [PATCH v2] net: add missing descriptions in net_device_priv_flags
From: David Miller @ 2016-03-22  2:58 UTC (permalink / raw)
  To: luisbg; +Cc: linux-kernel, netdev, benjamin.poirier
In-Reply-To: <1458593908-4295-1-git-send-email-luisbg@osg.samsung.com>

From: Luis de Bethencourt <luisbg@osg.samsung.com>
Date: Mon, 21 Mar 2016 20:58:28 +0000

> The flags IFF_XMIT_DST_RELEASE_PERM, IFF_IPVLAN_MASTER and
> IFF_IPVLAN_SLAVE are missing descriptions for the Documentation. Adding
> them.
> 
> Signed-off-by: Luis de Bethencourt <luisbg@osg.samsung.com>
> Suggested-by: Benjamin Poirier <benjamin.poirier@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH] net: Add missing kernel-doc for netdev ptype lists
From: David Miller @ 2016-03-22  2:58 UTC (permalink / raw)
  To: bpoirier; +Cc: netdev, luisbg, noureddine
In-Reply-To: <1458594508-14545-1-git-send-email-bpoirier@suse.com>

From: Benjamin Poirier <bpoirier@suse.com>
Date: Mon, 21 Mar 2016 14:08:28 -0700

> .//include/linux/netdevice.h:1826: warning: No description found for parameter 'ptype_all'
> .//include/linux/netdevice.h:1826: warning: No description found for parameter 'ptype_specific'
> 
> Introduced by commit 7866a621043f ("dev: add per net_device packet type
> chains")
> 
> Cc: Salam Noureddine <noureddine@arista.com>
> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>

Applied.

^ permalink raw reply

* Re: Make DST_CACHE a silent config option
From: David Miller @ 2016-03-22  2:58 UTC (permalink / raw)
  To: davej; +Cc: netdev
In-Reply-To: <20160321223722.GA26702@codemonkey.org.uk>

From: Dave Jones <davej@codemonkey.org.uk>
Date: Mon, 21 Mar 2016 18:37:22 -0400

> commit 911362c70d ("net: add dst_cache support") added a new
> kconfig option that gets selected by other networking options.
> It seems the intent wasn't to offer this as a user-selectable
> option given the lack of help text, so this patch converts it
> to a silent option.
> 
> Signed-off-by: Dave Jones <davej@codemonkey.org.uk>

That indeed is the intention, applied, thanks Dave.

^ permalink raw reply

* Re: [PATCH RESEND] net: ipv4: Fix truncated timestamp returned by inet_current_timestamp()
From: David Miller @ 2016-03-22  2:57 UTC (permalink / raw)
  To: deepa.kernel; +Cc: netdev, y2038, kuznet, yoshfuji, jmorris, kaber, arnd
In-Reply-To: <1458609686-7435-1-git-send-email-deepa.kernel@gmail.com>

From: Deepa Dinamani <deepa.kernel@gmail.com>
Date: Mon, 21 Mar 2016 18:21:26 -0700

> The millisecond timestamps returned by the function is
> converted to network byte order by making a call to htons().
> htons() only returns __be16 while __be32 is required here.
> 
> This was identified by the sparse warning from the buildbot:
> net/ipv4/af_inet.c:1405:16: sparse: incorrect type in return
> 			    expression (different base types)
> net/ipv4/af_inet.c:1405:16: expected restricted __be32
> net/ipv4/af_inet.c:1405:16: got restricted __be16 [usertype] <noident>
> 
> Change the function to use htonl() to return the correct __be32 type
> instead so that the millisecond value doesn't get truncated.
> 
> Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
> Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
> Cc: James Morris <jmorris@namei.org>
> Cc: Patrick McHardy <kaber@trash.net>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Fixes: 822c868532ca ("net: ipv4: Convert IP network timestamps to be y2038 safe")
> Reported-by: Fengguang Wu <fengguang.wu@intel.com> [0-day test robot]

Applied and queued up for -stable.

^ permalink raw reply

* RE: [PATCH net-next 1/3] net: add the AF_KCM entries to family name tables
From: Dexuan Cui @ 2016-03-22  1:39 UTC (permalink / raw)
  To: David Miller
  Cc: gregkh@linuxfoundation.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, devel@linuxdriverproject.org,
	olaf@aepfle.de, apw@canonical.com, jasowang@redhat.com,
	KY Srinivasan, Haiyang Zhang, vkuznets@redhat.com
In-Reply-To: <20160321.112742.1737417108964275737.davem@davemloft.net>

> From: David Miller [mailto:davem@davemloft.net]
> Sent: Monday, March 21, 2016 23:28
> To: Dexuan Cui <decui@microsoft.com>
> Cc: gregkh@linuxfoundation.org; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; devel@linuxdriverproject.org; olaf@aepfle.de;
> apw@canonical.com; jasowang@redhat.com; KY Srinivasan
> <kys@microsoft.com>; Haiyang Zhang <haiyangz@microsoft.com>;
> vkuznets@redhat.com
> Subject: Re: [PATCH net-next 1/3] net: add the AF_KCM entries to family
> name tables
> 
> 
> Two things wrong with this submission:
> 
> 1) You need to provide an initial "[PATCH net-next 0/3] ..." header posting
>    explaining at a high level what this patch series is about and how it is
>    implemented and why.

Hi David,
Thanks for the reply! I'll fix this.

> 2) The net-next tree is closed at this time because we are in the merge
> window,
>    therefore no new feature patches should be submitted to the netdev
> mailing
>    list at this time.  Please wait until some (reasonable) amount of time after
>    the merge window closes to resubmit this.

OK.  I'll repost it when the merge window is open -- I suppose that would happen
in 1~2 weeks, according to my reading the documentation.

Thanks,
-- Dexuan

^ permalink raw reply

* Re: [Make-wifi-fast] [RFCv2 1/3] mac80211: implement fq_codel for software queuing
From: David Lang @ 2016-03-22  1:35 UTC (permalink / raw)
  To: Michal Kazior
  Cc: emmanuel.grumbach, netdev, linux-wireless, ath10k, codel,
	make-wifi-fast, johannes, Tim Shepard
In-Reply-To: <1458123478-1795-2-git-send-email-michal.kazior@tieto.com>

On Wed, 16 Mar 2016, Michal Kazior wrote:

> Since 11n aggregation become important to get the
> best out of txops. However aggregation inherently
> requires buffering and queuing. Once variable
> medium conditions to different associated stations
> is considered it became apparent that bufferbloat
> can't be simply fought with qdiscs for wireless
> drivers.

If the network is quiet enough, don't do any buffering, but in almost all 
situations you are going to need to buffer starting no later than the second 
packet you try to send.

Don't try to make queueing occur, just deal with the queues that form naturally 
because you can't transmit data any faster (and work to keep them under some 
semblence of control)

It's a tempting trap to fall into to try and fill the aggregates to transmit as 
efficiently as possible, but don't skip transmitting because you don't have a 
full aggregate, transmit what you have and if there is more, you'll catch it on 
the next pass.

This is slightly less friendly on the network than waiting to see if you can 
fill the aggregate in a quick fashion, but if uces the lowest latency possible, 
and deteriorates into the same state that you end up with if you try to fill the 
aggregates as the load/congestion builds.

David Lang

>
> This bases on codel5 and sch_fq_codel.c. It may
> not be the Right Thing yet but it should at least
> provide a framework for more improvements.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
> include/net/mac80211.h     |  96 ++++++-
> net/mac80211/agg-tx.c      |   8 +-
> net/mac80211/cfg.c         |   2 +-
> net/mac80211/codel.h       | 264 ++++++++++++++++++
> net/mac80211/codel_i.h     |  89 ++++++
> net/mac80211/debugfs.c     | 267 ++++++++++++++++++
> net/mac80211/ieee80211_i.h |  45 +++-
> net/mac80211/iface.c       |  25 +-
> net/mac80211/main.c        |   9 +-
> net/mac80211/rx.c          |   2 +-
> net/mac80211/sta_info.c    |  10 +-
> net/mac80211/sta_info.h    |  27 ++
> net/mac80211/status.c      |  64 +++++
> net/mac80211/tx.c          | 658 ++++++++++++++++++++++++++++++++++++++++++---
> net/mac80211/util.c        |  21 +-
> 15 files changed, 1503 insertions(+), 84 deletions(-)
> create mode 100644 net/mac80211/codel.h
> create mode 100644 net/mac80211/codel_i.h
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index a53333cb1528..947d827f254b 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -565,6 +565,16 @@ struct ieee80211_bss_conf {
> 	struct ieee80211_p2p_noa_attr p2p_noa_attr;
> };
> 
> +/*
> + * struct codel_params - contains codel parameters
> + * @interval:	initial drop rate
> + * @target:     maximum persistent sojourn time
> + */
> +struct codel_params {
> +	u64	interval;
> +	u64	target;
> +};
> +
> /**
>  * enum mac80211_tx_info_flags - flags to describe transmission information/status
>  *
> @@ -853,6 +863,8 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
>  * @band: the band to transmit on (use for checking for races)
>  * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
>  * @ack_frame_id: internal frame ID for TX status, used internally
> + * @expected_duration: number of microseconds the stack expects this frame to
> + *	take to tx. Used for fair queuing.
>  * @control: union for control data
>  * @status: union for status data
>  * @driver_data: array of driver_data pointers
> @@ -865,11 +877,10 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
> struct ieee80211_tx_info {
> 	/* common information */
> 	u32 flags;
> -	u8 band;
> -
> -	u8 hw_queue;
> -
> -	u16 ack_frame_id;
> +	u32 band:2,
> +	    hw_queue:5,
> +	    ack_frame_id:15,
> +	    expected_duration:10;
>
> 	union {
> 		struct {
> @@ -888,8 +899,18 @@ struct ieee80211_tx_info {
> 				/* only needed before rate control */
> 				unsigned long jiffies;
> 			};
> -			/* NB: vif can be NULL for injected frames */
> -			struct ieee80211_vif *vif;
> +			union {
> +				/* NB: vif can be NULL for injected frames */
> +				struct ieee80211_vif *vif;
> +
> +				/* When packets are enqueued on txq it's easy
> +				 * to re-construct the vif pointer. There's no
> +				 * more space in tx_info so it can be used to
> +				 * store the necessary enqueue time for packet
> +				 * sojourn time computation.
> +				 */
> +				u64 enqueue_time;
> +			};
> 			struct ieee80211_key_conf *hw_key;
> 			u32 flags;
> 			/* 4 bytes free */
> @@ -2114,8 +2135,8 @@ enum ieee80211_hw_flags {
>  * @cipher_schemes: a pointer to an array of cipher scheme definitions
>  *	supported by HW.
>  *
> - * @txq_ac_max_pending: maximum number of frames per AC pending in all txq
> - *	entries for a vif.
> + * @txq_cparams: codel parameters to control tx queueing dropping behavior
> + * @txq_limit: maximum number of frames queuesd
>  */
> struct ieee80211_hw {
> 	struct ieee80211_conf conf;
> @@ -2145,7 +2166,8 @@ struct ieee80211_hw {
> 	u8 uapsd_max_sp_len;
> 	u8 n_cipher_schemes;
> 	const struct ieee80211_cipher_scheme *cipher_schemes;
> -	int txq_ac_max_pending;
> +	struct codel_params txq_cparams;
> +	u32 txq_limit;
> };
> 
> static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
> @@ -5633,6 +5655,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
>  * txq state can change half-way of this function and the caller may end up
>  * with "new" frame_cnt and "old" byte_cnt or vice-versa.
>  *
> + * Moreover returned values are best-case, i.e. assuming queueing algorithm
> + * will not drop frames due to excess latency.
> + *
>  * @txq: pointer obtained from station or virtual interface
>  * @frame_cnt: pointer to store frame count
>  * @byte_cnt: pointer to store byte count
> @@ -5640,4 +5665,55 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
> void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
> 			     unsigned long *frame_cnt,
> 			     unsigned long *byte_cnt);
> +
> +/**
> + * ieee80211_recalc_fq_period - recalculate fair-queuing period
> + *
> + * This is used to alter the dropping rate to react to possibly changing
> + * (active) station-tid service period and air conditions.
> + *
> + * Driver which implement wake_tx_queue() but don't use ieee80211_tx_schedule()
> + * are encouraged to call this function periodically.
> + *
> +* @hw: pointer as obtained from ieee80211_alloc_hw()
> + */
> +void ieee80211_recalc_fq_period(struct ieee80211_hw *hw);
> +
> +/**
> + * ieee80211_tx_schedule - schedule next transmission burst
> + *
> + * This function can be (and should be, preferably) called by drivers that use
> + * wake_tx_queue op. It uses fq-codel like algorithm to maintain fairness.
> + *
> + * This function may call in back to driver (get_expected_throughput op) so
> + * be careful with locking.
> + *
> + * Driver should take care of serializing calls to this functions. Otherwise
> + * fairness can't be guaranteed.
> + *
> + * This function returns the following values:
> + *	-EBUSY		Software queues are not empty yet. The function should
> + *			not be called until after driver's next tx completion.
> + *	-ENOENT		Software queues are empty.
> + *
> + * @hw: pointer as obtained from ieee80211_alloc_hw()
> + * @wake: callback to driver to handle burst for given txq within given (byte)
> + *	budget. The driver is expected to either call ieee80211_tx_dequeue() or
> + *	use its internal queues (if any). The budget should be respected only
> + *	for frames comming from ieee80211_tx_dequeue(). On termination it is
> + *	expected to return number of frames put onto hw queue that were taken
> + *	via ieee80211_tx_dequeue(). Frames from internal retry queues shall not
> + *	be included in the returned count. If hw queues become/are busy/full
> + *	the driver shall return a negative value which will prompt
> + *	ieee80211_tx_schedule() to terminate. If hw queues become full after at
> + *	least 1 frame dequeued via ieee80211_tx_dequeue() was sent the driver
> + *	is free to report either number of sent frames up until that point or a
> + *	negative value. The driver may return 0 if it wants to skip the txq
> + *	(e.g. target station is in powersave).
> + */
> +int ieee80211_tx_schedule(struct ieee80211_hw *hw,
> +			  int (*wake)(struct ieee80211_hw *hw,
> +				      struct ieee80211_txq *txq,
> +				      int budget));
> +
> #endif /* MAC80211_H */
> diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
> index 4932e9f243a2..b9d0cee2a786 100644
> --- a/net/mac80211/agg-tx.c
> +++ b/net/mac80211/agg-tx.c
> @@ -194,17 +194,21 @@ static void
> ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
> {
> 	struct ieee80211_txq *txq = sta->sta.txq[tid];
> +	struct ieee80211_sub_if_data *sdata;
> +	struct ieee80211_fq *fq;
> 	struct txq_info *txqi;
>
> 	if (!txq)
> 		return;
>
> 	txqi = to_txq_info(txq);
> +	sdata = vif_to_sdata(txq->vif);
> +	fq = &sdata->local->fq;
>
> 	/* Lock here to protect against further seqno updates on dequeue */
> -	spin_lock_bh(&txqi->queue.lock);
> +	spin_lock_bh(&fq->lock);
> 	set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
> -	spin_unlock_bh(&txqi->queue.lock);
> +	spin_unlock_bh(&fq->lock);
> }
> 
> static void
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index b37adb60c9cb..238d7bbd275e 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -3029,7 +3029,7 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
>
> 	spin_lock_irqsave(&local->ack_status_lock, spin_flags);
> 	id = idr_alloc(&local->ack_status_frames, ack_skb,
> -		       1, 0x10000, GFP_ATOMIC);
> +		       1, 0x8000, GFP_ATOMIC);
> 	spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
>
> 	if (id < 0) {
> diff --git a/net/mac80211/codel.h b/net/mac80211/codel.h
> new file mode 100644
> index 000000000000..e6470dbe5b0b
> --- /dev/null
> +++ b/net/mac80211/codel.h
> @@ -0,0 +1,264 @@
> +#ifndef __NET_MAC80211_CODEL_H
> +#define __NET_MAC80211_CODEL_H
> +
> +/*
> + * Codel - The Controlled-Delay Active Queue Management algorithm
> + *
> + *  Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
> + *  Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
> + *  Copyright (C) 2016 Michael D. Taht <dave.taht@bufferbloat.net>
> + *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
> + *  Copyright (C) 2015 Jonathan Morton <chromatix99@gmail.com>
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions, and the following disclaimer,
> + *    without modification.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The names of the authors may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * Alternatively, provided that this notice is retained in full, this
> + * software may be distributed under the terms of the GNU General
> + * Public License ("GPL") version 2, in which case the provisions of the
> + * GPL apply INSTEAD OF those given above.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> + * DAMAGE.
> + *
> + */
> +
> +#include <linux/version.h>
> +#include <linux/types.h>
> +#include <linux/ktime.h>
> +#include <linux/skbuff.h>
> +#include <net/pkt_sched.h>
> +#include <net/inet_ecn.h>
> +#include <linux/reciprocal_div.h>
> +
> +#include "codel_i.h"
> +
> +/* Controlling Queue Delay (CoDel) algorithm
> + * =========================================
> + * Source : Kathleen Nichols and Van Jacobson
> + * http://queue.acm.org/detail.cfm?id=2209336
> + *
> + * Implemented on linux by Dave Taht and Eric Dumazet
> + */
> +
> +/* CoDel5 uses a real clock, unlike codel */
> +
> +static inline u64 codel_get_time(void)
> +{
> +	return ktime_get_ns();
> +}
> +
> +static inline u32 codel_time_to_us(u64 val)
> +{
> +	do_div(val, NSEC_PER_USEC);
> +	return (u32)val;
> +}
> +
> +/* sizeof_in_bits(rec_inv_sqrt) */
> +#define REC_INV_SQRT_BITS (8 * sizeof(u16))
> +/* needed shift to get a Q0.32 number from rec_inv_sqrt */
> +#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
> +
> +/* Newton approximation method needs more iterations at small inputs,
> + * so cache them.
> + */
> +
> +static void codel_vars_init(struct codel_vars *vars)
> +{
> +	memset(vars, 0, sizeof(*vars));
> +}
> +
> +/*
> + * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots
> + * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2)
> + *
> + * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32
> + */
> +static inline void codel_Newton_step(struct codel_vars *vars)
> +{
> +	u32 invsqrt = ((u32)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
> +	u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 32;
> +	u64 val = (3LL << 32) - ((u64)vars->count * invsqrt2);
> +
> +	val >>= 2; /* avoid overflow in following multiply */
> +	val = (val * invsqrt) >> (32 - 2 + 1);
> +
> +	vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
> +}
> +
> +/*
> + * CoDel control_law is t + interval/sqrt(count)
> + * We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid
> + * both sqrt() and divide operation.
> + */
> +static u64 codel_control_law(u64 t,
> +			     u64 interval,
> +			     u32 rec_inv_sqrt)
> +{
> +	return t + reciprocal_scale(interval, rec_inv_sqrt <<
> +				    REC_INV_SQRT_SHIFT);
> +}
> +
> +/* Forward declaration of this for use elsewhere */
> +
> +static inline u64
> +custom_codel_get_enqueue_time(struct sk_buff *skb);
> +
> +static inline struct sk_buff *
> +custom_dequeue(struct codel_vars *vars, void *ptr);
> +
> +static inline void
> +custom_drop(struct sk_buff *skb, void *ptr);
> +
> +static bool codel_should_drop(struct sk_buff *skb,
> +			      __u32 *backlog,
> +			      __u32 backlog_thr,
> +			      struct codel_vars *vars,
> +			      const struct codel_params *p,
> +			      u64 now)
> +{
> +	if (!skb) {
> +		vars->first_above_time = 0;
> +		return false;
> +	}
> +
> +	if (now - custom_codel_get_enqueue_time(skb) < p->target ||
> +	    *backlog <= backlog_thr) {
> +		/* went below - stay below for at least interval */
> +		vars->first_above_time = 0;
> +		return false;
> +	}
> +
> +	if (vars->first_above_time == 0) {
> +		/* just went above from below; mark the time */
> +		vars->first_above_time = now + p->interval;
> +
> +	} else if (now > vars->first_above_time) {
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +static struct sk_buff *codel_dequeue(void *ptr,
> +				     __u32 *backlog,
> +				     __u32 backlog_thr,
> +				     struct codel_vars *vars,
> +				     struct codel_params *p,
> +				     u64 now,
> +				     bool overloaded)
> +{
> +	struct sk_buff *skb = custom_dequeue(vars, ptr);
> +	bool drop;
> +
> +	if (!skb) {
> +		vars->dropping = false;
> +		return skb;
> +	}
> +	drop = codel_should_drop(skb, backlog, backlog_thr, vars, p, now);
> +	if (vars->dropping) {
> +		if (!drop) {
> +			/* sojourn time below target - leave dropping state */
> +			vars->dropping = false;
> +		} else if (now >= vars->drop_next) {
> +			/* It's time for the next drop. Drop the current
> +			 * packet and dequeue the next. The dequeue might
> +			 * take us out of dropping state.
> +			 * If not, schedule the next drop.
> +			 * A large backlog might result in drop rates so high
> +			 * that the next drop should happen now,
> +			 * hence the while loop.
> +			 */
> +
> +			/* saturating increment */
> +			vars->count++;
> +			if (!vars->count)
> +				vars->count--;
> +
> +			codel_Newton_step(vars);
> +			vars->drop_next = codel_control_law(vars->drop_next,
> +							    p->interval,
> +							    vars->rec_inv_sqrt);
> +			do {
> +				if (INET_ECN_set_ce(skb) && !overloaded) {
> +					vars->ecn_mark++;
> +					/* and schedule the next drop */
> +					vars->drop_next = codel_control_law(
> +						vars->drop_next, p->interval,
> +						vars->rec_inv_sqrt);
> +					goto end;
> +				}
> +				custom_drop(skb, ptr);
> +				vars->drop_count++;
> +				skb = custom_dequeue(vars, ptr);
> +				if (skb && !codel_should_drop(skb, backlog,
> +							      backlog_thr,
> +							      vars, p, now)) {
> +					/* leave dropping state */
> +					vars->dropping = false;
> +				} else {
> +					/* schedule the next drop */
> +					vars->drop_next = codel_control_law(
> +						vars->drop_next, p->interval,
> +						vars->rec_inv_sqrt);
> +				}
> +			} while (skb && vars->dropping && now >=
> +				 vars->drop_next);
> +
> +			/* Mark the packet regardless */
> +			if (skb && INET_ECN_set_ce(skb))
> +				vars->ecn_mark++;
> +		}
> +	} else if (drop) {
> +		if (INET_ECN_set_ce(skb) && !overloaded) {
> +			vars->ecn_mark++;
> +		} else {
> +			custom_drop(skb, ptr);
> +			vars->drop_count++;
> +
> +			skb = custom_dequeue(vars, ptr);
> +			drop = codel_should_drop(skb, backlog, backlog_thr,
> +						 vars, p, now);
> +			if (skb && INET_ECN_set_ce(skb))
> +				vars->ecn_mark++;
> +		}
> +		vars->dropping = true;
> +		/* if min went above target close to when we last went below
> +		 * assume that the drop rate that controlled the queue on the
> +		 * last cycle is a good starting point to control it now.
> +		 */
> +		if (vars->count > 2 &&
> +		    now - vars->drop_next < 8 * p->interval) {
> +			vars->count -= 2;
> +			codel_Newton_step(vars);
> +		} else {
> +			vars->count = 1;
> +			vars->rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
> +		}
> +		codel_Newton_step(vars);
> +		vars->drop_next = codel_control_law(now, p->interval,
> +						    vars->rec_inv_sqrt);
> +	}
> +end:
> +	return skb;
> +}
> +#endif
> diff --git a/net/mac80211/codel_i.h b/net/mac80211/codel_i.h
> new file mode 100644
> index 000000000000..a7d23e45dee9
> --- /dev/null
> +++ b/net/mac80211/codel_i.h
> @@ -0,0 +1,89 @@
> +#ifndef __NET_MAC80211_CODEL_I_H
> +#define __NET_MAC80211_CODEL_I_H
> +
> +/*
> + * Codel - The Controlled-Delay Active Queue Management algorithm
> + *
> + *  Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
> + *  Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
> + *  Copyright (C) 2016 Michael D. Taht <dave.taht@bufferbloat.net>
> + *  Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
> + *  Copyright (C) 2015 Jonathan Morton <chromatix99@gmail.com>
> + *  Copyright (C) 2016 Michal Kazior <michal.kazior@tieto.com>
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions, and the following disclaimer,
> + *    without modification.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The names of the authors may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * Alternatively, provided that this notice is retained in full, this
> + * software may be distributed under the terms of the GNU General
> + * Public License ("GPL") version 2, in which case the provisions of the
> + * GPL apply INSTEAD OF those given above.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> + * DAMAGE.
> + *
> + */
> +
> +#include <linux/version.h>
> +#include <linux/types.h>
> +#include <linux/ktime.h>
> +#include <linux/skbuff.h>
> +#include <net/pkt_sched.h>
> +#include <net/inet_ecn.h>
> +#include <linux/reciprocal_div.h>
> +
> +/* Controlling Queue Delay (CoDel) algorithm
> + * =========================================
> + * Source : Kathleen Nichols and Van Jacobson
> + * http://queue.acm.org/detail.cfm?id=2209336
> + *
> + * Implemented on linux by Dave Taht and Eric Dumazet
> + */
> +
> +/* CoDel5 uses a real clock, unlike codel */
> +
> +#define MS2TIME(a) (a * (u64) NSEC_PER_MSEC)
> +#define US2TIME(a) (a * (u64) NSEC_PER_USEC)
> +
> +/**
> + * struct codel_vars - contains codel variables
> + * @count:		how many drops we've done since the last time we
> + *			entered dropping state
> + * @dropping:		set to > 0 if in dropping state
> + * @rec_inv_sqrt:	reciprocal value of sqrt(count) >> 1
> + * @first_above_time:	when we went (or will go) continuously above target
> + *			for interval
> + * @drop_next:		time to drop next packet, or when we dropped last
> + * @drop_count:	temp count of dropped packets in dequeue()
> + * @ecn_mark:	number of packets we ECN marked instead of dropping
> + */
> +
> +struct codel_vars {
> +	u32	count;
> +	u16	dropping;
> +	u16	rec_inv_sqrt;
> +	u64	first_above_time;
> +	u64	drop_next;
> +	u16	drop_count;
> +	u16	ecn_mark;
> +};
> +#endif
> diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
> index 4ab5c522ceee..9b0b8c3d23cd 100644
> --- a/net/mac80211/debugfs.c
> +++ b/net/mac80211/debugfs.c
> @@ -31,6 +31,30 @@ int mac80211_format_buffer(char __user *userbuf, size_t count,
> 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
> }
> 
> +static int mac80211_parse_buffer(const char __user *userbuf,
> +				 size_t count,
> +				 loff_t *ppos,
> +				 char *fmt, ...)
> +{
> +	va_list args;
> +	char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = {};
> +	int res;
> +
> +	if (count > sizeof(buf))
> +		return -EINVAL;
> +
> +	if (copy_from_user(buf, userbuf, count))
> +		return -EFAULT;
> +
> +	buf[sizeof(buf) - 1] = '\0';
> +
> +	va_start(args, fmt);
> +	res = vsscanf(buf, fmt, args);
> +	va_end(args);
> +
> +	return count;
> +}
> +
> #define DEBUGFS_READONLY_FILE_FN(name, fmt, value...)			\
> static ssize_t name## _read(struct file *file, char __user *userbuf,	\
> 			    size_t count, loff_t *ppos)			\
> @@ -70,6 +94,62 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
> DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
> 	local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
> 
> +DEBUGFS_READONLY_FILE(fq_drop_overlimit, "%d",
> +		      local->fq.drop_overlimit);
> +DEBUGFS_READONLY_FILE(fq_drop_codel, "%d",
> +		      local->fq.drop_codel);
> +DEBUGFS_READONLY_FILE(fq_backlog, "%d",
> +		      local->fq.backlog);
> +DEBUGFS_READONLY_FILE(fq_in_flight_usec, "%d",
> +		      atomic_read(&local->fq.in_flight_usec));
> +DEBUGFS_READONLY_FILE(fq_txq_limit, "%d",
> +		      local->hw.txq_limit);
> +DEBUGFS_READONLY_FILE(fq_txq_interval, "%llu",
> +		      local->hw.txq_cparams.interval);
> +DEBUGFS_READONLY_FILE(fq_txq_target, "%llu",
> +		      local->hw.txq_cparams.target);
> +DEBUGFS_READONLY_FILE(fq_ave_period, "%d",
> +		      (int)ewma_fq_period_read(&local->fq.ave_period));
> +
> +#define DEBUGFS_RW_FILE_FN(name, expr)				\
> +static ssize_t name## _write(struct file *file,			\
> +			     const char __user *userbuf,	\
> +			     size_t count,			\
> +			     loff_t *ppos)			\
> +{								\
> +	struct ieee80211_local *local = file->private_data;	\
> +	return expr;						\
> +}
> +
> +#define DEBUGFS_RW_FILE(name, expr, fmt, value...)	\
> +	DEBUGFS_READONLY_FILE_FN(name, fmt, value)	\
> +	DEBUGFS_RW_FILE_FN(name, expr)			\
> +	DEBUGFS_RW_FILE_OPS(name)
> +
> +#define DEBUGFS_RW_FILE_OPS(name)			\
> +static const struct file_operations name## _ops = {	\
> +	.read = name## _read,				\
> +	.write = name## _write,				\
> +	.open = simple_open,				\
> +	.llseek = generic_file_llseek,			\
> +};
> +
> +#define DEBUGFS_RW_EXPR_FQ(name)					\
> +({									\
> +	int res;							\
> +	res = mac80211_parse_buffer(userbuf, count, ppos, "%d", &name);	\
> +	ieee80211_recalc_fq_period(&local->hw);				\
> +	res;								\
> +})
> +
> +DEBUGFS_RW_FILE(fq_min_txops_target,   DEBUGFS_RW_EXPR_FQ(local->fq.min_txops_target),   "%d",  local->fq.min_txops_target);
> +DEBUGFS_RW_FILE(fq_max_txops_per_txq,  DEBUGFS_RW_EXPR_FQ(local->fq.max_txops_per_txq),  "%d",  local->fq.max_txops_per_txq);
> +DEBUGFS_RW_FILE(fq_min_txops_per_hw,   DEBUGFS_RW_EXPR_FQ(local->fq.min_txops_per_hw),   "%d",  local->fq.min_txops_per_hw);
> +DEBUGFS_RW_FILE(fq_max_txops_per_hw,   DEBUGFS_RW_EXPR_FQ(local->fq.max_txops_per_hw),   "%d",  local->fq.max_txops_per_hw);
> +DEBUGFS_RW_FILE(fq_txop_mixed_usec,    DEBUGFS_RW_EXPR_FQ(local->fq.txop_mixed_usec),    "%d",  local->fq.txop_mixed_usec);
> +DEBUGFS_RW_FILE(fq_txop_green_usec,    DEBUGFS_RW_EXPR_FQ(local->fq.txop_green_usec),    "%d",  local->fq.txop_green_usec);
> +
> +
> #ifdef CONFIG_PM
> static ssize_t reset_write(struct file *file, const char __user *user_buf,
> 			   size_t count, loff_t *ppos)
> @@ -177,8 +257,178 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
> 	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
> }
> 
> +static ssize_t fq_read(struct file *file, char __user *user_buf,
> +		       size_t count, loff_t *ppos)
> +{
> +	struct ieee80211_local *local = file->private_data;
> +	struct ieee80211_sub_if_data *sdata;
> +	struct sta_info *sta;
> +	struct txq_flow *flow;
> +	struct txq_info *txqi;
> +	void *buf;
> +	int new_flows;
> +	int old_flows;
> +	int len;
> +	int i;
> +	int rv;
> +	int res = 0;
> +	static const u8 zeroaddr[ETH_ALEN];
> +
> +	len = 32 * 1024;
> +	buf = kzalloc(len, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	spin_lock_bh(&local->fq.lock);
> +	rcu_read_lock();
> +
> +	list_for_each_entry(txqi, &local->fq.new_flows, flowchain) {
> +		res += scnprintf(buf + res, len - res,
> +				 "sched new txqi vif %s sta %pM tid %d deficit %d\n",
> +				 container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif)->name,
> +				 txqi->txq.sta ? txqi->txq.sta->addr : zeroaddr,
> +				 txqi->txq.tid,
> +				 txqi->deficit);
> +	}
> +
> +	list_for_each_entry(txqi, &local->fq.old_flows, flowchain) {
> +		res += scnprintf(buf + res, len - res,
> +				 "sched old txqi vif %s sta %pM tid %d deficit %d\n",
> +				 container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif)->name,
> +				 txqi->txq.sta ? txqi->txq.sta->addr : zeroaddr,
> +				 txqi->txq.tid,
> +				 txqi->deficit);
> +	}
> +
> +	list_for_each_entry_rcu(sta, &local->sta_list, list) {
> +		for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
> +			if (!sta->sta.txq[i])
> +				continue;
> +
> +			txqi = container_of(sta->sta.txq[i], struct txq_info, txq);
> +			if (!txqi->backlog_bytes)
> +				continue;
> +
> +			new_flows = 0;
> +			old_flows = 0;
> +
> +			list_for_each_entry(flow, &txqi->new_flows, flowchain)
> +				new_flows++;
> +			list_for_each_entry(flow, &txqi->old_flows, flowchain)
> +				old_flows++;
> +
> +			res += scnprintf(buf + res, len - res,
> +					 "sta %pM tid %d backlog (%db %dp) flows (%d new %d old) burst %d bpu %d in-flight %d\n",
> +					 sta->sta.addr,
> +					 i,
> +					 txqi->backlog_bytes,
> +					 txqi->backlog_packets,
> +					 new_flows,
> +					 old_flows,
> +					 txqi->bytes_per_burst,
> +					 txqi->bytes_per_usec,
> +					 atomic_read(&txqi->in_flight_usec)
> +					);
> +
> +			flow = &txqi->flow;
> +			res += scnprintf(buf + res, len - res,
> +					 "sta %pM def flow %p backlog (%db %dp)\n",
> +					 sta->sta.addr,
> +					 flow,
> +					 flow->backlog,
> +					 flow->queue.qlen
> +				);
> +
> +			list_for_each_entry(flow, &txqi->new_flows, flowchain)
> +				res += scnprintf(buf + res, len - res,
> +						 "sta %pM tid %d new flow %p backlog (%db %dp)\n",
> +						 sta->sta.addr,
> +						 i,
> +						 flow,
> +						 flow->backlog,
> +						 flow->queue.qlen
> +					);
> +
> +			list_for_each_entry(flow, &txqi->old_flows, flowchain)
> +				res += scnprintf(buf + res, len - res,
> +						 "sta %pM tid %d old flow %p backlog (%db %dp)\n",
> +						 sta->sta.addr,
> +						 i,
> +						 flow,
> +						 flow->backlog,
> +						 flow->queue.qlen
> +					);
> +		}
> +	}
> +
> +	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
> +		if (!sdata->vif.txq)
> +			continue;
> +
> +		txqi = container_of(sdata->vif.txq, struct txq_info, txq);
> +		if (!txqi->backlog_bytes)
> +			continue;
> +
> +		new_flows = 0;
> +		old_flows = 0;
> +
> +		list_for_each_entry(flow, &txqi->new_flows, flowchain)
> +			new_flows++;
> +		list_for_each_entry(flow, &txqi->old_flows, flowchain)
> +			old_flows++;
> +
> +		res += scnprintf(buf + res, len - res,
> +				 "vif %s backlog (%db %dp) flows (%d new %d old) burst %d bpu %d in-flight %d\n",
> +				 sdata->name,
> +				 txqi->backlog_bytes,
> +				 txqi->backlog_packets,
> +				 new_flows,
> +				 old_flows,
> +				 txqi->bytes_per_burst,
> +				 txqi->bytes_per_usec,
> +				 atomic_read(&txqi->in_flight_usec)
> +				);
> +
> +		flow = &txqi->flow;
> +		res += scnprintf(buf + res, len - res,
> +				 "vif %s def flow %p backlog (%db %dp)\n",
> +				 sdata->name,
> +				 flow,
> +				 flow->backlog,
> +				 flow->queue.qlen
> +			);
> +
> +		list_for_each_entry(flow, &txqi->new_flows, flowchain)
> +			res += scnprintf(buf + res, len - res,
> +					 "vif %s new flow %p backlog (%db %dp)\n",
> +					 sdata->name,
> +					 flow,
> +					 flow->backlog,
> +					 flow->queue.qlen
> +				);
> +
> +		list_for_each_entry(flow, &txqi->old_flows, flowchain)
> +			res += scnprintf(buf + res, len - res,
> +					 "vif %s old flow %p backlog (%db %dp)\n",
> +					 sdata->name,
> +					 flow,
> +					 flow->backlog,
> +					 flow->queue.qlen
> +				);
> +	}
> +
> +	rcu_read_unlock();
> +	spin_unlock_bh(&local->fq.lock);
> +
> +	rv = simple_read_from_buffer(user_buf, count, ppos, buf, res);
> +	kfree(buf);
> +
> +	return rv;
> +}
> +
> DEBUGFS_READONLY_FILE_OPS(hwflags);
> DEBUGFS_READONLY_FILE_OPS(queues);
> +DEBUGFS_READONLY_FILE_OPS(fq);
> 
> /* statistics stuff */
> 
> @@ -247,6 +497,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
> 	DEBUGFS_ADD(total_ps_buffered);
> 	DEBUGFS_ADD(wep_iv);
> 	DEBUGFS_ADD(queues);
> +	DEBUGFS_ADD(fq);
> #ifdef CONFIG_PM
> 	DEBUGFS_ADD_MODE(reset, 0200);
> #endif
> @@ -254,6 +505,22 @@ void debugfs_hw_add(struct ieee80211_local *local)
> 	DEBUGFS_ADD(user_power);
> 	DEBUGFS_ADD(power);
> 
> +	DEBUGFS_ADD(fq_drop_overlimit);
> +	DEBUGFS_ADD(fq_drop_codel);
> +	DEBUGFS_ADD(fq_backlog);
> +	DEBUGFS_ADD(fq_in_flight_usec);
> +	DEBUGFS_ADD(fq_txq_limit);
> +	DEBUGFS_ADD(fq_txq_interval);
> +	DEBUGFS_ADD(fq_txq_target);
> +	DEBUGFS_ADD(fq_ave_period);
> +
> +	DEBUGFS_ADD(fq_min_txops_target);
> +	DEBUGFS_ADD(fq_max_txops_per_txq);
> +	DEBUGFS_ADD(fq_min_txops_per_hw);
> +	DEBUGFS_ADD(fq_max_txops_per_hw);
> +	DEBUGFS_ADD(fq_txop_mixed_usec);
> +	DEBUGFS_ADD(fq_txop_green_usec);
> +
> 	statsd = debugfs_create_dir("statistics", phyd);
>
> 	/* if the dir failed, don't put all the other things into the root! */
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index f1565ce35273..443c941d5917 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -805,9 +805,18 @@ enum txq_info_flags {
> };
> 
> struct txq_info {
> -	struct sk_buff_head queue;
> +	struct txq_flow flow;
> +	struct list_head flowchain;
> +	struct list_head new_flows;
> +	struct list_head old_flows;
> +	int backlog_bytes;
> +	int backlog_packets;
> +	int bytes_per_burst;
> +	int bytes_per_usec;
> +	int deficit;
> +	int in_flight_delta_usec;
> +	atomic_t in_flight_usec;
> 	unsigned long flags;
> -	unsigned long byte_cnt;
>
> 	/* keep last! */
> 	struct ieee80211_txq txq;
> @@ -855,7 +864,6 @@ struct ieee80211_sub_if_data {
> 	bool control_port_no_encrypt;
> 	int encrypt_headroom;
> 
> -	atomic_t txqs_len[IEEE80211_NUM_ACS];
> 	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
> 	struct mac80211_qos_map __rcu *qos_map;
> 
> @@ -1092,11 +1100,37 @@ enum mac80211_scan_state {
> 	SCAN_ABORT,
> };
> 
> +DECLARE_EWMA(fq_period, 16, 4)
> +
> +struct ieee80211_fq {
> +	struct txq_flow *flows;
> +	struct list_head backlogs;
> +	struct list_head old_flows;
> +	struct list_head new_flows;
> +	struct ewma_fq_period ave_period;
> +	spinlock_t lock;
> +	atomic_t in_flight_usec;
> +	int flows_cnt;
> +	int perturbation;
> +	int quantum;
> +	int backlog;
> +	int min_txops_target;
> +	int max_txops_per_txq;
> +	int min_txops_per_hw;
> +	int max_txops_per_hw;
> +	int txop_mixed_usec;
> +	int txop_green_usec;
> +
> +	int drop_overlimit;
> +	int drop_codel;
> +};
> +
> struct ieee80211_local {
> 	/* embed the driver visible part.
> 	 * don't cast (use the static inlines below), but we keep
> 	 * it first anyway so they become a no-op */
> 	struct ieee80211_hw hw;
> +	struct ieee80211_fq fq;
>
> 	const struct ieee80211_ops *ops;
> 
> @@ -1928,6 +1962,11 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
> void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
> 			     struct sta_info *sta,
> 			     struct txq_info *txq, int tid);
> +void ieee80211_purge_txq(struct ieee80211_local *local, struct txq_info *txqi);
> +void ieee80211_init_flow(struct txq_flow *flow);
> +int ieee80211_setup_flows(struct ieee80211_local *local);
> +void ieee80211_teardown_flows(struct ieee80211_local *local);
> +
> void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
> 			 u16 transaction, u16 auth_alg, u16 status,
> 			 const u8 *extra, size_t extra_len, const u8 *bssid,
> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
> index 453b4e741780..d1063b50f12c 100644
> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -779,6 +779,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
> 			      bool going_down)
> {
> 	struct ieee80211_local *local = sdata->local;
> +	struct ieee80211_fq *fq = &local->fq;
> 	unsigned long flags;
> 	struct sk_buff *skb, *tmp;
> 	u32 hw_reconf_flags = 0;
> @@ -977,12 +978,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
> 	if (sdata->vif.txq) {
> 		struct txq_info *txqi = to_txq_info(sdata->vif.txq);
> 
> -		spin_lock_bh(&txqi->queue.lock);
> -		ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
> -		txqi->byte_cnt = 0;
> -		spin_unlock_bh(&txqi->queue.lock);
> -
> -		atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
> +		spin_lock_bh(&fq->lock);
> +		ieee80211_purge_txq(local, txqi);
> +		spin_unlock_bh(&fq->lock);
> 	}
>
> 	if (local->open_count == 0)
> @@ -1198,6 +1196,13 @@ static void ieee80211_if_setup(struct net_device *dev)
> 	dev->destructor = ieee80211_if_free;
> }
> 
> +static void ieee80211_if_setup_no_queue(struct net_device *dev)
> +{
> +	ieee80211_if_setup(dev);
> +	dev->priv_flags |= IFF_NO_QUEUE;
> +	/* Note for backporters: use dev->tx_queue_len = 0 instead of IFF_ */
> +}
> +
> static void ieee80211_iface_work(struct work_struct *work)
> {
> 	struct ieee80211_sub_if_data *sdata =
> @@ -1707,6 +1712,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
> 	struct net_device *ndev = NULL;
> 	struct ieee80211_sub_if_data *sdata = NULL;
> 	struct txq_info *txqi;
> +	void (*if_setup)(struct net_device *dev);
> 	int ret, i;
> 	int txqs = 1;
> 
> @@ -1734,12 +1740,17 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
> 			txq_size += sizeof(struct txq_info) +
> 				    local->hw.txq_data_size;
> 
> +		if (local->ops->wake_tx_queue)
> +			if_setup = ieee80211_if_setup_no_queue;
> +		else
> +			if_setup = ieee80211_if_setup;
> +
> 		if (local->hw.queues >= IEEE80211_NUM_ACS)
> 			txqs = IEEE80211_NUM_ACS;
>
> 		ndev = alloc_netdev_mqs(size + txq_size,
> 					name, name_assign_type,
> -					ieee80211_if_setup, txqs, 1);
> +					if_setup, txqs, 1);
> 		if (!ndev)
> 			return -ENOMEM;
> 		dev_net_set(ndev, wiphy_net(local->hw.wiphy));
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 8190bf27ebff..9fd3b10ae52b 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -1053,9 +1053,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
>
> 	local->dynamic_ps_forced_timeout = -1;
> 
> -	if (!local->hw.txq_ac_max_pending)
> -		local->hw.txq_ac_max_pending = 64;
> -
> 	result = ieee80211_wep_init(local);
> 	if (result < 0)
> 		wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
> @@ -1087,6 +1084,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
>
> 	rtnl_unlock();
> 
> +	result = ieee80211_setup_flows(local);
> +	if (result)
> +		goto fail_flows;
> +
> #ifdef CONFIG_INET
> 	local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
> 	result = register_inetaddr_notifier(&local->ifa_notifier);
> @@ -1112,6 +1113,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
> #if defined(CONFIG_INET) || defined(CONFIG_IPV6)
>  fail_ifa:
> #endif
> +	ieee80211_teardown_flows(local);
> + fail_flows:
> 	rtnl_lock();
> 	rate_control_deinitialize(local);
> 	ieee80211_remove_interfaces(local);
> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index dc27becb9b71..70f8f7949bf2 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info *sta)
> 	for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
> 		struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
> 
> -		if (!skb_queue_len(&txqi->queue))
> +		if (!txqi->backlog_packets)
> 			set_bit(tid, &sta->txq_buffered_tids);
> 		else
> 			clear_bit(tid, &sta->txq_buffered_tids);
> diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
> index 00c82fb152c0..0729046a0144 100644
> --- a/net/mac80211/sta_info.c
> +++ b/net/mac80211/sta_info.c
> @@ -112,11 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
> 	if (sta->sta.txq[0]) {
> 		for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
> 			struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
> -			int n = skb_queue_len(&txqi->queue);
> -
> -			ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
> -			atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
> -			txqi->byte_cnt = 0;
> +			ieee80211_purge_txq(local, txqi);
> 		}
> 	}
> 
> @@ -1193,7 +1189,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
> 		for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
> 			struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
> 
> -			if (!skb_queue_len(&txqi->queue))
> +			if (!txqi->backlog_packets)
> 				continue;
>
> 			drv_wake_tx_queue(local, txqi);
> @@ -1630,7 +1626,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
> 		for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
> 			struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
> 
> -			if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue))
> +			if (!(tids & BIT(tid)) || txqi->backlog_packets)
> 				continue;
>
> 			sta_info_recalc_tim(sta);
> diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
> index 053f5c4fa495..dd9d5f754c57 100644
> --- a/net/mac80211/sta_info.h
> +++ b/net/mac80211/sta_info.h
> @@ -19,6 +19,7 @@
> #include <linux/etherdevice.h>
> #include <linux/rhashtable.h>
> #include "key.h"
> +#include "codel_i.h"
> 
> /**
>  * enum ieee80211_sta_info_flags - Stations flags
> @@ -330,6 +331,32 @@ struct mesh_sta {
> 
> DECLARE_EWMA(signal, 1024, 8)
> 
> +struct txq_info;
> +
> +/**
> + * struct txq_flow - per traffic flow queue
> + *
> + * This structure is used to distinguish and queue different traffic flows
> + * separately for fair queueing/AQM purposes.
> + *
> + * @txqi: txq_info structure it is associated at given time
> + * @flowchain: can be linked to other flows for RR purposes
> + * @backlogchain: can be linked to other flows for backlog sorting purposes
> + * @queue: sk_buff queue
> + * @cvars: codel state vars
> + * @backlog: number of bytes pending in the queue
> + * @deficit: used for fair queueing balancing
> + */
> +struct txq_flow {
> +	struct txq_info *txqi;
> +	struct list_head flowchain;
> +	struct list_head backlogchain;
> +	struct sk_buff_head queue;
> +	struct codel_vars cvars;
> +	int backlog;
> +	int deficit;
> +};
> +
> /**
>  * struct sta_info - STA information
>  *
> diff --git a/net/mac80211/status.c b/net/mac80211/status.c
> index 8b1b2ea03eb5..2cd898f8a658 100644
> --- a/net/mac80211/status.c
> +++ b/net/mac80211/status.c
> @@ -502,6 +502,67 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
> 	}
> }
> 
> +static void ieee80211_report_txq_skb(struct ieee80211_local *local,
> +				     struct ieee80211_hdr *hdr,
> +				     struct sk_buff *skb)
> +{
> +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct ieee80211_sub_if_data *sdata;
> +	struct ieee80211_txq *txq = NULL;
> +	struct sta_info *sta;
> +	struct txq_info *txqi;
> +	struct rhash_head *tmp;
> +	const struct bucket_table *tbl;
> +	int tid;
> +	__le16 fc = hdr->frame_control;
> +	u8 *addr;
> +	static const u8 zeroaddr[ETH_ALEN];
> +
> +	if (!ieee80211_is_data(fc))
> +		return;
> +
> +	rcu_read_lock();
> +
> +	tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
> +	for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) {
> +		/* skip wrong virtual interface */
> +		if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
> +			continue;
> +
> +		tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
> +		txq = sta->sta.txq[tid];
> +
> +		break;
> +	}
> +
> +	if (!txq) {
> +		addr = ieee80211_get_DA(hdr);
> +		if (is_multicast_ether_addr(addr)) {
> +			sdata = ieee80211_sdata_from_skb(local, skb);
> +			txq = sdata->vif.txq;
> +		}
> +	}
> +
> +	if (txq) {
> +		txqi = container_of(txq, struct txq_info, txq);
> +		atomic_sub(info->expected_duration, &txqi->in_flight_usec);
> +		if (atomic_read(&txqi->in_flight_usec) < 0) {
> +			WARN_ON_ONCE(1);
> +			print_hex_dump(KERN_DEBUG, "skb: ", DUMP_PREFIX_OFFSET, 16, 1,
> +						skb->data, skb->len, 0);
> +			printk("underflow: txq tid %d sta %pM vif %s\n",
> +					txq->tid,
> +					txq->sta ? txq->sta->addr : zeroaddr,
> +					container_of(txq->vif, struct ieee80211_sub_if_data, vif)->name);
> +		}
> +	}
> +
> +	atomic_sub(info->expected_duration, &fq->in_flight_usec);
> +
> +	rcu_read_unlock();
> +}
> +
> static void ieee80211_report_used_skb(struct ieee80211_local *local,
> 				      struct sk_buff *skb, bool dropped)
> {
> @@ -512,6 +573,9 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
> 	if (dropped)
> 		acked = false;
> 
> +	if (local->ops->wake_tx_queue)
> +		ieee80211_report_txq_skb(local, hdr, skb);
> +
> 	if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
> 		struct ieee80211_sub_if_data *sdata;
> 
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 6040c29a9e17..3072e460e82a 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -34,6 +34,7 @@
> #include "wpa.h"
> #include "wme.h"
> #include "rate.h"
> +#include "codel.h"
> 
> /* misc utils */
> 
> @@ -1232,27 +1233,335 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
> 	return TX_CONTINUE;
> }
> 
> -static void ieee80211_drv_tx(struct ieee80211_local *local,
> -			     struct ieee80211_vif *vif,
> -			     struct ieee80211_sta *pubsta,
> -			     struct sk_buff *skb)
> +static inline u64
> +custom_codel_get_enqueue_time(struct sk_buff *skb)
> +{
> +	return IEEE80211_SKB_CB(skb)->control.enqueue_time;
> +}
> +
> +static inline struct sk_buff *
> +flow_dequeue(struct ieee80211_local *local, struct txq_flow *flow)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct txq_info *txqi = flow->txqi;
> +	struct txq_flow *i;
> +	struct sk_buff *skb;
> +
> +	skb = __skb_dequeue(&flow->queue);
> +	if (!skb)
> +		return NULL;
> +
> +	txqi->backlog_bytes -= skb->len;
> +	txqi->backlog_packets--;
> +	flow->backlog -= skb->len;
> +	fq->backlog--;
> +
> +	if (flow->backlog == 0) {
> +		list_del_init(&flow->backlogchain);
> +	} else {
> +		i = flow;
> +
> +		list_for_each_entry_continue(i, &fq->backlogs, backlogchain)
> +			if (i->backlog < flow->backlog)
> +				break;
> +
> +		list_move_tail(&flow->backlogchain, &i->backlogchain);
> +	}
> +
> +	return skb;
> +}
> +
> +static inline struct sk_buff *
> +custom_dequeue(struct codel_vars *vars, void *ptr)
> +{
> +	struct txq_flow *flow = ptr;
> +	struct txq_info *txqi = flow->txqi;
> +	struct ieee80211_vif *vif = txqi->txq.vif;
> +	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> +	struct ieee80211_local *local = sdata->local;
> +
> +	return flow_dequeue(local, flow);
> +}
> +
> +static inline void
> +custom_drop(struct sk_buff *skb, void *ptr)
> +{
> +	struct txq_flow *flow = ptr;
> +	struct txq_info *txqi = flow->txqi;
> +	struct ieee80211_vif *vif = txqi->txq.vif;
> +	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> +	struct ieee80211_local *local = sdata->local;
> +	struct ieee80211_hw *hw = &local->hw;
> +
> +	ieee80211_free_txskb(hw, skb);
> +	local->fq.drop_codel++;
> +}
> +
> +static u32 fq_hash(struct ieee80211_fq *fq, struct sk_buff *skb)
> +{
> +	u32 hash = skb_get_hash_perturb(skb, fq->perturbation);
> +	return reciprocal_scale(hash, fq->flows_cnt);
> +}
> +
> +static void fq_drop(struct ieee80211_local *local)
> +{
> +	struct ieee80211_hw *hw = &local->hw;
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct txq_flow *flow;
> +	struct sk_buff *skb;
> +
> +	flow = list_first_entry_or_null(&fq->backlogs, struct txq_flow,
> +					backlogchain);
> +	if (WARN_ON_ONCE(!flow))
> +		return;
> +
> +	skb = flow_dequeue(local, flow);
> +	if (WARN_ON_ONCE(!skb))
> +		return;
> +
> +	ieee80211_free_txskb(hw, skb);
> +	fq->drop_overlimit++;
> +}
> +
> +void ieee80211_init_flow(struct txq_flow *flow)
> +{
> +	INIT_LIST_HEAD(&flow->flowchain);
> +	INIT_LIST_HEAD(&flow->backlogchain);
> +	__skb_queue_head_init(&flow->queue);
> +	codel_vars_init(&flow->cvars);
> +}
> +
> +#define MIN_FQ_TARGET_USEC(fq) ((fq)->min_txops_target * (fq)->txop_mixed_usec)
> +
> +int ieee80211_setup_flows(struct ieee80211_local *local)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +	int i;
> +
> +	if (!local->ops->wake_tx_queue)
> +		return 0;
> +
> +	if (!local->hw.txq_limit)
> +		local->hw.txq_limit = 8192;
> +
> +	memset(fq, 0, sizeof(fq[0]));
> +	INIT_LIST_HEAD(&fq->backlogs);
> +	INIT_LIST_HEAD(&fq->old_flows);
> +	INIT_LIST_HEAD(&fq->new_flows);
> +	ewma_fq_period_init(&fq->ave_period);
> +	atomic_set(&fq->in_flight_usec, 0);
> +	spin_lock_init(&fq->lock);
> +	fq->flows_cnt = 4096;
> +	fq->perturbation = prandom_u32();
> +	fq->quantum = 300;
> +	fq->txop_mixed_usec = 5484;
> +	fq->txop_green_usec = 10000;
> +	fq->min_txops_target = 2;
> +	fq->max_txops_per_txq = 1;
> +	fq->min_txops_per_hw = 3;
> +	fq->max_txops_per_hw = 4;
> +
> +	if (!local->hw.txq_cparams.target)
> +		local->hw.txq_cparams.target = US2TIME(MIN_FQ_TARGET_USEC(fq));
> +
> +	if (!local->hw.txq_cparams.interval)
> +		local->hw.txq_cparams.interval = MS2TIME(100);
> +
> +	fq->flows = kzalloc(fq->flows_cnt * sizeof(fq->flows[0]), GFP_KERNEL);
> +	if (!fq->flows)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < fq->flows_cnt; i++)
> +		ieee80211_init_flow(&fq->flows[i]);
> +
> +	return 0;
> +}
> +
> +static void ieee80211_reset_flow(struct ieee80211_local *local,
> +				 struct txq_flow *flow)
> +{
> +	if (!list_empty(&flow->flowchain))
> +		list_del_init(&flow->flowchain);
> +
> +	if (!list_empty(&flow->backlogchain))
> +		list_del_init(&flow->backlogchain);
> +
> +	ieee80211_purge_tx_queue(&local->hw, &flow->queue);
> +
> +	flow->deficit = 0;
> +	flow->txqi = NULL;
> +}
> +
> +void ieee80211_purge_txq(struct ieee80211_local *local, struct txq_info *txqi)
> +{
> +	struct txq_flow *flow;
> +	int i;
> +
> +	for (i = 0; i < local->fq.flows_cnt; i++) {
> +		flow = &local->fq.flows[i];
> +
> +		if (flow->txqi != txqi)
> +			continue;
> +
> +		ieee80211_reset_flow(local, flow);
> +	}
> +
> +	ieee80211_reset_flow(local, &txqi->flow);
> +
> +	txqi->backlog_bytes = 0;
> +	txqi->backlog_packets = 0;
> +}
> +
> +void ieee80211_teardown_flows(struct ieee80211_local *local)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct ieee80211_sub_if_data *sdata;
> +	struct sta_info *sta;
> +	int i;
> +
> +	if (!local->ops->wake_tx_queue)
> +		return;
> +
> +	list_for_each_entry_rcu(sta, &local->sta_list, list)
> +		for (i = 0; i < IEEE80211_NUM_TIDS; i++)
> +			ieee80211_purge_txq(local,
> +					    to_txq_info(sta->sta.txq[i]));
> +
> +	list_for_each_entry_rcu(sdata, &local->interfaces, list)
> +		ieee80211_purge_txq(local, to_txq_info(sdata->vif.txq));
> +
> +	for (i = 0; i < fq->flows_cnt; i++)
> +		ieee80211_reset_flow(local, &fq->flows[i]);
> +
> +	kfree(fq->flows);
> +
> +	fq->flows = NULL;
> +	fq->flows_cnt = 0;
> +}
> +
> +static void ieee80211_txq_enqueue(struct ieee80211_local *local,
> +				  struct txq_info *txqi,
> +				  struct sk_buff *skb)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct ieee80211_hw *hw = &local->hw;
> +	struct txq_flow *flow;
> +	struct txq_flow *i;
> +	size_t idx = fq_hash(fq, skb);
> +
> +	lockdep_assert_held(&fq->lock);
> +
> +	flow = &fq->flows[idx];
> +
> +	if (flow->txqi && flow->txqi != txqi)
> +		flow = &txqi->flow;
> +
> +	/* The following overwrites `vif` pointer effectively. It is later
> +	 * restored using txq structure.
> +	 */
> +	IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
> +
> +	flow->txqi = txqi;
> +	flow->backlog += skb->len;
> +	txqi->backlog_bytes += skb->len;
> +	txqi->backlog_packets++;
> +	fq->backlog++;
> +
> +	if (list_empty(&flow->backlogchain))
> +		list_add_tail(&flow->backlogchain, &fq->backlogs);
> +
> +	i = flow;
> +	list_for_each_entry_continue_reverse(i, &fq->backlogs, backlogchain)
> +		if (i->backlog > flow->backlog)
> +			break;
> +
> +	list_move(&flow->backlogchain, &i->backlogchain);
> +
> +	if (list_empty(&flow->flowchain)) {
> +		flow->deficit = fq->quantum;
> +		list_add_tail(&flow->flowchain, &txqi->new_flows);
> +	}
> +
> +	if (list_empty(&txqi->flowchain)) {
> +		txqi->deficit = fq->quantum;
> +		list_add_tail(&txqi->flowchain, &fq->new_flows);
> +	}
> +
> +	__skb_queue_tail(&flow->queue, skb);
> +
> +	if (fq->backlog > hw->txq_limit)
> +		fq_drop(local);
> +}
> +
> +static struct sk_buff *ieee80211_txq_dequeue(struct ieee80211_local *local,
> +					     struct txq_info *txqi)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct ieee80211_hw *hw = &local->hw;
> +	struct txq_flow *flow;
> +	struct list_head *head;
> +	struct sk_buff *skb;
> +
> +begin:
> +	head = &txqi->new_flows;
> +	if (list_empty(head)) {
> +		head = &txqi->old_flows;
> +		if (list_empty(head))
> +			return NULL;
> +	}
> +
> +	flow = list_first_entry(head, struct txq_flow, flowchain);
> +
> +	if (flow->deficit <= 0) {
> +		flow->deficit += fq->quantum;
> +		list_move_tail(&flow->flowchain, &txqi->old_flows);
> +		goto begin;
> +	}
> +
> +	skb = codel_dequeue(flow,
> +			    &flow->backlog,
> +			    txqi->bytes_per_burst,
> +			    &flow->cvars,
> +			    &hw->txq_cparams,
> +			    codel_get_time(),
> +			    false);
> +	if (!skb) {
> +		if ((head == &txqi->new_flows) &&
> +		    !list_empty(&txqi->old_flows)) {
> +			list_move_tail(&flow->flowchain, &txqi->old_flows);
> +		} else {
> +			list_del_init(&flow->flowchain);
> +			flow->txqi = NULL;
> +		}
> +		goto begin;
> +	}
> +
> +	flow->deficit -= skb->len;
> +
> +	/* The `vif` pointer was overwritten with enqueue time during
> +	 * enqueuing. Restore it before handing to driver.
> +	 */
> +	IEEE80211_SKB_CB(skb)->control.vif = flow->txqi->txq.vif;
> +
> +	return skb;
> +}
> +
> +static struct txq_info *
> +ieee80211_get_txq(struct ieee80211_local *local,
> +		  struct ieee80211_vif *vif,
> +		  struct ieee80211_sta *pubsta,
> +		  struct sk_buff *skb)
> {
> 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
> -	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> -	struct ieee80211_tx_control control = {
> -		.sta = pubsta,
> -	};
> 	struct ieee80211_txq *txq = NULL;
> -	struct txq_info *txqi;
> -	u8 ac;
>
> 	if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
> 	    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
> -		goto tx_normal;
> +		return NULL;
>
> 	if (!ieee80211_is_data(hdr->frame_control))
> -		goto tx_normal;
> +		return NULL;
>
> 	if (pubsta) {
> 		u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
> @@ -1263,57 +1572,48 @@ static void ieee80211_drv_tx(struct ieee80211_local *local,
> 	}
>
> 	if (!txq)
> -		goto tx_normal;
> +		return NULL;
> 
> -	ac = txq->ac;
> -	txqi = to_txq_info(txq);
> -	atomic_inc(&sdata->txqs_len[ac]);
> -	if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
> -		netif_stop_subqueue(sdata->dev, ac);
> -
> -	spin_lock_bh(&txqi->queue.lock);
> -	txqi->byte_cnt += skb->len;
> -	__skb_queue_tail(&txqi->queue, skb);
> -	spin_unlock_bh(&txqi->queue.lock);
> -
> -	drv_wake_tx_queue(local, txqi);
> -
> -	return;
> -
> -tx_normal:
> -	drv_tx(local, &control, skb);
> +	return to_txq_info(txq);
> }
> 
> +#define TXQI_BYTES_TO_USEC(txqi, bytes) \
> +		DIV_ROUND_UP((bytes), max_t(int, 1, (txqi)->bytes_per_usec))
> +
> struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
> 				     struct ieee80211_txq *txq)
> {
> 	struct ieee80211_local *local = hw_to_local(hw);
> -	struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct ieee80211_tx_info *info;
> 	struct txq_info *txqi = container_of(txq, struct txq_info, txq);
> 	struct ieee80211_hdr *hdr;
> 	struct sk_buff *skb = NULL;
> -	u8 ac = txq->ac;
> +	int duration_usec;
> 
> -	spin_lock_bh(&txqi->queue.lock);
> +	spin_lock_bh(&fq->lock);
>
> 	if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
> 		goto out;
> 
> -	skb = __skb_dequeue(&txqi->queue);
> +	skb = ieee80211_txq_dequeue(local, txqi);
> 	if (!skb)
> 		goto out;
> 
> -	txqi->byte_cnt -= skb->len;
> +	duration_usec = TXQI_BYTES_TO_USEC(txqi, skb->len);
> +	duration_usec = min_t(int, BIT(10) - 1, duration_usec);
> 
> -	atomic_dec(&sdata->txqs_len[ac]);
> -	if (__netif_subqueue_stopped(sdata->dev, ac))
> -		ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
> +	info = IEEE80211_SKB_CB(skb);
> +	info->expected_duration = duration_usec;
> +
> +	txqi->in_flight_delta_usec += duration_usec;
> +	atomic_add(duration_usec, &txqi->in_flight_usec);
> +	atomic_add(duration_usec, &fq->in_flight_usec);
>
> 	hdr = (struct ieee80211_hdr *)skb->data;
> 	if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
> 		struct sta_info *sta = container_of(txq->sta, struct sta_info,
> 						    sta);
> -		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>
> 		hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid);
> 		if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
> @@ -1323,19 +1623,274 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
> 	}
> 
> out:
> -	spin_unlock_bh(&txqi->queue.lock);
> +	spin_unlock_bh(&fq->lock);
>
> 	return skb;
> }
> EXPORT_SYMBOL(ieee80211_tx_dequeue);
> 
> +static u16 ieee80211_get_txop_usec(struct ieee80211_local *local,
> +				   struct txq_info *txqi)
> +{
> +	struct ieee80211_sub_if_data *sdata;
> +	u16 txop_usec;
> +
> +	sdata = container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif);
> +	txop_usec = sdata->tx_conf[txqi->txq.ac].txop * 32;
> +
> +	/* How to pick between mixed/greenfield txops? */
> +	if (txop_usec == 0)
> +		txop_usec = local->fq.txop_mixed_usec;
> +
> +	return txop_usec;
> +}
> +
> +static u32 ieee80211_get_tput_kbps(struct ieee80211_local *local,
> +				   struct txq_info *txqi)
> +{
> +	struct ieee80211_sub_if_data *sdata;
> +	struct ieee80211_supported_band *sband;
> +	struct ieee80211_chanctx_conf *chanctx_conf;
> +	enum ieee80211_band band;
> +	struct rate_control_ref *ref = NULL;
> +	struct sta_info *sta;
> +	int idx;
> +	u32 tput;
> +
> +	if (txqi->txq.sta) {
> +		sta = container_of(txqi->txq.sta, struct sta_info, sta);
> +
> +		if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
> +			ref = local->rate_ctrl;
> +
> +		if (ref)
> +			tput = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
> +		else if (local->ops->get_expected_throughput)
> +			tput = drv_get_expected_throughput(local, &sta->sta);
> +		else
> +			tput = 0;
> +	} else {
> +		sdata = container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif);
> +
> +		rcu_read_lock();
> +		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
> +		band = chanctx_conf->def.chan->band;
> +		rcu_read_unlock();
> +
> +		sband = local->hw.wiphy->bands[band];
> +		idx = sdata->vif.bss_conf.mcast_rate[band];
> +		if (idx > 0) {
> +			/* Convert units from 100Kbps and assume 20% MAC
> +			 * overhead, i.e. 80% efficiency.
> +			 */
> +			tput = sband[band].bitrates[idx].bitrate * 100;
> +			tput = (tput * 8) / 10;
> +		} else {
> +			tput = 1000;
> +		}
> +	}
> +
> +	return tput;
> +}
> +
> +static void ieee80211_recalc_txqi_tput(struct ieee80211_local *local,
> +				       struct txq_info *txqi)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +	int tput_kbps;
> +	int txop_usec;
> +
> +	lockdep_assert_held(&fq->lock);
> +
> +	tput_kbps = ieee80211_get_tput_kbps(local, txqi);
> +	txop_usec = ieee80211_get_txop_usec(local, txqi);
> +	txqi->bytes_per_usec = max_t(int, 1, DIV_ROUND_UP(1024 * (tput_kbps/8),
> +							  USEC_PER_SEC));
> +	txqi->bytes_per_burst = max_t(int, 1, txop_usec * txqi->bytes_per_usec);
> +}
> +
> +void ieee80211_recalc_fq_period(struct ieee80211_hw *hw)
> +{
> +	struct ieee80211_local *local = hw_to_local(hw);
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct txq_info *txqi;
> +	int period = 0;
> +	int target_usec;
> +
> +	spin_lock_bh(&fq->lock);
> +
> +	list_for_each_entry(txqi, &fq->new_flows, flowchain) {
> +		ieee80211_recalc_txqi_tput(local, txqi);
> +
> +		period += TXQI_BYTES_TO_USEC(txqi, min(txqi->backlog_bytes,
> +						       txqi->bytes_per_burst));
> +	}
> +
> +	list_for_each_entry(txqi, &fq->old_flows, flowchain) {
> +		ieee80211_recalc_txqi_tput(local, txqi);
> +
> +		period += TXQI_BYTES_TO_USEC(txqi, min(txqi->backlog_bytes,
> +						       txqi->bytes_per_burst));
> +	}
> +
> +	ewma_fq_period_add(&fq->ave_period, period);
> +
> +	target_usec = ewma_fq_period_read(&fq->ave_period);
> +	target_usec = max_t(u64, target_usec, MIN_FQ_TARGET_USEC(fq));
> +	hw->txq_cparams.target = US2TIME(target_usec);
> +
> +	spin_unlock_bh(&fq->lock);
> +}
> +EXPORT_SYMBOL(ieee80211_recalc_fq_period);
> +
> +static int ieee80211_tx_sched_budget(struct ieee80211_local *local,
> +				     struct txq_info *txqi)
> +{
> +	int txop_usec;
> +	int budget;
> +
> +	/* XXX: Should this consider per-txq or per-sta in flight duration? */
> +	txop_usec = ieee80211_get_txop_usec(local, txqi);
> +	budget = local->fq.max_txops_per_txq * txop_usec;
> +	budget -= atomic_read(&txqi->in_flight_usec);
> +	budget = min(budget, txop_usec);
> +	budget *= min_t(int, 1, txqi->bytes_per_usec);
> +
> +	return budget;
> +}
> +
> +static void ieee80211_tx_sched_next_txqi(struct ieee80211_local *local,
> +					 struct list_head **list,
> +					 struct list_head **head)
> +{
> +	struct ieee80211_fq *fq = &local->fq;
> +
> +	if (!*list) {
> +		*head = &fq->new_flows;
> +		*list = *head;
> +	}
> +
> +	*list = (*list)->next;
> +
> +	if (*list != *head)
> +		return;
> +
> +	if (*head == &fq->new_flows) {
> +		*head = &fq->old_flows;
> +		*list = *head;
> +		ieee80211_tx_sched_next_txqi(local, list, head);
> +		return;
> +	}
> +
> +	*head = NULL;
> +	*list = NULL;
> +}
> +
> +int ieee80211_tx_schedule(struct ieee80211_hw *hw,
> +			  int (*wake)(struct ieee80211_hw *hw,
> +				      struct ieee80211_txq *txq,
> +				      int budget))
> +{
> +	struct ieee80211_local *local = hw_to_local(hw);
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct list_head *list = NULL;
> +	struct list_head *head = NULL;
> +	struct txq_info *txqi = NULL;
> +	int min_in_flight_usec;
> +	int max_in_flight_usec;
> +	int in_flight_usec;
> +	int ret = 0;
> +	int budget;
> +
> +	rcu_read_lock();
> +	spin_lock_bh(&fq->lock);
> +
> +	min_in_flight_usec = fq->min_txops_per_hw * fq->txop_mixed_usec;
> +	max_in_flight_usec = fq->max_txops_per_hw * fq->txop_mixed_usec;
> +	in_flight_usec = atomic_read(&fq->in_flight_usec);
> +
> +	if (in_flight_usec >= min_in_flight_usec) {
> +		ret = -EBUSY;
> +		goto unlock;
> +	}
> +
> +	for (;;) {
> +		if (in_flight_usec >= max_in_flight_usec) {
> +			ret = -EBUSY;
> +			break;
> +		}
> +
> +		if (list && list_is_last(list, &fq->old_flows)) {
> +			ret = -EBUSY;
> +			break;
> +		}
> +
> +		ieee80211_tx_sched_next_txqi(local, &list, &head);
> +		if (!list) {
> +			ret = -ENOENT;
> +			break;
> +		}
> +
> +		txqi = list_entry(list, struct txq_info, flowchain);
> +
> +		if (txqi->deficit < 0) {
> +			txqi->deficit += fq->quantum;
> +			list_move_tail(&txqi->flowchain, &fq->old_flows);
> +			list = NULL;
> +			continue;
> +		}
> +
> +		budget = ieee80211_tx_sched_budget(local, txqi);
> +		txqi->in_flight_delta_usec = 0;
> +
> +		spin_unlock_bh(&fq->lock);
> +		ret = wake(hw, &txqi->txq, budget);
> +		spin_lock_bh(&fq->lock);
> +
> +		if (ret > 0) {
> +			txqi->deficit -= txqi->in_flight_delta_usec;
> +			in_flight_usec += txqi->in_flight_delta_usec;
> +		}
> +
> +		if (!txqi->backlog_bytes) {
> +			if (head == &fq->new_flows && !list_empty(&fq->old_flows)) {
> +				list_move_tail(&txqi->flowchain, &fq->old_flows);
> +			} else {
> +				list_del_init(&txqi->flowchain);
> +			}
> +
> +			list = NULL;
> +		}
> +
> +		if (ret < 0) {
> +			ret = -EBUSY;
> +			break;
> +		} else if (ret == 0 && txqi) {
> +			/* `list` is not reset to skip over */
> +			continue;
> +		}
> +
> +		list = NULL;
> +	}
> +
> +unlock:
> +	spin_unlock_bh(&fq->lock);
> +	rcu_read_unlock();
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(ieee80211_tx_schedule);
> +
> static bool ieee80211_tx_frags(struct ieee80211_local *local,
> 			       struct ieee80211_vif *vif,
> 			       struct ieee80211_sta *sta,
> 			       struct sk_buff_head *skbs,
> 			       bool txpending)
> {
> +	struct ieee80211_fq *fq = &local->fq;
> +	struct ieee80211_tx_control control = {};
> 	struct sk_buff *skb, *tmp;
> +	struct txq_info *txqi;
> 	unsigned long flags;
>
> 	skb_queue_walk_safe(skbs, skb, tmp) {
> @@ -1350,6 +1905,24 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
> 		}
> #endif
> 
> +		/* XXX: This changes behavior for offchan-tx. Is this really a
> +		 *      problem with per-sta-tid queueing now?
> +		 */
> +		txqi = ieee80211_get_txq(local, vif, sta, skb);
> +		if (txqi) {
> +			info->control.vif = vif;
> +
> +			__skb_unlink(skb, skbs);
> +
> +			spin_lock_bh(&fq->lock);
> +			ieee80211_txq_enqueue(local, txqi, skb);
> +			spin_unlock_bh(&fq->lock);
> +
> +			drv_wake_tx_queue(local, txqi);
> +
> +			continue;
> +		}
> +
> 		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
> 		if (local->queue_stop_reasons[q] ||
> 		    (!txpending && !skb_queue_empty(&local->pending[q]))) {
> @@ -1392,9 +1965,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
> 		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
>
> 		info->control.vif = vif;
> +		control.sta = sta;
>
> 		__skb_unlink(skb, skbs);
> -		ieee80211_drv_tx(local, vif, sta, skb);
> +		drv_tx(local, &control, skb);
> 	}
>
> 	return true;
> @@ -2381,7 +2955,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
>
> 			spin_lock_irqsave(&local->ack_status_lock, flags);
> 			id = idr_alloc(&local->ack_status_frames, ack_skb,
> -				       1, 0x10000, GFP_ATOMIC);
> +				       1, 0x8000, GFP_ATOMIC);
> 			spin_unlock_irqrestore(&local->ack_status_lock, flags);
>
> 			if (id >= 0) {
> diff --git a/net/mac80211/util.c b/net/mac80211/util.c
> index 0319d6d4f863..afb1bbf9b3f4 100644
> --- a/net/mac80211/util.c
> +++ b/net/mac80211/util.c
> @@ -244,6 +244,9 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
> 	struct ieee80211_sub_if_data *sdata;
> 	int n_acs = IEEE80211_NUM_ACS;
> 
> +	if (local->ops->wake_tx_queue)
> +		return;
> +
> 	if (local->hw.queues < IEEE80211_NUM_ACS)
> 		n_acs = 1;
> 
> @@ -260,11 +263,6 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
> 		for (ac = 0; ac < n_acs; ac++) {
> 			int ac_queue = sdata->vif.hw_queue[ac];
> 
> -			if (local->ops->wake_tx_queue &&
> -			    (atomic_read(&sdata->txqs_len[ac]) >
> -			     local->hw.txq_ac_max_pending))
> -				continue;
> -
> 			if (ac_queue == queue ||
> 			    (sdata->vif.cab_queue == queue &&
> 			     local->queue_stop_reasons[ac_queue] == 0 &&
> @@ -352,6 +350,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
> 	if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
> 		return;
> 
> +	if (local->ops->wake_tx_queue)
> +		return;
> +
> 	if (local->hw.queues < IEEE80211_NUM_ACS)
> 		n_acs = 1;
> 
> @@ -3392,8 +3393,12 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
> 			     struct sta_info *sta,
> 			     struct txq_info *txqi, int tid)
> {
> -	skb_queue_head_init(&txqi->queue);
> +	INIT_LIST_HEAD(&txqi->flowchain);
> +	INIT_LIST_HEAD(&txqi->old_flows);
> +	INIT_LIST_HEAD(&txqi->new_flows);
> +	ieee80211_init_flow(&txqi->flow);
> 	txqi->txq.vif = &sdata->vif;
> +	txqi->flow.txqi = txqi;
>
> 	if (sta) {
> 		txqi->txq.sta = &sta->sta;
> @@ -3414,9 +3419,9 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
> 	struct txq_info *txqi = to_txq_info(txq);
>
> 	if (frame_cnt)
> -		*frame_cnt = txqi->queue.qlen;
> +		*frame_cnt = txqi->backlog_packets;
>
> 	if (byte_cnt)
> -		*byte_cnt = txqi->byte_cnt;
> +		*byte_cnt = txqi->backlog_bytes;
> }
> EXPORT_SYMBOL(ieee80211_txq_get_depth);
> -- 
> 2.1.4
>
> _______________________________________________
> Make-wifi-fast mailing list
> Make-wifi-fast@lists.bufferbloat.net
> https://lists.bufferbloat.net/listinfo/make-wifi-fast
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel

^ permalink raw reply

* Re: [PATCH net-next] net/mlx4_core: Fix backward compatibility on VFs
From: Alexey Kardashevskiy @ 2016-03-22  1:24 UTC (permalink / raw)
  To: Eli Cohen
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q, linux-rdma-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20160321135630.GA95906-lgQlq6cFzJSjLWYaRI30zHI+JuX82XLG@public.gmane.org>

On 03/22/2016 12:56 AM, Eli Cohen wrote:
> On Mon, Mar 21, 2016 at 04:02:16PM +1100, Alexey Kardashevskiy wrote:
>>
>> After more tries, I found that if for whatever reason mlx4_core
>> fails to stop while shutting the guest down (last message is
>> "mlx4_core 0000:00:00.0: mlx4_shutdown was called"), then next time
>> VF in guest won't start.
>>
>> Example #1:
>>
>> mlx4_core: Mellanox ConnectX core driver v2.2-1 (Feb, 2014)
>> mlx4_core: Initializing 0000:00:00.0
>> mlx4_core 0000:00:00.0: enabling device (0000 -> 0002)
>> mlx4_core 0000:00:00.0: Detected virtual function - running in slave mode
>> mlx4_core 0000:00:00.0: Sending reset
>> mlx4_core 0000:00:00.0: Sending vhcr0
>> mlx4_core 0000:00:00.0: HCA minimum page size:1
>> mlx4_core 0000:00:00.0: UAR size:4096 != kernel PAGE_SIZE of 65536
>> mlx4_core 0000:00:00.0: Failed to obtain slave caps
>
> Alexey, can you verify that the value of the enable_4k_uar parameter
> is false?

aik@fstn1-p1:~$ cat 
/sys/bus/pci/drivers/mlx4_core/module/parameters/enable_4k_uar
N
aik@fstn1-p1:~$



>
>>
>> Example #2:
>>
>> root@le-dbg:~# dhclient eth0
>> NETDEV WATCHDOG: eth0 (mlx4_core): transmit queue 11 timed out
>> ------------[ cut here ]------------
>> WARNING: at /home/aik/p/guest-kernel/net/sched/sch_generic.c:303
>>
>> and no IP assigned, timed out.
>>
>>
>> This is fixed by the guest restart, first restart might not help,
>> then the second restart will.
>>
>> The host is running the latest upstream plus the patch I am replying
>> to. The guest is using initramdisk from debian bootstrap and vanilla
>> v4.2 kernel, ppc64le arch, POWER8 chip, QEMU is running with 1 CPU
>> and 2GB of RAM.
>>
>> Does this look any familiar?
>>
>
> This is completely unrelated to the compatibility problem you reported
> and which this patch addresses. We will reproduce in house and post a
> fix.


Example #2 is but example #1 mentions "UAR size" :)



-- 
Alexey
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH RESEND] net: ipv4: Fix truncated timestamp returned by inet_current_timestamp()
From: Deepa Dinamani @ 2016-03-22  1:21 UTC (permalink / raw)
  To: netdev, y2038
  Cc: David S. Miller, Alexey Kuznetsov, Hideaki YOSHIFUJI,
	James Morris, Patrick McHardy, Arnd Bergmann

The millisecond timestamps returned by the function is
converted to network byte order by making a call to htons().
htons() only returns __be16 while __be32 is required here.

This was identified by the sparse warning from the buildbot:
net/ipv4/af_inet.c:1405:16: sparse: incorrect type in return
			    expression (different base types)
net/ipv4/af_inet.c:1405:16: expected restricted __be32
net/ipv4/af_inet.c:1405:16: got restricted __be16 [usertype] <noident>

Change the function to use htonl() to return the correct __be32 type
instead so that the millisecond value doesn't get truncated.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: James Morris <jmorris@namei.org>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Arnd Bergmann <arnd@arndb.de>
Fixes: 822c868532ca ("net: ipv4: Convert IP network timestamps to be y2038 safe")
Reported-by: Fengguang Wu <fengguang.wu@intel.com> [0-day test robot]
---
Fixed the y2038 list email address.

 net/ipv4/af_inet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0cc923f..5fab7e3 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1402,7 +1402,7 @@ __be32 inet_current_timestamp(void)
 	msecs += (u32)ts.tv_nsec / NSEC_PER_MSEC;
 
 	/* Convert to network byte order. */
-	return htons(msecs);
+	return htonl(msecs);
 }
 EXPORT_SYMBOL(inet_current_timestamp);
 
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH net 09/10] net: hns: adds limitation for debug port mtu
From: Yisen Zhuang @ 2016-03-22  1:19 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davem, yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
	linux-kernel, linuxarm
In-Reply-To: <56F0028D.4070500@cogentembedded.com>



在 2016/3/21 22:17, Sergei Shtylyov 写道:
> Hello.
> 
> On 03/21/2016 02:06 PM, Yisen Zhuang wrote:
> 
>> From: Kejian Yan <yankejian@huawei.com>
>>
>> If mtu for debug port is set more than 1500, it may cause that packets
>> are dropped by ppe. So maximum value for debug port should be 1500.
>>
>> Signed-off-by: Kejian Yan <yankejian@huawei.com>
>> Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
> [...]
>> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
>> index a69c8af..a68efd6 100644
>> --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
>> +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
>> @@ -28,6 +28,7 @@ struct dsaf_device;
>>   #define MAC_MAX_MTU        9600
>>   #define MAC_MAX_MTU_V2        9728
>>   #define MAC_MIN_MTU        68
>> +#define MAC_MAX_MTU_DBG         MAC_DEFAULT_MTU
> 
>    Please use tabs, not spaces to indent the value, like above

Will fix it in next version.

Thanks,

Yisen

> 
> [...]
> 
> MBR, Sergei
> 
> 
> .
> 

^ permalink raw reply

* Re: [PATCH net 06/10] net: hns: fix return value of the function about rss
From: Yisen Zhuang @ 2016-03-22  1:16 UTC (permalink / raw)
  To: David Miller
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
	linux-kernel, linuxarm
In-Reply-To: <20160321.114238.1469581550499984000.davem@davemloft.net>



在 2016/3/21 23:42, David Miller 写道:
> From: Yisen Zhuang <Yisen.Zhuang@huawei.com>
> Date: Mon, 21 Mar 2016 19:06:37 +0800
> 
>> diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
>> index 3c4a3bc..f3a5e05 100644
>> --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
>> +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
>  ...
>> @@ -1235,12 +1226,11 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
>>  {
>>  	struct hns_nic_priv *priv = netdev_priv(netdev);
>>  	struct hnae_ae_ops *ops;
>> -	int ret;
>>  
>>  	if (AE_IS_VER1(priv->enet_ver)) {
>>  		netdev_err(netdev,
>>  			   "RSS feature is not supported on this hardware\n");
>> -		return -EOPNOTSUPP;
>> +		return (u32)-EOPNOTSUPP;
>>  	}
>>  
> 
> This is incredibly broken, you cannot cast this negative error return value to
> an unsigned integer.
> 
Hi David,

This is my misunderstanding of the return value. Will fix it in next version.

Many thanks,

Yisen

> .
> 

^ permalink raw reply

* Re: [PATCH net 03/10] net: hns: add uc match for debug ports
From: Yisen Zhuang @ 2016-03-22  1:03 UTC (permalink / raw)
  To: David Miller
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
	linux-kernel, linuxarm
In-Reply-To: <20160321.114055.845640249977716034.davem@davemloft.net>



在 2016/3/21 23:40, David Miller 写道:
> From: Yisen Zhuang <Yisen.Zhuang@huawei.com>
> Date: Mon, 21 Mar 2016 19:06:34 +0800
> 
>> +	(void)hns_mac_set_promisc(mac_cb, (u8)!!en);
> 
> This cast to void is unnecssary.

I think hns_mac_set_promisc don't need to return a value, so i will fix it in next submit.

Thanks

> 
>> +static void hns_gmac_set_uc_match(void *mac_drv, u16 en)
>> +{
>> +	struct mac_driver *drv = (struct mac_driver *)mac_drv;
> 
> Casts from void pointers are unnecessary.

Will fix it in next submit.

Thanks

> 
>> +{
>> +	struct mac_driver *drv = (struct mac_driver *)mac_drv;
> 
> Likewise.

Will fix it in next submit.

Thanks,

Yisen

> 
> .
> 

^ permalink raw reply

* Re: [PATCH net 01/10] net: hns: bug fix about ping6
From: Yisen Zhuang @ 2016-03-22  0:46 UTC (permalink / raw)
  To: David Miller
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, xieqianqian, andrew, ivecera, netdev,
	linux-kernel, linuxarm
In-Reply-To: <20160321.113924.1745428836278929494.davem@davemloft.net>



在 2016/3/21 23:39, David Miller 写道:
> From: Yisen Zhuang <Yisen.Zhuang@huawei.com>
> Date: Mon, 21 Mar 2016 19:06:32 +0800
> 
>> From: Kejian Yan <yankejian@huawei.com>
>>
>> The current upstreaming code fails to ping other IPv6 net device, because
>> the enet receives the multicast packets with the src mac addr whick is the
>                                                                 ^^^^^
> 
> "which"

Will fix it in next submit.

Thanks

> 
>> @@ -670,6 +671,14 @@ out_bnum_err:
>>  		return -EFAULT;
>>  	}
>>  
>> +	/* filter out multicast pkt with the same src mac as this port */
>> +	eh = (struct ethhdr *)skb->data;
> 
> Please use the "eth_hdr()" helper.

Will fix it in next submit.

Thanks,

Yisen

> 
> .
> 

^ permalink raw reply

* [PATCH 1/1] net: ipv4: Fix truncated timestamp returned by inet_current_timestamp()
From: Deepa Dinamani @ 2016-03-22  0:41 UTC (permalink / raw)
  To: y2038, netdev
  Cc: David S. Miller, Alexey Kuznetsov, Hideaki YOSHIFUJI,
	James Morris, Patrick McHardy, Arnd Bergmann

The millisecond timestamps returned by the function is
converted to network byte order by making a call to htons().
htons() only returns __be16 while __be32 is required here.

This was identified by the sparse warning from the buildbot:
net/ipv4/af_inet.c:1405:16: sparse: incorrect type in return
			    expression (different base types)
net/ipv4/af_inet.c:1405:16: expected restricted __be32
net/ipv4/af_inet.c:1405:16: got restricted __be16 [usertype] <noident>

Change the function to use htonl() to return the correct __be32 type
instead so that the millisecond value doesn't get truncated.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: James Morris <jmorris@namei.org>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Arnd Bergmann <arnd@arndb.de>
Fixes: 822c868532ca ("net: ipv4: Convert IP network timestamps to be y2038 safe")
Reported-by: Fengguang Wu <fengguang.wu@intel.com> [0-day test robot]
---
 net/ipv4/af_inet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0cc923f..5fab7e3 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1402,7 +1402,7 @@ __be32 inet_current_timestamp(void)
 	msecs += (u32)ts.tv_nsec / NSEC_PER_MSEC;
 
 	/* Convert to network byte order. */
-	return htons(msecs);
+	return htonl(msecs);
 }
 EXPORT_SYMBOL(inet_current_timestamp);
 
-- 
1.9.1

^ permalink raw reply related

* Make DST_CACHE a silent config option
From: Dave Jones @ 2016-03-21 22:37 UTC (permalink / raw)
  To: netdev

commit 911362c70d ("net: add dst_cache support") added a new
kconfig option that gets selected by other networking options.
It seems the intent wasn't to offer this as a user-selectable
option given the lack of help text, so this patch converts it
to a silent option.

Signed-off-by: Dave Jones <davej@codemonkey.org.uk>

diff --git a/net/Kconfig b/net/Kconfig
index e13449870d06..a8934d8c8fda 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -397,7 +397,7 @@ config LWTUNNEL
 	  with light weight tunnel state associated with fib routes.
 
 config DST_CACHE
-	bool "dst cache"
+	bool
 	default n
 
 config NET_DEVLINK

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox