Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 8/8 V3] rtlwifi: Remove all remaining references to variable 'noise' in rtl_stats struct
From: Larry Finger @ 2013-09-18 19:58 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev
In-Reply-To: <1379534339-14895-5-git-send-email-Larry.Finger@lwfinger.net>

This completes removal of all places that reference variable 'noise'
in the rtl_stats struct. The definition of the struct is unchanged.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 1 -
 drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 1 -
 drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 1 -
 drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 1 -
 4 files changed, 4 deletions(-)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -477,7 +477,6 @@ bool rtl88ee_rx_query_desc(struct ieee80
 
 	/*rx_status->qual = status->signal; */
 	rx_status->signal = status->recvsignalpower + 10;
-	/*rx_status->noise = -status->noise; */
 	if (status->packet_report_type == TX_REPORT2) {
 		status->macid_valid_entry[0] =
 			 GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -420,7 +420,6 @@ bool rtl92ce_rx_query_desc(struct ieee80
 
 	/*rx_status->qual = stats->signal; */
 	rx_status->signal = stats->recvsignalpower + 10;
-	/*rx_status->noise = -stats->noise; */
 
 	return true;
 }
Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -330,7 +330,6 @@ bool rtl92se_rx_query_desc(struct ieee80
 
 	/*rx_status->qual = stats->signal; */
 	rx_status->signal = stats->rssi + 10;
-	/*rx_status->noise = -stats->noise; */
 
 	return true;
 }
Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -359,7 +359,6 @@ bool rtl8723ae_rx_query_desc(struct ieee
 
 	/*rx_status->qual = status->signal; */
 	rx_status->signal = status->recvsignalpower + 10;
-	/*rx_status->noise = -status->noise; */
 
 	return true;
 }

^ permalink raw reply

* [PATCH 7/8 V3] rtlwifi: rtl8188ee: Fix smatch warning in rtl8188ee/hw.c
From: Larry Finger @ 2013-09-18 19:58 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev, Stable
In-Reply-To: <1379534339-14895-5-git-send-email-Larry.Finger@lwfinger.net>

Smatch lists the following:
  CHECK   drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
drivers/net/wireless/rtlwifi/rtl8188ee/hw.c:149 _rtl88ee_set_fw_clock_on() info: ignoring unreachable code.
drivers/net/wireless/rtlwifi/rtl8188ee/hw.c:149 _rtl88ee_set_fw_clock_on() info: ignoring unreachable code.

This info message is the result of a real error due to a missing break statement
in a "while (1)" loop.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org> [3.10+]
---
 drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 1 +
 1 file changed, 1 insertion(+)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -143,6 +143,7 @@ static void _rtl88ee_set_fw_clock_on(str
 		} else {
 			rtlhal->fw_clk_change_in_progress = false;
 			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			break;
 		}
 	}
 

^ permalink raw reply

* [PATCH 6/8 V3] rtlwifi: Fix smatch warnings in usb.c
From: Larry Finger @ 2013-09-18 19:58 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev
In-Reply-To: <1379534339-14895-5-git-send-email-Larry.Finger@lwfinger.net>

Smatch displays the following:
  CHECK   drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/usb.c:458 _rtl_usb_rx_process_agg() warn: assigning (-98) to unsigned variable 'stats.noise'
drivers/net/wireless/rtlwifi/usb.c:503 _rtl_usb_rx_process_noagg() warn: assigning (-98) to unsigned variable 'stats.noise'
drivers/net/wireless/rtlwifi/usb.c:596 _rtl_rx_get_padding() info: ignoring unreachable code.
drivers/net/wireless/rtlwifi/usb.c:596 _rtl_rx_get_padding() info: ignoring unreachable code.

The variable 'stats.noise' is not used, thus the initializers are removed.
The unreachable code info is fixed by including the appropriate section inside
#ifdef .. #endif constructions.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/usb.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/usb.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/usb.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/usb.c
@@ -455,7 +455,6 @@ static void _rtl_usb_rx_process_agg(stru
 	struct ieee80211_rx_status rx_status = {0};
 	struct rtl_stats stats = {
 		.signal = 0,
-		.noise = -98,
 		.rate = 0,
 	};
 
@@ -498,7 +497,6 @@ static void _rtl_usb_rx_process_noagg(st
 	struct ieee80211_rx_status rx_status = {0};
 	struct rtl_stats stats = {
 		.signal = 0,
-		.noise = -98,
 		.rate = 0,
 	};
 
@@ -582,12 +580,15 @@ static void _rtl_rx_work(unsigned long p
 static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr,
 					unsigned int len)
 {
+#if NET_IP_ALIGN != 0
 	unsigned int padding = 0;
+#endif
 
 	/* make function no-op when possible */
 	if (NET_IP_ALIGN == 0 || len < sizeof(*hdr))
 		return 0;
 
+#if NET_IP_ALIGN != 0
 	/* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */
 	/* TODO: deduplicate common code, define helper function instead? */
 
@@ -608,6 +609,7 @@ static unsigned int _rtl_rx_get_padding(
 		padding ^= NET_IP_ALIGN;
 
 	return padding;
+#endif
 }
 
 #define __RADIO_TAP_SIZE_RSV	32

^ permalink raw reply

* [PATCH 5/8 V3] rtlwifi: Fix smatch warning in pci.c
From: Larry Finger @ 2013-09-18 19:58 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev
In-Reply-To: <1379534339-14895-5-git-send-email-Larry.Finger@lwfinger.net>

Smatch reports the following:
  CHECK   drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/pci.c:739 _rtl_pci_rx_interrupt() warn: assigning (-98) to unsigned variable 'stats.noise'

The variable 'stats.noise' is not used. That initializer is removed.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/pci.c | 1 -
 1 file changed, 1 deletion(-)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/pci.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/pci.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/pci.c
@@ -736,7 +736,6 @@ static void _rtl_pci_rx_interrupt(struct
 
 	struct rtl_stats stats = {
 		.signal = 0,
-		.noise = -98,
 		.rate = 0,
 	};
 	int index = rtlpci->rx_ring[rx_queue_idx].idx;

^ permalink raw reply

* [PATCH 4/8 V3] rtlwifi: rtl8192_common: Fix smatch errors and warnings in rtl8192c/dm_common.c
From: Larry Finger @ 2013-09-18 19:58 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev

Smatch lists the following:
  CHECK   drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:551 rtl92c_dm_pwdb_monitor() info: ignoring unreachable code.
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:551 rtl92c_dm_pwdb_monitor() info: ignoring unreachable code.
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:870 rtl92c_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'txpwr_level' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:870 rtl92c_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'txpwr_level' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:882 rtl92c_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'txpwr_level' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:883 rtl92c_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'txpwr_level' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:891 rtl92c_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'txpwr_level' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c:892 rtl92c_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'txpwr_level' 2 <= 2

The unreachable code message is fixed by deleting the code that follows a return.

The errors are fixed by increasing the size of txpwr_level.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c |   25 +------------------------
 1 file changed, 1 insertion(+), 24 deletions(-)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -541,29 +541,6 @@ EXPORT_SYMBOL(rtl92c_dm_write_dig);
 
 static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff;
-
-	u8 h2c_parameter[3] = { 0 };
-
-	return;
-
-	if (tmpentry_max_pwdb != 0) {
-		rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb;
-	} else {
-		rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
-	}
-
-	if (tmpentry_min_pwdb != 0xff) {
-		rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb;
-	} else {
-		rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
-	}
-
-	h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);
-	h2c_parameter[0] = 0;
-
-	rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
 }
 
 void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw)
@@ -673,7 +650,7 @@ static void rtl92c_dm_txpower_tracking_c
 	s8 cck_index = 0;
 	int i;
 	bool is2t = IS_92C_SERIAL(rtlhal->version);
-	s8 txpwr_level[2] = {0, 0};
+	s8 txpwr_level[3] = {0, 0, 0};
 	u8 ofdm_min_index = 6, rf;
 
 	rtlpriv->dm.txpower_trackinginit = true;

^ permalink raw reply

* [PATCH 2/8 V3] rtlwifi: rtl8192de: Fix smatch warnings in rtl8192de/hw.c
From: Larry Finger @ 2013-09-18 19:57 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev
In-Reply-To: <1379534260-14841-1-git-send-email-Larry.Finger@lwfinger.net>

Smatch lists the following:
  CHECK   drivers/net/wireless/rtlwifi/rtl8192de/hw.c
drivers/net/wireless/rtlwifi/rtl8192de/hw.c:1200 rtl92de_set_qos() info: ignoring unreachable code.
drivers/net/wireless/rtlwifi/rtl8192de/hw.c:1200 rtl92de_set_qos() info: ignoring unreachable code.

The dead code is deleted.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/rtl8192de/hw.c |   19 -------------------
 1 file changed, 19 deletions(-)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -1194,25 +1194,6 @@ void rtl92d_linked_set_reg(struct ieee80
  * mac80211 will send pkt when scan */
 void rtl92de_set_qos(struct ieee80211_hw *hw, int aci)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	rtl92d_dm_init_edca_turbo(hw);
-	return;
-	switch (aci) {
-	case AC1_BK:
-		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
-		break;
-	case AC0_BE:
-		break;
-	case AC2_VI:
-		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
-		break;
-	case AC3_VO:
-		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
-		break;
-	default:
-		RT_ASSERT(false, "invalid aci: %d !\n", aci);
-		break;
-	}
 }
 
 void rtl92de_enable_interrupt(struct ieee80211_hw *hw)

^ permalink raw reply

* [PATCH 1/8 V3] rtlwifi: rtl8192du: Fix smatch errors in /rtl8192de/dm.c
From: Larry Finger @ 2013-09-18 19:57 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev
In-Reply-To: <1379534260-14841-1-git-send-email-Larry.Finger@lwfinger.net>

Smatch lists the following:
  CHECK   drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1054 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'ofdm_index' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1056 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'ofdm_index' 2 <= 2
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1126 rtl92d_dm_txpower_tracking_callback_thermalmeter() debug: remove_pools: nr_children over 4000 (4596). (rtlpriv->dbg.global_debuglevel merged)
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1126 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1129 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1132 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1135 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1138 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1141 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1144 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1147 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch1ch13' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1151 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1154 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1157 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1160 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1163 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1166 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1169 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255
drivers/net/wireless/rtlwifi/rtl8192de/dm.c:1172 rtl92d_dm_txpower_tracking_callback_thermalmeter() error: buffer overflow 'cckswing_table_ch14' 33 <= 255

This patch fixes several off-by-one errors. It also removes a comment
referencing variable 'noise' in the rts_stats struct.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/rtl8192de/dm.c  | 8 ++++++--
 drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 1 -
 2 files changed, 6 insertions(+), 3 deletions(-)

Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -840,9 +840,9 @@ static void rtl92d_dm_txpower_tracking_c
 	bool internal_pa = false;
 	long ele_a = 0, ele_d, temp_cck, val_x, value32;
 	long val_y, ele_c = 0;
-	u8 ofdm_index[2];
+	u8 ofdm_index[3];
 	s8 cck_index = 0;
-	u8 ofdm_index_old[2] = {0, 0};
+	u8 ofdm_index_old[3] = {0, 0, 0};
 	s8 cck_index_old = 0;
 	u8 index;
 	int i;
@@ -1118,6 +1118,10 @@ static void rtl92d_dm_txpower_tracking_c
 				 val_x, val_y, ele_a, ele_c, ele_d,
 				 val_x, val_y);
 
+			if (cck_index >= CCK_TABLE_SIZE)
+				cck_index = CCK_TABLE_SIZE - 1;
+			if (cck_index < 0)
+				cck_index = 0;
 			if (rtlhal->current_bandtype == BAND_ON_2_4G) {
 				/* Adjust CCK according to IQK result */
 				if (!rtlpriv->dm.cck_inch14) {
Index: wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
===================================================================
--- wireless-testing-save.orig/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ wireless-testing-save/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -526,7 +526,6 @@ bool rtl92de_rx_query_desc(struct ieee80
 	}
 	/*rx_status->qual = stats->signal; */
 	rx_status->signal = stats->rssi + 10;
-	/*rx_status->noise = -stats->noise; */
 	return true;
 }
 

^ permalink raw reply

* [PATCH 0/8 V3] rtlwifi: Patches to fix problems shown by smatch
From: Larry Finger @ 2013-09-18 19:57 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Larry Finger, netdev

Fix smatch warnings and errors in the rtlwifi family of drivers.

V2 addresses comments by David Laight and Sergei Shtylyov.
V3 addresses further comments by David, Sergei, and Kalle Valo. The
   dead code is removed, and the variable is left in the struct.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---

Larry Finger (8):
  rtlwifi: rtl8192du: Fix smatch errors in /rtl8192de/dm.c
  rtlwifi: rtl8192de: Fix smatch warnings in rtl8192de/hw.c
  rtlwifi: rtl8192cu: Fix smatch warning in rtl8192cu/trx.c
  rtlwifi: rtl8192_common: Fix smatch errors and warnings in
    rtl8192c/dm_common.c
  rtlwifi: Fix smatch warning in pci.c
  rtlwifi: Fix smatch warnings in usb.c
  rtlwifi: rtl8188ee: Fix smatch warning in rtl8188ee/hw.c
  rtlwifi: Remove all remaining references to variable 'noise'
    in rtl_stats struct

 drivers/net/wireless/rtlwifi/pci.c                | 1 -
 drivers/net/wireless/rtlwifi/rtl8188ee/hw.c       | 1 +
 drivers/net/wireless/rtlwifi/rtl8188ee/trx.c      | 1 -
 drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c | 4 +++-
 drivers/net/wireless/rtlwifi/rtl8192ce/trx.c      | 1 -
 drivers/net/wireless/rtlwifi/rtl8192cu/trx.c      | 2 --
 drivers/net/wireless/rtlwifi/rtl8192de/dm.c       | 8 ++++++--
 drivers/net/wireless/rtlwifi/rtl8192de/hw.c       | 2 ++
 drivers/net/wireless/rtlwifi/rtl8192de/trx.c      | 1 -
 drivers/net/wireless/rtlwifi/rtl8192se/trx.c      | 1 -
 drivers/net/wireless/rtlwifi/rtl8723ae/trx.c      | 1 -
 drivers/net/wireless/rtlwifi/usb.c                | 6 ++++--
 drivers/net/wireless/rtlwifi/wifi.h               | 1 -
 13 files changed, 16 insertions(+), 14 deletions(-)

-- 
1.8.1.4


^ permalink raw reply

* Re: fyi: scheduling while atomic dmesg output 3.12-rc1
From: Arend van Spriel @ 2013-09-18 17:11 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: Joe Perches, brcm80211-dev-list, linux-wireless,
	Rafał Miłecki
In-Reply-To: <5239B12D.3040206@hauke-m.de>

On 09/18/2013 03:57 PM, Hauke Mehrtens wrote:
> On 09/18/2013 11:19 AM, Arend van Spriel wrote:
>> On 09/17/2013 07:45 PM, Joe Perches wrote:
>>> <3>[   11.206312] BUG: scheduling while atomic:
>>> NetworkManager/866/0x00000200
>>
>> Thanks, Joe
>>
>> I got a report on this few days ago. It was introduced by bcma API
>> change and I already sent email to the committer of that change, ie.
>> Hauke Mehrtens. Hope it will be settled soon how to fix this.
>>
>> Gr. AvS
>
> Hi,
>
> I see four solutions for the problem:
>
> 1. convert the usleep_range(1000, 2000) into udelay(1000) in
> drivers/bcma/driver_pci.c
>
> 2. remove the call of bcma_core_pci_power_save() from bcma_core_pci_up()
> so that it does not get called by brcmsmac.
>
> 3. remove the call of bcma_core_pci_power_save() from bcma_core_pci_up()
> and move the call to somewhere out of the big spin lock.
>
> 4. convert the big brmcsmac spin lock into a mutex lock and use an
> additional spin lock for the parts where it is actually needed.
>
> For 3.12 I am for solution 1 or 2 and for the long term 3.13? I am for
> solution 4, but that needs bigger changes.

Agree. When looking into this I considered option 4 would be a bigger 
work, but I agree we should aim for that in the long term. For the short 
term I would say option 2 makes sense although I guess the power_save 
call is there for a reason. So I will also look if option 3 is doable.

Regards,
Arend



^ permalink raw reply

* Re: RT3573 wpa_supplicant: "nl80211: Delete station $my_ap" after "SME: Send 20/40 BSS Coexistence to $my_ap"
From: Peter Stuge @ 2013-09-18 15:42 UTC (permalink / raw)
  To: Xose Vazquez Perez; +Cc: linux-wireless, users@rt2x00.serialmonkey.com
In-Reply-To: <5239A815.40909@gmail.com>

Xose Vazquez Perez wrote:
> > I'm testing the WNDA4100 with torvalds/linux.git and as of a day or
> > two ago and wpa_supplicant-2.0.
> > 
> > I haven't measured throughput. Latency is really bad for interactive
> > connections, but at least the packets are flowing on all bands. Yay!
> > 
> > Ping to the access point is around 3 ms with the odd 20+ ms when the
> > kernel goes off to do something else.
> 
> Support for RT3573 was added recently, you should use wireless-next:
> http://git.kernel.org/cgit/linux/kernel/git/linville/wireless-next.git

I made a typo in my first email - it should have read:

"I'm testing the WNDA4100 with torvalds/linux.git as of a day or two ago"

I am on linux.git commit d8efd82eece89f8a5790b0febf17522affe9e1f1
which contains commit f212781, current wireless-next/master HEAD.

I also looked on the rt2x00 list for proposed 3573 patches but didn't
see any. I hope I already have the latest code.

Do you suspect that my problem (as described briefly in the email
subject and with more detail after the part of my email which you
quoted) is related to the device driver rather than higher-up parts
of the stack?


> You can also try latest fw(v0.33):
> http://rt2x00.serialmonkey.com/pipermail/users_rt2x00.serialmonkey.com/attachments/20130111/f8ebe4d3/attachment.bin

Thanks! Will try this and get back to you.

But why isn't this file in linux-firmware.git? Especially if it was
sent already in January?


Kind regards

//Peter

^ permalink raw reply

* Question on 802.11n feature
From: Cedric VONCKEN @ 2013-09-18 15:13 UTC (permalink / raw)
  To: linux-wireless

	Dear mailling list, 

	I am using a unex DNMA-863 with AR9106 chipset and ath9k linux
driver.

	I would like to know if in this configuration I could support
these features:
		- MRC (Maximal ratio combining)
		- A-MSDU
		- A-MPDU
		- MLD (Maximum Likehood Decoding)
		- SST
		- U-APSD (Unscheduled Automatic Power Save Delivery)

If some features are supported, is it possible to enable/disable it? if
yes how I can do that ?

	Thanks for your help.
	

Cedric Voncken 


^ permalink raw reply

* Re: fyi: scheduling while atomic dmesg output 3.12-rc1
From: Hauke Mehrtens @ 2013-09-18 13:57 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: Joe Perches, brcm80211-dev-list, linux-wireless,
	Rafał Miłecki
In-Reply-To: <52397023.2080000@broadcom.com>

On 09/18/2013 11:19 AM, Arend van Spriel wrote:
> On 09/17/2013 07:45 PM, Joe Perches wrote:
>> <3>[   11.206312] BUG: scheduling while atomic:
>> NetworkManager/866/0x00000200
> 
> Thanks, Joe
> 
> I got a report on this few days ago. It was introduced by bcma API
> change and I already sent email to the committer of that change, ie.
> Hauke Mehrtens. Hope it will be settled soon how to fix this.
> 
> Gr. AvS

Hi,

I see four solutions for the problem:

1. convert the usleep_range(1000, 2000) into udelay(1000) in
drivers/bcma/driver_pci.c

2. remove the call of bcma_core_pci_power_save() from bcma_core_pci_up()
so that it does not get called by brcmsmac.

3. remove the call of bcma_core_pci_power_save() from bcma_core_pci_up()
and move the call to somewhere out of the big spin lock.

4. convert the big brmcsmac spin lock into a mutex lock and use an
additional spin lock for the parts where it is actually needed.

For 3.12 I am for solution 1 or 2 and for the long term 3.13? I am for
solution 4, but that needs bigger changes.

Hauke

^ permalink raw reply

* [PATCH 3.12] ath9k: add txq locking for ath_tx_aggr_start
From: Felix Fietkau @ 2013-09-18 13:23 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville

Prevents race conditions when un-aggregated frames are pending in the
driver.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/xmit.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 9b3736e..5ac713d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1390,11 +1390,15 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 		      u16 tid, u16 *ssn)
 {
 	struct ath_atx_tid *txtid;
+	struct ath_txq *txq;
 	struct ath_node *an;
 	u8 density;
 
 	an = (struct ath_node *)sta->drv_priv;
 	txtid = ATH_AN_2_TID(an, tid);
+	txq = txtid->ac->txq;
+
+	ath_txq_lock(sc, txq);
 
 	/* update ampdu factor/density, they may have changed. This may happen
 	 * in HT IBSS when a beacon with HT-info is received after the station
@@ -1418,6 +1422,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 	memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
 	txtid->baw_head = txtid->baw_tail = 0;
 
+	ath_txq_unlock_complete(sc, txq);
+
 	return 0;
 }
 
-- 
1.8.0.2


^ permalink raw reply related

* [PATCH] ath10k: fix num_sends_allowed replenishing
From: Michal Kazior @ 2013-09-18 13:22 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

Recent ce_sendlist removal patch has broken
num_sends_allowed incrementing. num_sends_allowed
exceeded initial values and could overflow.

This code was supposed to replenish
num_sends_allowed for partial sendlist items (i.e.
before final sendlist item from a sendlist was
completed and could be processed by completion
handlers).

Fortunately it seems it cause any major breakage,
yet.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c |    4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index f1faf46..dff23d9 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -626,10 +626,6 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
 	while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
 					     &ce_data, &nbytes,
 					     &transfer_id) == 0) {
-		spin_lock_bh(&pipe_info->pipe_lock);
-		pipe_info->num_sends_allowed++;
-		spin_unlock_bh(&pipe_info->pipe_lock);
-
 		compl = get_free_compl(pipe_info);
 		if (!compl)
 			break;
-- 
1.7.9.5


^ permalink raw reply related

* Re: RT3573 wpa_supplicant: "nl80211: Delete station $my_ap" after "SME: Send 20/40 BSS Coexistence to $my_ap"
From: Xose Vazquez Perez @ 2013-09-18 13:18 UTC (permalink / raw)
  To: peter, linux-wireless, users@rt2x00.serialmonkey.com

Peter Stuge wrote:

> I'm testing the WNDA4100 with torvalds/linux.git and as of a day or
> two ago and wpa_supplicant-2.0.
> 
> I haven't measured throughput. Latency is really bad for interactive
> connections, but at least the packets are flowing on all bands. Yay!
> 
> Ping to the access point is around 3 ms with the odd 20+ ms when the
> kernel goes off to do something else.

Support for RT3573 was added recently, you should use wireless-next:
http://git.kernel.org/cgit/linux/kernel/git/linville/wireless-next.git

You can also try latest fw(v0.33):
http://rt2x00.serialmonkey.com/pipermail/users_rt2x00.serialmonkey.com/attachments/20130111/f8ebe4d3/attachment.bin

md5sum:
======
ac4f6d8b679945208a978e397c016aa7 rt2870.bin (8192 bytes)

# mv /lib/firmware/rt2870.bin /lib/firmware/rt2870.bin.orig
# mv attachment.bin /lib/firmware/rt2870.bin

^ permalink raw reply

* [RFC] ath10k: replenish HTT RX buffers in a tasklet
From: Michal Kazior @ 2013-09-18 13:08 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

This fixes system starvation when under heavy RX
traffic. This problem could be observed on AP135
and led to watchdog resetting the platform.

Patch starves FW RX ring buffer by progressively
replenishing buffers to auto-balance the RX
handled to the host system.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt.h    |    8 +++++++
 drivers/net/wireless/ath/ath10k/htt_rx.c |   36 +++++++++++++++++++++++++++---
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index e090902..8dcf808 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -19,6 +19,7 @@
 #define _HTT_H_
 
 #include <linux/bug.h>
+#include <linux/interrupt.h>
 
 #include "htc.h"
 #include "rx_desc.h"
@@ -1268,6 +1269,7 @@ struct ath10k_htt {
 	/* set if host-fw communication goes haywire
 	 * used to avoid further failures */
 	bool rx_confused;
+	struct tasklet_struct rx_replenish_task;
 };
 
 #define RX_HTT_HDR_STATUS_LEN 64
@@ -1308,6 +1310,12 @@ struct htt_rx_desc {
 #define HTT_RX_BUF_SIZE 1920
 #define HTT_RX_MSDU_SIZE (HTT_RX_BUF_SIZE - (int)sizeof(struct htt_rx_desc))
 
+/* Refill a bunch of RX buffers for each refill round so that FW/HW can handle
+ * aggregated traffic more nicely. Picked empirically.
+ * FIXME: Can this value be calculated sanely? */
+#define ATH10K_HTT_MAX_NUM_REFILL 16
+
+
 /*
  * DMA_MAP expects the buffer to be an integral number of cache lines.
  * Rather than checking the actual cache line size, this code makes a
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index a39fbf4..66e9ecd 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -178,10 +178,27 @@ static int ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
 
 static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
 {
-	int ret, num_to_fill;
+	int ret, num_deficit, num_to_fill;
 
+	/* Refilling the whole RX ring buffer proves to be a bad idea. The
+	 * reason is RX may take very long periods of time and starve other
+	 * tasks on a system.
+	 *
+	 * By limiting the number of refills the replenishing occurs
+	 * progressively. This in turns makes use of the fact tasklets are
+	 * processed in FIFO order. This means actual RX processing can starve
+	 * out refilling if there's not enough free processing power. If
+	 * there's not enough buffers on RX ring FW will not report RX until it
+	 * is refilled with enough buffers. This automatically balances load
+	 * wrt to CPU power.
+	 *
+	 * This probably comes at a cost of lower maximum theoretical
+	 * throughput but stabilizes the real throughput and prevents
+	 * starvation (which can lead to poor performance itself) */
 	spin_lock_bh(&htt->rx_ring.lock);
-	num_to_fill = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
+	num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
+	num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit);
+	num_deficit -= num_to_fill;
 	ret = ath10k_htt_rx_ring_fill_n(htt, num_to_fill);
 	if (ret == -ENOMEM) {
 		/*
@@ -192,8 +209,11 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
 		 */
 		mod_timer(&htt->rx_ring.refill_retry_timer, jiffies +
 			  msecs_to_jiffies(HTT_RX_RING_REFILL_RETRY_MS));
+	} else if (num_deficit > 0) {
+		tasklet_schedule(&htt->rx_replenish_task);
 	}
 	spin_unlock_bh(&htt->rx_ring.lock);
+
 }
 
 static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
@@ -212,6 +232,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt)
 {
 	int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
 
+	tasklet_kill(&htt->rx_replenish_task);
 	del_timer_sync(&htt->rx_ring.refill_retry_timer);
 
 	while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
@@ -442,6 +463,12 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 	return msdu_chaining;
 }
 
+static void ath10k_htt_rx_replenish_task(unsigned long ptr)
+{
+	struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
+	ath10k_htt_rx_msdu_buff_replenish(htt);
+}
+
 int ath10k_htt_rx_attach(struct ath10k_htt *htt)
 {
 	dma_addr_t paddr;
@@ -502,6 +529,9 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
 	if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))
 		goto err_fill_ring;
 
+	tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
+		     (unsigned long)htt);
+
 	ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
 		   htt->rx_ring.size, htt->rx_ring.fill_level);
 	return 0;
@@ -968,7 +998,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 		}
 	}
 
-	ath10k_htt_rx_msdu_buff_replenish(htt);
+	tasklet_schedule(&htt->rx_replenish_task);
 }
 
 static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH] ath10k: implement host memory chunks feature
From: Michal Kazior @ 2013-09-18 13:07 UTC (permalink / raw)
  To: Bartosz Markowski; +Cc: ath10k, linux-wireless
In-Reply-To: <CACKGw+HgRbZU4DV5ZFHZA-X-78nEUd87hDeabMr1r1fRc-yOvw@mail.gmail.com>

On 18 September 2013 14:36, Bartosz Markowski
<bartosz.markowski@tieto.com> wrote:
> On 18 September 2013 12:51, Michal Kazior <michal.kazior@tieto.com> wrote:
>> On 18 September 2013 11:47, Bartosz Markowski
>>> +       ar->hif.ops->chunk_free(ar, idx);
>>> +}
>>> +
>>>  #endif /* _HIF_H_ */
>>> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
>>> index f1faf46..547d67d 100644
>>> --- a/drivers/net/wireless/ath/ath10k/pci.c
>>> +++ b/drivers/net/wireless/ath/ath10k/pci.c
>>> @@ -1966,6 +1966,49 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
>>>  }
>>>  #endif
>>>
>>> +static int ath10k_pci_hif_chunk_alloc(struct ath10k *ar,
>>> +                                     u32 req_id,
>>> +                                     u32 idx,
>>> +                                     u32 num_units,
>>> +                                     u32 unit_len)
>>> +{
>>> +       dma_addr_t paddr;
>>> +       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
>>> +
>>> +       if (!num_units  || !unit_len)
>>> +               return 0;
>>> +
>>
>> I'm not seeing any checks against buffer overflow of mem_chunks[req_id].
>
> if (idx == ATH10K_MAX_MEM_CHUNKS) in ath10k_wmi_alloc_host_mem ?

Oh, but the check is _after_ call to chunk_alloc(). What if
ath10k_wmi_alloc_host_mem() were to be called while idx == MAX?


Michał.

^ permalink raw reply

* [PATCH 5/5] ath10k: use msdu headroom to store txfrag
From: Michal Kazior @ 2013-09-18 12:43 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1379508202-9660-1-git-send-email-michal.kazior@tieto.com>

Instead of allocating sk_buff for a mere 16-byte
tx fragment list buffer use headroom of the
original msdu sk_buff.

This decreases CPU cache pressure and improves
performance.

Measured improvement on AP135 is 560mbps ->
590mbps of UDP TX briding traffic.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h   |    4 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c |   82 +++++++++++++++---------------
 drivers/net/wireless/ath/ath10k/mac.c    |    4 ++
 drivers/net/wireless/ath/ath10k/txrx.c   |   16 +++---
 4 files changed, 53 insertions(+), 53 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4563f80..292ad45 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -54,7 +54,9 @@ struct ath10k_skb_cb {
 		u8 vdev_id;
 		u8 tid;
 		bool is_offchan;
-		struct sk_buff *txfrag;
+
+		u8 frag_len;
+		u8 pad_len;
 	} __packed htt;
 } __packed;
 
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 5e738d8..3b93c6a 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -307,7 +307,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	struct device *dev = htt->ar->dev;
 	struct sk_buff *txdesc = NULL;
 	struct htt_cmd *cmd;
-	u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
+	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
+	u8 vdev_id = skb_cb->htt.vdev_id;
 	int len = 0;
 	int msdu_id = -1;
 	int res;
@@ -350,6 +351,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	memcpy(cmd->mgmt_tx.hdr, msdu->data,
 	       min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
 
+	skb_cb->htt.frag_len = 0;
+	skb_cb->htt.pad_len = 0;
+
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
 		goto err_unmap_msdu;
@@ -377,13 +381,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	struct htt_cmd *cmd;
 	struct htt_data_tx_desc_frag *tx_frags;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
 	struct sk_buff *txdesc = NULL;
-	struct sk_buff *txfrag = NULL;
 	bool use_frags;
 	u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
 	u8 tid;
-	int prefetch_len, desc_len, frag_len;
-	dma_addr_t frags_paddr;
+	int prefetch_len, desc_len;
 	int msdu_id = -1;
 	int res;
 	u8 flags0;
@@ -407,7 +410,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	prefetch_len = roundup(prefetch_len, 4);
 
 	desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len;
-	frag_len = sizeof(*tx_frags) * 2;
 
 	txdesc = ath10k_htc_alloc_skb(desc_len);
 	if (!txdesc) {
@@ -421,41 +423,44 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	use_frags = htt->target_version_major < 3 ||
 		    !ieee80211_is_mgmt(hdr->frame_control);
 
-	if (use_frags) {
-		txfrag = dev_alloc_skb(frag_len);
-		if (!txfrag) {
-			res = -ENOMEM;
-			goto err_free_txdesc;
-		}
-	}
-
 	if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
 		ath10k_warn("htt alignment check failed. dropping packet.\n");
 		res = -EIO;
-		goto err_free_txfrag;
+		goto err_free_txdesc;
+	}
+
+	if (use_frags) {
+		skb_cb->htt.frag_len = sizeof(*tx_frags) * 2;
+		skb_cb->htt.pad_len = (unsigned long)msdu->data -
+				      round_down((unsigned long)msdu->data, 4);
+
+		skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
+	} else {
+		skb_cb->htt.frag_len = 0;
+		skb_cb->htt.pad_len = 0;
 	}
 
 	res = ath10k_skb_map(dev, msdu);
 	if (res)
-		goto err_free_txfrag;
+		goto err_pull_txfrag;
 
 	if (use_frags) {
+		dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len,
+					DMA_TO_DEVICE);
+
 		/* tx fragment list must be terminated with zero-entry */
-		skb_put(txfrag, frag_len);
-		tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
-		tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
-		tx_frags[0].len   = __cpu_to_le32(msdu->len);
+		tx_frags = (struct htt_data_tx_desc_frag *)msdu->data;
+		tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr +
+						  skb_cb->htt.frag_len +
+						  skb_cb->htt.pad_len);
+		tx_frags[0].len   = __cpu_to_le32(msdu->len -
+						  skb_cb->htt.frag_len -
+						  skb_cb->htt.pad_len);
 		tx_frags[1].paddr = __cpu_to_le32(0);
 		tx_frags[1].len   = __cpu_to_le32(0);
 
-		res = ath10k_skb_map(dev, txfrag);
-		if (res)
-			goto err_unmap_msdu;
-
-		ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx\n",
-			   (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr);
-		ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
-				txfrag->data, frag_len);
+		dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len,
+					   DMA_TO_DEVICE);
 	}
 
 	ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
@@ -488,35 +493,28 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
 	flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
 
-	if (use_frags)
-		frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
-	else
-		frags_paddr = ATH10K_SKB_CB(msdu)->paddr;
-
 	cmd->hdr.msg_type        = HTT_H2T_MSG_TYPE_TX_FRM;
 	cmd->data_tx.flags0      = flags0;
 	cmd->data_tx.flags1      = __cpu_to_le16(flags1);
-	cmd->data_tx.len         = __cpu_to_le16(msdu->len);
+	cmd->data_tx.len         = __cpu_to_le16(msdu->len -
+						 skb_cb->htt.frag_len -
+						 skb_cb->htt.pad_len);
 	cmd->data_tx.id          = __cpu_to_le16(msdu_id);
-	cmd->data_tx.frags_paddr = __cpu_to_le32(frags_paddr);
+	cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr);
 	cmd->data_tx.peerid      = __cpu_to_le32(HTT_INVALID_PEERID);
 
-	memcpy(cmd->data_tx.prefetch, msdu->data, prefetch_len);
+	memcpy(cmd->data_tx.prefetch, hdr, prefetch_len);
 
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
-		goto err_restore;
+		goto err_unmap_msdu;
 
 	return 0;
 
-err_restore:
-	if (use_frags)
-		ath10k_skb_unmap(dev, txfrag);
 err_unmap_msdu:
 	ath10k_skb_unmap(dev, msdu);
-err_free_txfrag:
-	if (use_frags)
-		dev_kfree_skb_any(txfrag);
+err_pull_txfrag:
+	skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
 err_free_txdesc:
 	dev_kfree_skb_any(txdesc);
 err_free_msdu_id:
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 9112e6d6f..99a9bad 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3342,6 +3342,10 @@ int ath10k_mac_register(struct ath10k *ar)
 			IEEE80211_HW_WANT_MONITOR_VIF |
 			IEEE80211_HW_AP_LINK_PS;
 
+	/* MSDU can have HTT TX fragment pushed in front. The additional 4
+	 * bytes is used for padding/alignment if necessary. */
+	ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
+
 	if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
 		ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
 
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 15395af..57931d0 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -49,7 +49,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 {
 	struct device *dev = htt->ar->dev;
 	struct ieee80211_tx_info *info;
-	struct sk_buff *msdu, *txfrag;
+	struct ath10k_skb_cb *skb_cb;
+	struct sk_buff *msdu;
 	int ret;
 
 	ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
@@ -62,20 +63,15 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 	}
 
 	msdu = htt->pending_tx[tx_done->msdu_id];
-	txfrag = ATH10K_SKB_CB(msdu)->htt.txfrag;
-
-	if (txfrag) {
-		ret = ath10k_skb_unmap(dev, txfrag);
-		if (ret)
-			ath10k_warn("txfrag unmap failed (%d)\n", ret);
-
-		dev_kfree_skb_any(txfrag);
-	}
+	skb_cb = ATH10K_SKB_CB(msdu);
 
 	ret = ath10k_skb_unmap(dev, msdu);
 	if (ret)
 		ath10k_warn("data skb unmap failed (%d)\n", ret);
 
+	if (skb_cb->htt.frag_len)
+		skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
+
 	ath10k_report_offchan_tx(htt->ar, msdu);
 
 	info = IEEE80211_SKB_CB(msdu);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 3/5] ath10k: decouple HTT TX completions
From: Michal Kazior @ 2013-09-18 12:43 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1379508202-9660-1-git-send-email-michal.kazior@tieto.com>

Until now the all MSDU transfer related structures
were freed when all resources were unreferenced.

Now HTC transfer is freed independently and HTT
transfer is so too.

This yields a way more simpler ath10k_skb_cb and
should possibly enable parallel pipe processing
(which is now serialized in
ath10k_pci_process_ce routine).

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h   |    8 ----
 drivers/net/wireless/ath/ath10k/htt_rx.c |    4 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c |   64 ++++--------------------------
 drivers/net/wireless/ath/ath10k/mac.c    |    2 -
 drivers/net/wireless/ath/ath10k/txrx.c   |   52 ++++++++----------------
 drivers/net/wireless/ath/ath10k/txrx.h   |    5 +--
 6 files changed, 27 insertions(+), 108 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index fcf94ee..4563f80 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -52,18 +52,10 @@ struct ath10k_skb_cb {
 
 	struct {
 		u8 vdev_id;
-		u16 msdu_id;
 		u8 tid;
 		bool is_offchan;
-		bool is_conf;
-		bool discard;
-		bool no_ack;
-		u8 refcount;
 		struct sk_buff *txfrag;
-		struct sk_buff *msdu;
 	} __packed htt;
-
-	/* 4 bytes left on 64bit arch */
 } __packed;
 
 static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index a39fbf4..62ea9c8 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1140,7 +1140,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
 			break;
 		}
 
-		ath10k_txrx_tx_completed(htt, &tx_done);
+		ath10k_txrx_tx_unref(htt, &tx_done);
 		break;
 	}
 	case HTT_T2H_MSG_TYPE_TX_COMPL_IND: {
@@ -1174,7 +1174,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
 		for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
 			msdu_id = resp->data_tx_completion.msdus[i];
 			tx_done.msdu_id = __le16_to_cpu(msdu_id);
-			ath10k_txrx_tx_completed(htt, &tx_done);
+			ath10k_txrx_tx_unref(htt, &tx_done);
 		}
 		break;
 	}
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index c4bbf74..06946d2 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -117,7 +117,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
 
 static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
 {
-	struct sk_buff *txdesc;
+	struct htt_tx_done tx_done = {0};
 	int msdu_id;
 
 	/* No locks needed. Called after communication with the device has
@@ -127,18 +127,13 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
 		if (!test_bit(msdu_id, htt->used_msdu_ids))
 			continue;
 
-		txdesc = htt->pending_tx[msdu_id];
-		if (!txdesc)
-			continue;
-
 		ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
 			   msdu_id);
 
-		if (ATH10K_SKB_CB(txdesc)->htt.refcount > 0)
-			ATH10K_SKB_CB(txdesc)->htt.refcount = 1;
+		tx_done.discard = 1;
+		tx_done.msdu_id = msdu_id;
 
-		ATH10K_SKB_CB(txdesc)->htt.discard = true;
-		ath10k_txrx_tx_unref(htt, txdesc);
+		ath10k_txrx_tx_unref(htt, &tx_done);
 	}
 }
 
@@ -152,26 +147,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt)
 
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
-	struct ath10k_htt *htt = &ar->htt;
-
-	if (skb_cb->htt.is_conf) {
-		dev_kfree_skb_any(skb);
-		return;
-	}
-
-	if (skb_cb->is_aborted) {
-		skb_cb->htt.discard = true;
-
-		/* if the skbuff is aborted we need to make sure we'll free up
-		 * the tx resources, we can't simply run tx_unref() 2 times
-		 * because if htt tx completion came in earlier we'd access
-		 * unallocated memory */
-		if (skb_cb->htt.refcount > 1)
-			skb_cb->htt.refcount = 1;
-	}
-
-	ath10k_txrx_tx_unref(htt, skb);
+	dev_kfree_skb_any(skb);
 }
 
 int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
@@ -192,8 +168,6 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
 	cmd = (struct htt_cmd *)skb->data;
 	cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_VERSION_REQ;
 
-	ATH10K_SKB_CB(skb)->htt.is_conf = true;
-
 	ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
 	if (ret) {
 		dev_kfree_skb_any(skb);
@@ -233,8 +207,6 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
 	req->cookie_lsb = cpu_to_le32(cookie & 0xffffffff);
 	req->cookie_msb = cpu_to_le32((cookie & 0xffffffff00000000ULL) >> 32);
 
-	ATH10K_SKB_CB(skb)->htt.is_conf = true;
-
 	ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
 	if (ret) {
 		ath10k_warn("failed to send htt type stats request: %d", ret);
@@ -321,8 +293,6 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 
 #undef desc_offset
 
-	ATH10K_SKB_CB(skb)->htt.is_conf = true;
-
 	ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
 	if (ret) {
 		dev_kfree_skb_any(skb);
@@ -335,7 +305,6 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 {
 	struct device *dev = htt->ar->dev;
-	struct ath10k_skb_cb *skb_cb;
 	struct sk_buff *txdesc = NULL;
 	struct htt_cmd *cmd;
 	u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
@@ -364,7 +333,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 		res = msdu_id;
 		goto err;
 	}
-	htt->pending_tx[msdu_id] = txdesc;
+	htt->pending_tx[msdu_id] = msdu;
 	spin_unlock_bh(&htt->tx_lock);
 
 	res = ath10k_skb_map(dev, msdu);
@@ -381,15 +350,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	memcpy(cmd->mgmt_tx.hdr, msdu->data,
 	       min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
 
-	/* refcount is decremented by HTC and HTT completions until it reaches
-	 * zero and is freed */
-	skb_cb = ATH10K_SKB_CB(txdesc);
-	skb_cb->htt.is_conf = false;
-	skb_cb->htt.msdu_id = msdu_id;
-	skb_cb->htt.refcount = 2;
-	skb_cb->htt.msdu = msdu;
-	skb_cb->htt.txfrag = NULL;
-
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
 		goto err;
@@ -417,7 +377,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	struct htt_cmd *cmd;
 	struct htt_data_tx_desc_frag *tx_frags;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
-	struct ath10k_skb_cb *skb_cb;
 	struct sk_buff *txdesc = NULL;
 	struct sk_buff *txfrag = NULL;
 	u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
@@ -470,7 +429,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 		res = msdu_id;
 		goto err;
 	}
-	htt->pending_tx[msdu_id] = txdesc;
+	htt->pending_tx[msdu_id] = msdu;
 	spin_unlock_bh(&htt->tx_lock);
 
 	res = ath10k_skb_map(dev, msdu);
@@ -553,15 +512,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 	memcpy(cmd->data_tx.prefetch, msdu->data, prefetch_len);
 
-	/* refcount is decremented by HTC and HTT completions until it reaches
-	 * zero and is freed */
-	skb_cb = ATH10K_SKB_CB(txdesc);
-	skb_cb->htt.is_conf = false;
-	skb_cb->htt.msdu_id = msdu_id;
-	skb_cb->htt.refcount = 2;
-	skb_cb->htt.txfrag = txfrag;
-	skb_cb->htt.msdu = msdu;
-
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
 		goto err;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0d367e4..9112e6d6f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1757,8 +1757,6 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 		ath10k_tx_h_seq_no(skb);
 	}
 
-	ATH10K_SKB_CB(skb)->is_mapped = false;
-	ATH10K_SKB_CB(skb)->is_aborted = false;
 	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id;
 	ATH10K_SKB_CB(skb)->htt.tid = tid;
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index f6fed31..15395af 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -44,21 +44,25 @@ out:
 	spin_unlock_bh(&ar->data_lock);
 }
 
-void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
+void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+			  const struct htt_tx_done *tx_done)
 {
 	struct device *dev = htt->ar->dev;
 	struct ieee80211_tx_info *info;
-	struct sk_buff *txfrag = ATH10K_SKB_CB(txdesc)->htt.txfrag;
-	struct sk_buff *msdu = ATH10K_SKB_CB(txdesc)->htt.msdu;
+	struct sk_buff *msdu, *txfrag;
 	int ret;
 
-	if (ATH10K_SKB_CB(txdesc)->htt.refcount == 0)
-		return;
-
-	ATH10K_SKB_CB(txdesc)->htt.refcount--;
+	ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
+		   tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
 
-	if (ATH10K_SKB_CB(txdesc)->htt.refcount > 0)
+	if (tx_done->msdu_id >= htt->max_num_pending_tx) {
+		ath10k_warn("warning: msdu_id %d too big, ignoring\n",
+			    tx_done->msdu_id);
 		return;
+	}
+
+	msdu = htt->pending_tx[tx_done->msdu_id];
+	txfrag = ATH10K_SKB_CB(msdu)->htt.txfrag;
 
 	if (txfrag) {
 		ret = ath10k_skb_unmap(dev, txfrag);
@@ -76,7 +80,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
 
 	info = IEEE80211_SKB_CB(msdu);
 
-	if (ATH10K_SKB_CB(txdesc)->htt.discard) {
+	if (tx_done->discard) {
 		ieee80211_free_txskb(htt->ar->hw, msdu);
 		goto exit;
 	}
@@ -84,7 +88,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		info->flags |= IEEE80211_TX_STAT_ACK;
 
-	if (ATH10K_SKB_CB(txdesc)->htt.no_ack)
+	if (tx_done->no_ack)
 		info->flags &= ~IEEE80211_TX_STAT_ACK;
 
 	ieee80211_tx_status(htt->ar->hw, msdu);
@@ -92,36 +96,12 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
 
 exit:
 	spin_lock_bh(&htt->tx_lock);
-	htt->pending_tx[ATH10K_SKB_CB(txdesc)->htt.msdu_id] = NULL;
-	ath10k_htt_tx_free_msdu_id(htt, ATH10K_SKB_CB(txdesc)->htt.msdu_id);
+	htt->pending_tx[tx_done->msdu_id] = NULL;
+	ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
 	__ath10k_htt_tx_dec_pending(htt);
 	if (htt->num_pending_tx == 0)
 		wake_up(&htt->empty_tx_wq);
 	spin_unlock_bh(&htt->tx_lock);
-
-	dev_kfree_skb_any(txdesc);
-}
-
-void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
-			      const struct htt_tx_done *tx_done)
-{
-	struct sk_buff *txdesc;
-
-	ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
-		   tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
-
-	if (tx_done->msdu_id >= htt->max_num_pending_tx) {
-		ath10k_warn("warning: msdu_id %d too big, ignoring\n",
-			    tx_done->msdu_id);
-		return;
-	}
-
-	txdesc = htt->pending_tx[tx_done->msdu_id];
-
-	ATH10K_SKB_CB(txdesc)->htt.discard = tx_done->discard;
-	ATH10K_SKB_CB(txdesc)->htt.no_ack = tx_done->no_ack;
-
-	ath10k_txrx_tx_unref(htt, txdesc);
 }
 
 static const u8 rx_legacy_rate_idx[] = {
diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h
index e78632a..356dc9c 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.h
+++ b/drivers/net/wireless/ath/ath10k/txrx.h
@@ -19,9 +19,8 @@
 
 #include "htt.h"
 
-void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc);
-void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
-			      const struct htt_tx_done *tx_done);
+void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+			  const struct htt_tx_done *tx_done);
 void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info);
 
 struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 4/5] ath10k: cleanup HTT TX functions
From: Michal Kazior @ 2013-09-18 12:43 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1379508202-9660-1-git-send-email-michal.kazior@tieto.com>

Use a saner goto scheme for failure handling. Also
group operations more sensibly.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_tx.c |  141 ++++++++++++++----------------
 1 file changed, 68 insertions(+), 73 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 06946d2..5e738d8 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -315,30 +315,30 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 	res = ath10k_htt_tx_inc_pending(htt);
 	if (res)
-		return res;
+		goto err;
 
 	len += sizeof(cmd->hdr);
 	len += sizeof(cmd->mgmt_tx);
 
-	txdesc = ath10k_htc_alloc_skb(len);
-	if (!txdesc) {
-		res = -ENOMEM;
-		goto err;
-	}
-
 	spin_lock_bh(&htt->tx_lock);
-	msdu_id = ath10k_htt_tx_alloc_msdu_id(htt);
-	if (msdu_id < 0) {
+	res = ath10k_htt_tx_alloc_msdu_id(htt);
+	if (res < 0) {
 		spin_unlock_bh(&htt->tx_lock);
-		res = msdu_id;
-		goto err;
+		goto err_tx_dec;
 	}
+	msdu_id = res;
 	htt->pending_tx[msdu_id] = msdu;
 	spin_unlock_bh(&htt->tx_lock);
 
+	txdesc = ath10k_htc_alloc_skb(len);
+	if (!txdesc) {
+		res = -ENOMEM;
+		goto err_free_msdu_id;
+	}
+
 	res = ath10k_skb_map(dev, msdu);
 	if (res)
-		goto err;
+		goto err_free_txdesc;
 
 	skb_put(txdesc, len);
 	cmd = (struct htt_cmd *)txdesc->data;
@@ -352,22 +352,22 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
-		goto err;
+		goto err_unmap_msdu;
 
 	return 0;
 
-err:
+err_unmap_msdu:
 	ath10k_skb_unmap(dev, msdu);
-
-	if (txdesc)
-		dev_kfree_skb_any(txdesc);
-	if (msdu_id >= 0) {
-		spin_lock_bh(&htt->tx_lock);
-		htt->pending_tx[msdu_id] = NULL;
-		ath10k_htt_tx_free_msdu_id(htt, msdu_id);
-		spin_unlock_bh(&htt->tx_lock);
-	}
+err_free_txdesc:
+	dev_kfree_skb_any(txdesc);
+err_free_msdu_id:
+	spin_lock_bh(&htt->tx_lock);
+	htt->pending_tx[msdu_id] = NULL;
+	ath10k_htt_tx_free_msdu_id(htt, msdu_id);
+	spin_unlock_bh(&htt->tx_lock);
+err_tx_dec:
 	ath10k_htt_tx_dec_pending(htt);
+err:
 	return res;
 }
 
@@ -379,6 +379,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
 	struct sk_buff *txdesc = NULL;
 	struct sk_buff *txfrag = NULL;
+	bool use_frags;
 	u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
 	u8 tid;
 	int prefetch_len, desc_len, frag_len;
@@ -390,7 +391,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 	res = ath10k_htt_tx_inc_pending(htt);
 	if (res)
-		return res;
+		goto err;
+
+	spin_lock_bh(&htt->tx_lock);
+	res = ath10k_htt_tx_alloc_msdu_id(htt);
+	if (res < 0) {
+		spin_unlock_bh(&htt->tx_lock);
+		goto err_tx_dec;
+	}
+	msdu_id = res;
+	htt->pending_tx[msdu_id] = msdu;
+	spin_unlock_bh(&htt->tx_lock);
 
 	prefetch_len = min(htt->prefetch_len, msdu->len);
 	prefetch_len = roundup(prefetch_len, 4);
@@ -401,46 +412,34 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	txdesc = ath10k_htc_alloc_skb(desc_len);
 	if (!txdesc) {
 		res = -ENOMEM;
-		goto err;
+		goto err_free_msdu_id;
 	}
 
 	/* Since HTT 3.0 there is no separate mgmt tx command. However in case
 	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
 	 * fragment list host driver specifies directly frame pointer. */
-	if (htt->target_version_major < 3 ||
-	    !ieee80211_is_mgmt(hdr->frame_control)) {
+	use_frags = htt->target_version_major < 3 ||
+		    !ieee80211_is_mgmt(hdr->frame_control);
+
+	if (use_frags) {
 		txfrag = dev_alloc_skb(frag_len);
 		if (!txfrag) {
 			res = -ENOMEM;
-			goto err;
+			goto err_free_txdesc;
 		}
 	}
 
 	if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
 		ath10k_warn("htt alignment check failed. dropping packet.\n");
 		res = -EIO;
-		goto err;
+		goto err_free_txfrag;
 	}
 
-	spin_lock_bh(&htt->tx_lock);
-	msdu_id = ath10k_htt_tx_alloc_msdu_id(htt);
-	if (msdu_id < 0) {
-		spin_unlock_bh(&htt->tx_lock);
-		res = msdu_id;
-		goto err;
-	}
-	htt->pending_tx[msdu_id] = msdu;
-	spin_unlock_bh(&htt->tx_lock);
-
 	res = ath10k_skb_map(dev, msdu);
 	if (res)
-		goto err;
+		goto err_free_txfrag;
 
-	/* Since HTT 3.0 there is no separate mgmt tx command. However in case
-	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
-	 * fragment list host driver specifies directly frame pointer. */
-	if (htt->target_version_major < 3 ||
-	    !ieee80211_is_mgmt(hdr->frame_control)) {
+	if (use_frags) {
 		/* tx fragment list must be terminated with zero-entry */
 		skb_put(txfrag, frag_len);
 		tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
@@ -451,7 +450,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 		res = ath10k_skb_map(dev, txfrag);
 		if (res)
-			goto err;
+			goto err_unmap_msdu;
 
 		ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx\n",
 			   (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr);
@@ -476,15 +475,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 		flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
 	flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
 
-	/* Since HTT 3.0 there is no separate mgmt tx command. However in case
-	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
-	 * fragment list host driver specifies directly frame pointer. */
-	if (htt->target_version_major >= 3 &&
-	    ieee80211_is_mgmt(hdr->frame_control))
-		flags0 |= SM(ATH10K_HW_TXRX_MGMT,
+	if (use_frags)
+		flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
 			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
 	else
-		flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
+		flags0 |= SM(ATH10K_HW_TXRX_MGMT,
 			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
 
 	flags1  = 0;
@@ -493,14 +488,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
 	flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
 
-	/* Since HTT 3.0 there is no separate mgmt tx command. However in case
-	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
-	 * fragment list host driver specifies directly frame pointer. */
-	if (htt->target_version_major >= 3 &&
-	    ieee80211_is_mgmt(hdr->frame_control))
-		frags_paddr = ATH10K_SKB_CB(msdu)->paddr;
-	else
+	if (use_frags)
 		frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
+	else
+		frags_paddr = ATH10K_SKB_CB(msdu)->paddr;
 
 	cmd->hdr.msg_type        = HTT_H2T_MSG_TYPE_TX_FRM;
 	cmd->data_tx.flags0      = flags0;
@@ -514,23 +505,27 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
-		goto err;
+		goto err_restore;
 
 	return 0;
-err:
-	if (txfrag)
+
+err_restore:
+	if (use_frags)
 		ath10k_skb_unmap(dev, txfrag);
-	if (txdesc)
-		dev_kfree_skb_any(txdesc);
-	if (txfrag)
+err_unmap_msdu:
+	ath10k_skb_unmap(dev, msdu);
+err_free_txfrag:
+	if (use_frags)
 		dev_kfree_skb_any(txfrag);
-	if (msdu_id >= 0) {
-		spin_lock_bh(&htt->tx_lock);
-		htt->pending_tx[msdu_id] = NULL;
-		ath10k_htt_tx_free_msdu_id(htt, msdu_id);
-		spin_unlock_bh(&htt->tx_lock);
-	}
+err_free_txdesc:
+	dev_kfree_skb_any(txdesc);
+err_free_msdu_id:
+	spin_lock_bh(&htt->tx_lock);
+	htt->pending_tx[msdu_id] = NULL;
+	ath10k_htt_tx_free_msdu_id(htt, msdu_id);
+	spin_unlock_bh(&htt->tx_lock);
+err_tx_dec:
 	ath10k_htt_tx_dec_pending(htt);
-	ath10k_skb_unmap(dev, msdu);
+err:
 	return res;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 1/5] ath10k: use num_pending_tx instead of msdu id bitmap
From: Michal Kazior @ 2013-09-18 12:43 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1379508202-9660-1-git-send-email-michal.kazior@tieto.com>

It's more efficient to simply check num_pending_tx
value instead of traversing whole bitmap of
msdu ids.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c  |    3 +--
 drivers/net/wireless/ath/ath10k/txrx.c |    2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 11aa13e..5a56833 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2853,8 +2853,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 			bool empty;
 
 			spin_lock_bh(&ar->htt.tx_lock);
-			empty = bitmap_empty(ar->htt.used_msdu_ids,
-					     ar->htt.max_num_pending_tx);
+			empty = (ar->htt.num_pending_tx == 0);
 			spin_unlock_bh(&ar->htt.tx_lock);
 
 			skip = (ar->state == ATH10K_STATE_WEDGED);
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 68b6fae..37b8196 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -96,7 +96,7 @@ exit:
 	htt->pending_tx[ATH10K_SKB_CB(txdesc)->htt.msdu_id] = NULL;
 	ath10k_htt_tx_free_msdu_id(htt, ATH10K_SKB_CB(txdesc)->htt.msdu_id);
 	__ath10k_htt_tx_dec_pending(htt);
-	if (bitmap_empty(htt->used_msdu_ids, htt->max_num_pending_tx))
+	if (htt->num_pending_tx == 0)
 		wake_up(&htt->empty_tx_wq);
 	spin_unlock_bh(&htt->tx_lock);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 2/5] ath10k: avoid needless memset on TX path
From: Michal Kazior @ 2013-09-18 12:43 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1379508202-9660-1-git-send-email-michal.kazior@tieto.com>

This reduces number of memory accesses and
hopefully contributes to better performance in the
future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
 drivers/net/wireless/ath/ath10k/htc.c    |    2 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c |    4 +++-
 drivers/net/wireless/ath/ath10k/mac.c    |    4 +++-
 drivers/net/wireless/ath/ath10k/txrx.c   |    1 -
 4 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index d0d7212..3118d75 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -103,10 +103,10 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
 	struct ath10k_htc_hdr *hdr;
 
 	hdr = (struct ath10k_htc_hdr *)skb->data;
-	memset(hdr, 0, sizeof(*hdr));
 
 	hdr->eid = ep->eid;
 	hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
+	hdr->flags = 0;
 
 	spin_lock_bh(&ep->htc->tx_lock);
 	hdr->seq_no = ep->seq_no++;
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 4548128..c4bbf74 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -384,9 +384,11 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	/* refcount is decremented by HTC and HTT completions until it reaches
 	 * zero and is freed */
 	skb_cb = ATH10K_SKB_CB(txdesc);
+	skb_cb->htt.is_conf = false;
 	skb_cb->htt.msdu_id = msdu_id;
 	skb_cb->htt.refcount = 2;
 	skb_cb->htt.msdu = msdu;
+	skb_cb->htt.txfrag = NULL;
 
 	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
 	if (res)
@@ -505,7 +507,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
 	skb_put(txdesc, desc_len);
 	cmd = (struct htt_cmd *)txdesc->data;
-	memset(cmd, 0, desc_len);
 
 	tid = ATH10K_SKB_CB(msdu)->htt.tid;
 
@@ -555,6 +556,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	/* refcount is decremented by HTC and HTT completions until it reaches
 	 * zero and is freed */
 	skb_cb = ATH10K_SKB_CB(txdesc);
+	skb_cb->htt.is_conf = false;
 	skb_cb->htt.msdu_id = msdu_id;
 	skb_cb->htt.refcount = 2;
 	skb_cb->htt.txfrag = txfrag;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 5a56833..0d367e4 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1757,7 +1757,9 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 		ath10k_tx_h_seq_no(skb);
 	}
 
-	memset(ATH10K_SKB_CB(skb), 0, sizeof(*ATH10K_SKB_CB(skb)));
+	ATH10K_SKB_CB(skb)->is_mapped = false;
+	ATH10K_SKB_CB(skb)->is_aborted = false;
+	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id;
 	ATH10K_SKB_CB(skb)->htt.tid = tid;
 
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 37b8196..f6fed31 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -75,7 +75,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
 	ath10k_report_offchan_tx(htt->ar, msdu);
 
 	info = IEEE80211_SKB_CB(msdu);
-	memset(&info->status, 0, sizeof(info->status));
 
 	if (ATH10K_SKB_CB(txdesc)->htt.discard) {
 		ieee80211_free_txskb(htt->ar->hw, msdu);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 0/5] ath10k: tx performance patches
From: Michal Kazior @ 2013-09-18 12:43 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior

Hi,

This patchset reduces CPU load and improves
improves TX performance on AP135 by additional
30mbps (give or take; 560mbps -> 590mbps), at
least on my testbed.


Michal Kazior (5):
  ath10k: use num_pending_tx instead of msdu id bitmap
  ath10k: avoid needless memset on TX path
  ath10k: decouple HTT TX completions
  ath10k: cleanup HTT TX functions
  ath10k: use msdu headroom to store txfrag

 drivers/net/wireless/ath/ath10k/core.h   |   12 +-
 drivers/net/wireless/ath/ath10k/htc.c    |    2 +-
 drivers/net/wireless/ath/ath10k/htt_rx.c |    4 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c |  249 ++++++++++++------------------
 drivers/net/wireless/ath/ath10k/mac.c    |    9 +-
 drivers/net/wireless/ath/ath10k/txrx.c   |   65 +++-----
 drivers/net/wireless/ath/ath10k/txrx.h   |    5 +-
 7 files changed, 131 insertions(+), 215 deletions(-)

-- 
1.7.9.5


^ permalink raw reply

* Re: [PATCH] ath10k: implement host memory chunks feature
From: Bartosz Markowski @ 2013-09-18 12:36 UTC (permalink / raw)
  To: Michal Kazior; +Cc: ath10k, linux-wireless
In-Reply-To: <CA+BoTQ=fRoVXNaeiiWUwc_tLiW4GJZnCKJKYO55+JHqOSasAkA@mail.gmail.com>

On 18 September 2013 12:51, Michal Kazior <michal.kazior@tieto.com> wrote:
> On 18 September 2013 11:47, Bartosz Markowski

[...]

>> +#define MAX_MEM_CHUNKS 32
>
> I think this should be prefixed with ATH10K_.

I'll fix this in v2, thanks

>> +
>> +       /* Allocate/Free the host memory for firmware use */
>> +       int (*chunk_alloc)(struct ath10k *ar, u32 req_id, u32 index,
>> +                          u32 num_units, u32 unit_len);
>> +
>> +       void (*chunk_free)(struct ath10k *ar, int idx);
>
> Can't we simply use dma_alloc_coherent(ar->dev) and avoid this HIF
> abstraction? pci_alloc_consistent is just an alias for
> dma_alloc_coherent anyway.

I guess so, but that's only an option If there's no NACK for current
version, I will keep it as is.

>> @@ -173,4 +179,21 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
>>         return ar->hif.ops->resume(ar);
>>  }
>>
>> +static inline int ath10k_hif_chunk_alloc(struct ath10k *ar,
>> +                                        u32 req_id,
>> +                                        u32 idx,
>> +                                        u32 num_units,
>> +                                        u32 unit_len)
>> +{
>> +       if (!ar->hif.ops->chunk_alloc)
>> +               return -EOPNOTSUPP;
>> +
>> +       return ar->hif.ops->chunk_alloc(ar, req_id, idx, num_units, unit_len);
>> +}
>> +
>> +static inline void ath10k_hif_chunk_free(struct ath10k *ar, int idx)
>> +{
>
> Missing check for hif.ops->chunk_free pointer here?

As in all void callbacks there. Maybe I will send a separte patch to add this.

>> +       ar->hif.ops->chunk_free(ar, idx);
>> +}
>> +
>>  #endif /* _HIF_H_ */
>> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
>> index f1faf46..547d67d 100644
>> --- a/drivers/net/wireless/ath/ath10k/pci.c
>> +++ b/drivers/net/wireless/ath/ath10k/pci.c
>> @@ -1966,6 +1966,49 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
>>  }
>>  #endif
>>
>> +static int ath10k_pci_hif_chunk_alloc(struct ath10k *ar,
>> +                                     u32 req_id,
>> +                                     u32 idx,
>> +                                     u32 num_units,
>> +                                     u32 unit_len)
>> +{
>> +       dma_addr_t paddr;
>> +       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
>> +
>> +       if (!num_units  || !unit_len)
>> +               return 0;
>> +
>
> I'm not seeing any checks against buffer overflow of mem_chunks[req_id].

if (idx == ATH10K_MAX_MEM_CHUNKS) in ath10k_wmi_alloc_host_mem ?

>> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
>> index 6803ead..89de893 100644
>> --- a/drivers/net/wireless/ath/ath10k/wmi.c
>> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
>> @@ -22,6 +22,7 @@
>>  #include "debug.h"
>>  #include "wmi.h"
>>  #include "mac.h"
>> +#include "hif.h"
>>
>>  int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
>>  {
>> @@ -964,6 +965,46 @@ static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
>>         ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
>>  }
>>
>> +#define HOST_MEM_SIZE_UNIT 4
>> +
>> +static void ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
>> +                                     u32 num_units, u32 unit_len)
>> +{
>> +       u32 remaining_units, allocated_units, idx;
>> +
>> +       /* adjust the length to nearest multiple of unit size */
>> +       unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) &
>> +                  (~(HOST_MEM_SIZE_UNIT - 1));
>
> round_up() ?

Good point :) Thanks

>> @@ -1013,12 +1054,44 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
>>                          ar->fw_version_build);
>>         }
>>
>> -       /* FIXME: it probably should be better to support this */
>> -       if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
>> -               ath10k_warn("target requested %d memory chunks; ignoring\n",
>> +       WARN_ON(__le32_to_cpu(ev->num_mem_reqs) > WMI_MAX_MEM_REQS);
>
> This seems wrong.
>
> ath10k_warn() should be used here. Is it really safe to continue and
> use the num_mem_reqs while it exceeds the limit?

I will change to ath10k_warn(). As far as I know there's no case FW
requests more than 1 mem_req, but
hmm maybe it's better to fallback here..

>> +
>> +       if (__le32_to_cpu(ev->num_mem_reqs)) {
>
> if (!__le32_to_cpu(ev->num_mem_reqs))
>   return;

Right, thanks

-- 
Bartosz

^ permalink raw reply

* Re: [PATCH] ath10k: implement host memory chunks feature
From: Michal Kazior @ 2013-09-18 10:51 UTC (permalink / raw)
  To: Bartosz Markowski; +Cc: ath10k, linux-wireless
In-Reply-To: <1379497651-29933-1-git-send-email-bartosz.markowski@tieto.com>

On 18 September 2013 11:47, Bartosz Markowski
<bartosz.markowski@tieto.com> wrote:
> Firmware can request a memory pool from host to offload
> it's own resources. This is a feature designed especially
> for AP mode where the target has to deal with large number
> of peers.
>
> So we allocate and map a consistent DMA memory which FW can
> use to store e.g. peer rate contol maps.
>
> Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
> ---
>  drivers/net/wireless/ath/ath10k/core.h |   12 +++
>  drivers/net/wireless/ath/ath10k/hif.h  |   23 ++++++
>  drivers/net/wireless/ath/ath10k/pci.c  |   45 +++++++++++
>  drivers/net/wireless/ath/ath10k/wmi.c  |  129 ++++++++++++++++++++++++++++++--
>  drivers/net/wireless/ath/ath10k/wmi.h  |   12 ++-
>  5 files changed, 209 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index fcf94ee..c194f61 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -278,6 +278,15 @@ enum ath10k_fw_features {
>         ATH10K_FW_FEATURE_COUNT,
>  };
>
> +#define MAX_MEM_CHUNKS 32

I think this should be prefixed with ATH10K_.


> +
> +struct ath10k_mem_chunk {
> +       void *vaddr;
> +       dma_addr_t paddr;
> +       u32 len;
> +       u32 req_id;
> +};
> +
>  struct ath10k {
>         struct ath_common ath_common;
>         struct ieee80211_hw *hw;
> @@ -297,6 +306,9 @@ struct ath10k {
>         u32 vht_cap_info;
>         u32 num_rf_chains;
>
> +       u32 num_mem_chunks;
> +       struct ath10k_mem_chunk mem_chunks[MAX_MEM_CHUNKS];
> +
>         DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
>
>         struct targetdef *targetdef;
> diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
> index dcdea68..4af6a66 100644
> --- a/drivers/net/wireless/ath/ath10k/hif.h
> +++ b/drivers/net/wireless/ath/ath10k/hif.h
> @@ -83,6 +83,12 @@ struct ath10k_hif_ops {
>
>         int (*suspend)(struct ath10k *ar);
>         int (*resume)(struct ath10k *ar);
> +
> +       /* Allocate/Free the host memory for firmware use */
> +       int (*chunk_alloc)(struct ath10k *ar, u32 req_id, u32 index,
> +                          u32 num_units, u32 unit_len);
> +
> +       void (*chunk_free)(struct ath10k *ar, int idx);

Can't we simply use dma_alloc_coherent(ar->dev) and avoid this HIF
abstraction? pci_alloc_consistent is just an alias for
dma_alloc_coherent anyway.


>  };
>
>
> @@ -173,4 +179,21 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
>         return ar->hif.ops->resume(ar);
>  }
>
> +static inline int ath10k_hif_chunk_alloc(struct ath10k *ar,
> +                                        u32 req_id,
> +                                        u32 idx,
> +                                        u32 num_units,
> +                                        u32 unit_len)
> +{
> +       if (!ar->hif.ops->chunk_alloc)
> +               return -EOPNOTSUPP;
> +
> +       return ar->hif.ops->chunk_alloc(ar, req_id, idx, num_units, unit_len);
> +}
> +
> +static inline void ath10k_hif_chunk_free(struct ath10k *ar, int idx)
> +{

Missing check for hif.ops->chunk_free pointer here?


> +       ar->hif.ops->chunk_free(ar, idx);
> +}
> +
>  #endif /* _HIF_H_ */
> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
> index f1faf46..547d67d 100644
> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -1966,6 +1966,49 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
>  }
>  #endif
>
> +static int ath10k_pci_hif_chunk_alloc(struct ath10k *ar,
> +                                     u32 req_id,
> +                                     u32 idx,
> +                                     u32 num_units,
> +                                     u32 unit_len)
> +{
> +       dma_addr_t paddr;
> +       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
> +
> +       if (!num_units  || !unit_len)
> +               return 0;
> +

I'm not seeing any checks against buffer overflow of mem_chunks[req_id].


> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
> index 6803ead..89de893 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -22,6 +22,7 @@
>  #include "debug.h"
>  #include "wmi.h"
>  #include "mac.h"
> +#include "hif.h"
>
>  int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
>  {
> @@ -964,6 +965,46 @@ static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
>         ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
>  }
>
> +#define HOST_MEM_SIZE_UNIT 4
> +
> +static void ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
> +                                     u32 num_units, u32 unit_len)
> +{
> +       u32 remaining_units, allocated_units, idx;
> +
> +       /* adjust the length to nearest multiple of unit size */
> +       unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) &
> +                  (~(HOST_MEM_SIZE_UNIT - 1));

round_up() ?


> @@ -1013,12 +1054,44 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
>                          ar->fw_version_build);
>         }
>
> -       /* FIXME: it probably should be better to support this */
> -       if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
> -               ath10k_warn("target requested %d memory chunks; ignoring\n",
> +       WARN_ON(__le32_to_cpu(ev->num_mem_reqs) > WMI_MAX_MEM_REQS);

This seems wrong.

ath10k_warn() should be used here. Is it really safe to continue and
use the num_mem_reqs while it exceeds the limit?


> +
> +       if (__le32_to_cpu(ev->num_mem_reqs)) {

if (!__le32_to_cpu(ev->num_mem_reqs))
  return;



Michał.

^ permalink raw reply


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