* [PATCH v1] brcmfmac: use %*ph to print small buffer
From: Andy Shevchenko @ 2019-09-04 17:50 UTC (permalink / raw)
To: Arend van Spriel, Franky Lin, Hante Meuleman, Chi-Hsien Lin,
Wright Feng, linux-wireless, Kalle Valo, brcm80211-dev-list.pdl,
brcm80211-dev-list
Cc: Andy Shevchenko
Use %*ph format to print small buffer as hex string.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 5dcaaf65799e..dd6303f5f72e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -4222,10 +4222,8 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
vndr_ies->count++;
- brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
- parsed_info->vndrie.oui[0],
- parsed_info->vndrie.oui[1],
- parsed_info->vndrie.oui[2],
+ brcmf_dbg(TRACE, "** OUI %3ph, type 0x%02x\n",
+ parsed_info->vndrie.oui,
parsed_info->vndrie.oui_type);
if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
@@ -4349,12 +4347,10 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
for (i = 0; i < old_vndr_ies.count; i++) {
vndrie_info = &old_vndr_ies.ie_info[i];
- brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
+ brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%3ph\n",
vndrie_info->vndrie.id,
vndrie_info->vndrie.len,
- vndrie_info->vndrie.oui[0],
- vndrie_info->vndrie.oui[1],
- vndrie_info->vndrie.oui[2]);
+ vndrie_info->vndrie.oui);
del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
vndrie_info->ie_ptr,
@@ -4386,12 +4382,10 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
remained_buf_len -= (vndrie_info->ie_len +
VNDR_IE_VSIE_OFFSET);
- brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
+ brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%3ph\n",
vndrie_info->vndrie.id,
vndrie_info->vndrie.len,
- vndrie_info->vndrie.oui[0],
- vndrie_info->vndrie.oui[1],
- vndrie_info->vndrie.oui[2]);
+ vndrie_info->vndrie.oui);
del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
vndrie_info->ie_ptr,
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH v1] zd1211rw: use %*ph to print small buffer
From: Andy Shevchenko @ 2019-09-04 17:53 UTC (permalink / raw)
To: Daniel Drake, Ulrich Kunitz, linux-wireless, Kalle Valo; +Cc: Andy Shevchenko
Use %*ph format to print small buffer as hex string.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/net/wireless/zydas/zd1211rw/zd_chip.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_chip.c b/drivers/net/wireless/zydas/zd1211rw/zd_chip.c
index 40c0a86dbfc7..0af4b1986e48 100644
--- a/drivers/net/wireless/zydas/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_chip.c
@@ -41,8 +41,7 @@ void zd_chip_clear(struct zd_chip *chip)
static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size)
{
u8 *addr = zd_mac_get_perm_addr(zd_chip_to_mac(chip));
- return scnprintf(buffer, size, "%02x-%02x-%02x",
- addr[0], addr[1], addr[2]);
+ return scnprintf(buffer, size, "%3phD", addr);
}
/* Prints an identifier line, which will support debugging. */
--
2.23.0.rc1
^ permalink raw reply related
* [RFC 0/4] Allow live MAC address change
From: James Prestwood @ 2019-09-04 19:11 UTC (permalink / raw)
To: linux-wireless; +Cc: James Prestwood
This set enables userspace to change the devices MAC address via RTNL
or CMD_CONNECT/CMD_AUTHENTICATE without bringing the device down then
back up. This has several benefits:
- Simplifies user space logic. No longer requires tracking multiple
RTNL/netlink message transactions (down, change mac, up, connect).
- Drastically speeds up connection times when changing MAC on a
per-connect basis.
- Eliminates potential race conditions in userspace. At any time
during the down/change/up sequence the device could be hot
unplugged or something could go wrong in the kernel leaving
userspace in an unknown state.
A new extended feature was added,
NL80211_EXT_FEATURE_LIVE_ADDRESS_CHANGE which is set if the device
supports this feature. This feature is enabled by default for mac80211
based drivers.
A new NL80211 attribute was added, NL80211_ATTR_MAC_TO_CHANGE. This
attribute can be used with CMD_CONNECT/CMD_AUTHENTICATE to change the
MAC address automatically without having to go through RTNL.
I have taken some timings for all 3 ways of changing the MAC. Powered
change via RTNL, non powered via RTNL, and changing through
CMD_CONNECT. All times were taken in microseconds and tested on an
Intel 7260 PCI wireless adapter:
Powered via RTNL:
Average: 294508.9
Min: 284523
Max: 300345
==================================
Non-Powered via RTNL:
Average: 14824.7
Min: 11037
Max: 17812
Speedup from powered change: 19.87x (average)
==================================
via CMD_CONNECT:
Average: 11848.7
Min: 9748
Max: 17152
Speedup from powered change: 24.86x (average)
==================================
The speed increases between powered and non-powered are quite
impressive. Besides the obvious speedup, the amount of code requred
for userspace to take advantage of this feature is extremely small
(via CMD_CONNECT, essentially a feature check and an extra attribute).
In addition, the changes/complexity to the kernel is minimal.
James Prestwood (4):
nl80211: Add LIVE_ADDR_CHANGE feature
{nl|cfg}80211: Support mac change as part of SME Connect
mac80211: Support LIVE_ADDRESS_CHANGE feature
{nl,cfg}nl80211: Support mac change for mlme_authenticate
include/net/cfg80211.h | 1 +
include/uapi/linux/nl80211.h | 10 +++++++
net/mac80211/iface.c | 51 ++++++++++++++++++++++++++++++++++--
net/mac80211/main.c | 1 +
net/wireless/core.h | 4 ++-
net/wireless/mlme.c | 9 ++++++-
net/wireless/nl80211.c | 18 ++++++++++++-
net/wireless/sme.c | 9 ++++++-
net/wireless/util.c | 11 ++++++++
9 files changed, 108 insertions(+), 6 deletions(-)
--
2.17.1
^ permalink raw reply
* [RFC 1/4] nl80211: Add LIVE_ADDR_CHANGE feature
From: James Prestwood @ 2019-09-04 19:11 UTC (permalink / raw)
To: linux-wireless; +Cc: James Prestwood
In-Reply-To: <20190904191155.28056-1-prestwoj@gmail.com>
Add a new feature bit signifying that the wireless hardware supports
changing the mac address while the underlying net_device is UP. Note
that this is slightly different from IFF_LIVE_ADDR_CHANGE as additional
restrictions might be imposed by the hardware. Typical restrictions
are:
- No connection is active on this interface, e.g. carrier is off
- No scan is in progress
- No offchannel operation is in progress
---
include/uapi/linux/nl80211.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index bf7c4222f512..0ceb945a08fb 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -5481,6 +5481,14 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
* station mode (SAE password is passed as part of the connect command).
*
+ * @NL80211_EXT_FEATURE_LIVE_ADDR_CHANGE: Device can perform a MAC address
+ * change without having to bring the underlying network device down
+ * first. For example, in station mode this can be used to vary the
+ * origin MAC address prior to a connection to a new AP for privacy
+ * or other reasons. Note that certain driver specific restrictions
+ * might apply, e.g. no scans in progress, no offchannel operations
+ * in progress, and no active connections.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5526,6 +5534,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
NL80211_EXT_FEATURE_SAE_OFFLOAD,
+ NL80211_EXT_FEATURE_LIVE_ADDRESS_CHANGE,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
--
2.17.1
^ permalink raw reply related
* [RFC 2/4] {nl|cfg}80211: Support mac change as part of SME Connect
From: James Prestwood @ 2019-09-04 19:11 UTC (permalink / raw)
To: linux-wireless; +Cc: James Prestwood
In-Reply-To: <20190904191155.28056-1-prestwoj@gmail.com>
---
include/net/cfg80211.h | 1 +
include/uapi/linux/nl80211.h | 1 +
net/wireless/core.h | 1 +
net/wireless/nl80211.c | 11 +++++++++++
net/wireless/sme.c | 7 +++++++
net/wireless/util.c | 11 +++++++++++
6 files changed, 32 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5253e7f667bd..25eacbebfa29 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2553,6 +2553,7 @@ struct cfg80211_connect_params {
size_t fils_erp_rrk_len;
bool want_1x;
struct ieee80211_edmg edmg;
+ const u8 *mac_to_use;
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 0ceb945a08fb..1bb4ce58da67 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2834,6 +2834,7 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_EDMG_CHANNELS,
NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ NL80211_ATTR_MAC_TO_USE,
/* add attributes here, update the policy in nl80211.c */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 77556c58d9ac..29e6ab2cf343 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -454,6 +454,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct vif_params *params);
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
void cfg80211_process_wdev_events(struct wireless_dev *wdev);
+int cfg80211_set_mac_to_use(struct net_device *dev, const u8 *mac);
bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
u32 center_freq_khz, u32 bw_khz);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4565d7385884..0202a762b5c8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -591,6 +591,8 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
.len = SAE_PASSWORD_MAX_LEN },
[NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
[NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
+ [NL80211_ATTR_MAC_TO_USE] = { .type = NLA_EXACT_LEN_WARN,
+ .len = ETH_ALEN },
};
/* policy for the key attributes */
@@ -10045,6 +10047,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT;
}
+ if (info->attrs[NL80211_ATTR_MAC_TO_USE]) {
+ if (!wiphy_ext_feature_isset(wiphy,
+ NL80211_EXT_FEATURE_LIVE_ADDRESS_CHANGE))
+ return -EOPNOTSUPP;
+
+ connect.mac_to_use =
+ nla_data(info->attrs[NL80211_ATTR_MAC_TO_USE]);
+ }
+
wdev_lock(dev->ieee80211_ptr);
err = cfg80211_connect(rdev, dev, &connect, connkeys,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 7a6c38ddc65a..f164af33655f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1242,11 +1242,18 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
IEEE80211_BSS_TYPE_ESS;
+ if (connect->mac_to_use) {
+ err = cfg80211_set_mac_to_use(dev, connect->mac_to_use);
+ if (err)
+ goto fail;
+ }
+
if (!rdev->ops->connect)
err = cfg80211_sme_connect(wdev, connect, prev_bssid);
else
err = rdev_connect(rdev, dev, connect);
+fail:
if (err) {
wdev->connect_keys = NULL;
/*
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 92cb2cbb179b..06700431cba0 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2148,3 +2148,14 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
return false;
}
EXPORT_SYMBOL(cfg80211_iftype_allowed);
+
+int cfg80211_set_mac_to_use(struct net_device *dev, const u8 *mac)
+{
+ struct sockaddr sa;
+
+ sa.sa_family = dev->type;
+ memcpy(sa.sa_data, mac, ETH_ALEN);
+
+ return dev_set_mac_address(dev, &sa, NULL);
+}
+EXPORT_SYMBOL(cfg80211_set_mac_to_use);
--
2.17.1
^ permalink raw reply related
* [RFC 3/4] mac80211: Support LIVE_ADDRESS_CHANGE feature
From: James Prestwood @ 2019-09-04 19:11 UTC (permalink / raw)
To: linux-wireless; +Cc: James Prestwood
In-Reply-To: <20190904191155.28056-1-prestwoj@gmail.com>
---
net/mac80211/iface.c | 51 ++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/main.c | 1 +
2 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8dc6580e1787..16ef6b83e7ea 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -198,15 +198,57 @@ static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr,
return ret;
}
+static int ieee80211_can_live_addr_change(struct ieee80211_sub_if_data *sdata)
+{
+ if (netif_carrier_ok(sdata->dev))
+ return -EBUSY;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_OCB:
+ /* No further checking required, when started or UP these
+ * interface types set carrier
+ */
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (sdata->u.ibss.ssid_len != 0)
+ return -EBUSY;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (!list_empty(&sdata->local->roc_list) ||
+ !sdata->local->scanning)
+ return -EBUSY;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+
static int ieee80211_change_mac(struct net_device *dev, void *addr)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct sockaddr *sa = addr;
bool check_dup = true;
+ bool live = false;
int ret;
- if (ieee80211_sdata_running(sdata))
- return -EBUSY;
+ if (ieee80211_sdata_running(sdata)) {
+ ret = ieee80211_can_live_addr_change(sdata);
+ if (ret)
+ return ret;
+
+ live = true;
+ }
if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
@@ -216,7 +258,11 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
if (ret)
return ret;
+ if (live)
+ drv_remove_interface(local, sdata);
ret = eth_mac_addr(dev, sa);
+ if (live)
+ drv_add_interface(local, sdata);
if (ret == 0)
memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
@@ -1871,6 +1917,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->u.mgd.use_4addr = params->use_4addr;
ndev->features |= local->hw.netdev_features;
+ ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 29b9d57df1a3..0aea583e5e69 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -596,6 +596,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_LIVE_ADDRESS_CHANGE);
wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
--
2.17.1
^ permalink raw reply related
* [RFC 4/4] {nl,cfg}nl80211: Support mac change for mlme_authenticate
From: James Prestwood @ 2019-09-04 19:11 UTC (permalink / raw)
To: linux-wireless; +Cc: James Prestwood
In-Reply-To: <20190904191155.28056-1-prestwoj@gmail.com>
---
net/wireless/core.h | 3 ++-
net/wireless/mlme.c | 9 ++++++++-
net/wireless/nl80211.c | 7 ++++++-
net/wireless/sme.c | 2 +-
4 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 29e6ab2cf343..869ab983692d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -366,7 +366,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *auth_data, int auth_data_len);
+ const u8 *auth_data, int auth_data_len,
+ const u8 *mac_to_use);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index f9462010575f..adf411905e64 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -226,7 +226,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *auth_data, int auth_data_len)
+ const u8 *auth_data, int auth_data_len,
+ const u8 *mac_to_use)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req = {
@@ -257,6 +258,12 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (!req.bss)
return -ENOENT;
+ if (mac_to_use) {
+ err = cfg80211_set_mac_to_use(dev, mac_to_use);
+ if (err)
+ return err;
+ }
+
err = rdev_auth(rdev, dev, &req);
cfg80211_put_bss(&rdev->wiphy, req.bss);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0202a762b5c8..db32eaaaa50e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8898,6 +8898,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
enum nl80211_auth_type auth_type;
struct key_parse key;
bool local_state_change;
+ const u8 *mac_to_change = NULL;
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
@@ -8993,6 +8994,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+ if (info->attrs[NL80211_ATTR_MAC_TO_USE])
+ mac_to_change = nla_data(
+ info->attrs[NL80211_ATTR_MAC_TO_USE]);
+
/*
* Since we no longer track auth state, ignore
* requests to only change local state.
@@ -9004,7 +9009,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx,
- auth_data, auth_data_len);
+ auth_data, auth_data_len, mac_to_change);
wdev_unlock(dev->ieee80211_ptr);
return err;
}
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index f164af33655f..f66ea48b73df 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -174,7 +174,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev,
params->ssid, params->ssid_len,
NULL, 0,
params->key, params->key_len,
- params->key_idx, NULL, 0);
+ params->key_idx, NULL, 0, NULL);
case CFG80211_CONN_AUTH_FAILED_TIMEOUT:
*treason = NL80211_TIMEOUT_AUTH;
return -ENOTCONN;
--
2.17.1
^ permalink raw reply related
* [PATCH] cfg80211: Do not compare with boolean in nl80211_common_reg_change_event
From: zhong jiang @ 2019-09-05 4:25 UTC (permalink / raw)
To: johannes, davem; +Cc: linux-wireless, zhongjiang, netdev, linux-kernel
With the help of boolinit.cocci, we use !nl80211_reg_change_event_fill
instead of (nl80211_reg_change_event_fill == false). Meanwhile, Clean
up the code.
Signed-off-by: zhong jiang <zhongjiang@huawei.com>
---
net/wireless/nl80211.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3e30e18..0c7fa60 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -14997,12 +14997,10 @@ void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
- if (!hdr) {
- nlmsg_free(msg);
- return;
- }
+ if (!hdr)
+ goto nla_put_failure;
- if (nl80211_reg_change_event_fill(msg, request) == false)
+ if (!nl80211_reg_change_event_fill(msg, request))
goto nla_put_failure;
genlmsg_end(msg, hdr);
--
1.7.12.4
^ permalink raw reply related
* Re: [PATCH 1/2] staging: dt-bindings: wilc1000: add optional rtc_clk property
From: Ajay.Kathat @ 2019-09-05 6:09 UTC (permalink / raw)
To: Eugen.Hristev, Adham.Abozaeid, linux-wireless, devel,
linux-kernel
Cc: Claudiu.Beznea
In-Reply-To: <1567603548-13355-1-git-send-email-eugen.hristev@microchip.com>
Hi Eugen,
On 04-Sep-19 7:03 PM, Eugen Hristev - M18282 wrote:
> From: Eugen Hristev <eugen.hristev@microchip.com>
>
> Add bindings for optional rtc clock pin.
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Thanks for sending the patch series. The changes in this series looks
good to me.
Acked-by: Ajay Singh <ajay.kathat@microchip.com>
Regards,
Ajay
> ---
> drivers/staging/wilc1000/microchip,wilc1000,sdio.txt | 8 +++++++-
> drivers/staging/wilc1000/microchip,wilc1000,spi.txt | 8 ++++++++
> 2 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt b/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
> index 4f7d1c2..da52359 100644
> --- a/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
> +++ b/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
> @@ -10,7 +10,9 @@ Required properties:
>
> Optional:
> - bus-width : Number of data lines wired up the slot. Default 1 bit.
> -
> +- rtc_clk : Clock connected on the rtc clock line. Must be assigned
> + a frequency with assigned-clocks property, and must be
> + connected to a clock provider.
>
> Examples:
> mmc1: mmc@fc000000 {
> @@ -24,6 +26,10 @@ mmc1: mmc@fc000000 {
> wilc_sdio@0 {
> compatible = "microchip,wilc1000-sdio";
> irq-gpios = <&pioC 27 0>;
> + clocks = <&pck1>;
> + clock-names = "rtc_clk";
> + assigned-clocks = <&pck1>;
> + assigned-clock-rates = <32768>;
> status = "okay";
> reg = <0>;
> bus-width = <4>;
> diff --git a/drivers/staging/wilc1000/microchip,wilc1000,spi.txt b/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
> index 87db87b..3423693 100644
> --- a/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
> +++ b/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
> @@ -9,6 +9,10 @@ Required properties:
> - reg : Chip select address of device
> - irq-gpios : Connect to a host IRQ
>
> +Optional:
> +- rtc_clk : Clock connected on the rtc clock line. Must be assigned
> + a frequency with assigned-clocks property, and must be
> + connected to a clock provider.
>
> Examples:
>
> @@ -21,6 +25,10 @@ spi1: spi@fc018000 {
> spi-max-frequency = <48000000>;
> reg = <0>;
> irq-gpios = <&pioC 27 0>;
> + clocks = <&pck1>;
> + clock-names = "rtc_clk";
> + assigned-clocks = <&pck1>;
> + assigned-clock-rates = <32768>;
> status = "okay";
> };
> };
>
^ permalink raw reply
* Re: [PATCH 1/2] staging: dt-bindings: wilc1000: add optional rtc_clk property
From: Greg KH @ 2019-09-05 7:37 UTC (permalink / raw)
To: Ajay.Kathat
Cc: Eugen.Hristev, Adham.Abozaeid, linux-wireless, devel,
linux-kernel
In-Reply-To: <da5ea898-d8da-a6e2-97a0-4662b7d70b31@microchip.com>
On Thu, Sep 05, 2019 at 06:09:43AM +0000, Ajay.Kathat@microchip.com wrote:
> Hi Eugen,
>
> On 04-Sep-19 7:03 PM, Eugen Hristev - M18282 wrote:
> > From: Eugen Hristev <eugen.hristev@microchip.com>
> >
> > Add bindings for optional rtc clock pin.
> >
> > Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
>
> Thanks for sending the patch series. The changes in this series looks
> good to me.
>
> Acked-by: Ajay Singh <ajay.kathat@microchip.com>
This is good, but, you are adding new features to the driver, when it is
still in the staging directory. What's the plan on getting it out of
here? What is left to do?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 2/2] staging: wilc1000: look for rtc_clk clock
From: Greg KH @ 2019-09-05 7:38 UTC (permalink / raw)
To: Eugen.Hristev
Cc: Adham.Abozaeid, Ajay.Kathat, linux-wireless, devel, linux-kernel
In-Reply-To: <1567603548-13355-2-git-send-email-eugen.hristev@microchip.com>
On Wed, Sep 04, 2019 at 01:34:01PM +0000, Eugen.Hristev@microchip.com wrote:
> From: Eugen Hristev <eugen.hristev@microchip.com>
>
> If rtc_clk is provided from DT, use it and enable it.
> This is optional.
> The signal may be hardcoded and no need to be requested,
> but if DT provides it, use it.
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
> Acked-by: Ajay Singh <ajay.kathat@microchip.com>
> ---
> drivers/staging/wilc1000/wilc_sdio.c | 14 ++++++++++++++
> drivers/staging/wilc1000/wilc_wfi_netdevice.h | 1 +
> 2 files changed, 15 insertions(+)
This patch does not apply to my tree at all.
Please redo it against staging-next and resend the series, with Ajay's
ack added to it.
thanks,
greg k-h
^ permalink raw reply
* RE: [PATCH 2/7] ath10k: change max RX bundle size from 8 to 32 for sdio
From: Wen Gong @ 2019-09-05 10:12 UTC (permalink / raw)
To: Dave Taht; +Cc: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org
In-Reply-To: <87lfv4chi2.fsf@taht.net>
> -----Original Message-----
> From: Dave Taht <dave@taht.net>
> Sent: Wednesday, September 4, 2019 9:34 PM
> To: Wen Gong <wgong@qti.qualcomm.com>
> Cc: ath10k@lists.infradead.org; linux-wireless@vger.kernel.org
> Subject: [EXT] Re: [PATCH 2/7] ath10k: change max RX bundle size from 8 to
> 32 for sdio
>
> > Hi Dave,
> > So your mean is change 8 to 32 will impact latency? It will increase latency
> of rx?
>
> Heh. for rx, in this case, probably not!
>
> I just get twitchy every time folk fiddle with buffer sizes. In one
> recent case someone had fiddled with the interrupt polling interval on
> something, going from 1ms to 10ms - it saved on cpu, but...
> ... just trying to make sure folk grok the tradoffs with a bit of
> laughter.
>
> carry on!
Hah, so you do not have any concern about this patch.
Patch 3 sent, https://patchwork.kernel.org/patch/11122175/
>
> >
> >>
> >> 0xFFFEFFFF
^ permalink raw reply
* [PATCH v5 0/8] ath10k: improve throughout of tcp/udp TX/RX of sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
The bottleneck of throughout on sdio chip is the bus bandwidth, to the
patches are all to increase the use ratio of sdio bus.
udp-rx udp-tx tcp-rx tcp-tx
without patches(Mbps) 320 180 170 151
with patches(Mbps) 450 410 400 320
These patches only affect sdio bus chip, explanation is mentioned in each
patch's commit log.
Alagu Sankar (1):
ath10k: enable RX bundle receive for sdio
v2: fix incorrect skb tail of rx bundle in ath10k_sdio_mbox_rx_process_packet
v3: change some code style
split fix incorrect skb tail of rx bundle to patch "adjust skb length in ath10k_sdio_mbox_rx_packet"
v4: add err handle in ath10k_sdio_mbox_rx_fetch_bundle
v5: no change
Nicolas Boichat (1):
ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet
v2: no this patch
v3: new added
v4: change commit log
v5: no change
Wen Gong (6):
ath10k: change max RX bundle size from 8 to 32 for sdio
v2: change macro HTC_GET_BUNDLE_COUNT
v3: change some code style
v4: add macro ATH10K_HTC_FLAG_BUNDLE_MASK
v5: no change
ath10k: add workqueue for RX path of sdio
v2: no change
v3: change some code style
v4: no change
v5: no change
ath10k: disable TX complete indication of htt for sdio
v2: change some code style
v3: change some code style
v4: no change
v5: no change
ath10k: add htt TX bundle for sdio
v2: no change
v3: change some code style
v4: no change
v5: change ath10k_htc_setup_tx_req to add check bundle_tx
to forbidden init 2 times
ath10k: enable alt data of TX path for sdio
v2: no change
v3: change some code style
v4: add macro ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK
v5: no change
ath10k: enable napi on RX path for sdio
v2: no change
v3: change some code style
v4: change some code style
v5: move skb_queue_head_init(&ar->htt.rx_indication_head)
from ath10k_htt_connect to ath10k_core_create to forbidden
init 2 times
drivers/net/wireless/ath/ath10k/core.c | 44 +++-
drivers/net/wireless/ath/ath10k/core.h | 4 +-
drivers/net/wireless/ath/ath10k/hif.h | 9 +
drivers/net/wireless/ath/ath10k/htc.c | 378 ++++++++++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/htc.h | 49 +++-
drivers/net/wireless/ath/ath10k/htt.c | 13 ++
drivers/net/wireless/ath/ath10k/htt.h | 20 +-
drivers/net/wireless/ath/ath10k/htt_rx.c | 80 ++++++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 38 +++-
drivers/net/wireless/ath/ath10k/hw.h | 2 +-
drivers/net/wireless/ath/ath10k/sdio.c | 281 ++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/sdio.h | 31 ++-
12 files changed, 852 insertions(+), 97 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH v5 1/8] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
From: Nicolas Boichat <drinkcat@chromium.org>
When the FW bundles multiple packets, pkt->act_len may be incorrect
as it refers to the first packet only (however, the FW will only
bundle packets that fit into the same pkt->alloc_len).
Before this patch, the skb length would be set (incorrectly) to
pkt->act_len in ath10k_sdio_mbox_rx_packet, and then later manually
adjusted in ath10k_sdio_mbox_rx_process_packet.
The first problem is that ath10k_sdio_mbox_rx_process_packet does not
use proper skb_put commands to adjust the length (it directly changes
skb->len), so we end up with a mismatch between skb->head + skb->tail
and skb->data + skb->len. This is quite serious, and causes corruptions
in the TCP stack, as the stack tries to coalesce packets, and relies
on skb->tail being correct (that is, skb_tail_pointer must point to
the first byte_after_ the data).
Instead of re-adjusting the size in ath10k_sdio_mbox_rx_process_packet,
this moves the code to ath10k_sdio_mbox_rx_packet, and also add a
bounds check, as skb_put would crash the kernel if not enough space is
available.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Fixes: 8530b4e7b22bc3b ("ath10k: sdio: set skb len for all rx packets")
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: no this patch
v3: new added
v4: change commit log
v5: no change
drivers/net/wireless/ath/ath10k/sdio.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 8ed4fbd..1127e44 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -381,16 +381,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data;
bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
enum ath10k_htc_ep_id eid;
- u16 payload_len;
u8 *trailer;
int ret;
- payload_len = le16_to_cpu(htc_hdr->len);
- skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
-
if (trailer_present) {
- trailer = skb->data + sizeof(*htc_hdr) +
- payload_len - htc_hdr->trailer_len;
+ trailer = skb->data + skb->len - htc_hdr->trailer_len;
eid = pipe_id_to_eid(htc_hdr->eid);
@@ -632,13 +627,29 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
struct sk_buff *skb = pkt->skb;
+ struct ath10k_htc_hdr *htc_hdr;
int ret;
ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
skb->data, pkt->alloc_len);
+
+ if (!ret) {
+ /* Update actual length. The original length may be incorrect,
+ * as the FW will bundle multiple packets as long as their sizes
+ * fit within the same aligned length (pkt->alloc_len).
+ */
+ htc_hdr = (struct ath10k_htc_hdr *)skb->data;
+ pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
+ if (pkt->act_len <= pkt->alloc_len) {
+ skb_put(skb, pkt->act_len);
+ } else {
+ ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
+ pkt->act_len, pkt->alloc_len);
+ ret = -EMSGSIZE;
+ }
+ }
+
pkt->status = ret;
- if (!ret)
- skb_put(skb, pkt->act_len);
return ret;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v5 2/8] ath10k: enable RX bundle receive for sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
From: Alagu Sankar <alagusankar@silex-india.com>
The existing implementation of initiating multiple sdio transfers for
receive bundling is slowing down the receive speed. Combining the
transfers using a bundle method would be ideal.
The transmission utilization ratio for sdio bus for small packet is
slow, because the space and time cost for sdio bus is same for large
length packet and small length packet. So the speed of data for large
length packet is higher than small length.
Test result of different length of data:
data packet(byte) cost time(us) calculated rate(Mbps)
256 28 73
512 33 124
1024 35 234
1792 45 318
14336 168 682
28672 333 688
57344 660 695
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Alagu Sankar <alagusankar@silex-india.com>
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: fix incorrect skb tail of rx bundle in ath10k_sdio_mbox_rx_process_packet
v3: change some code style
split fix incorrect skb tail of rx bundle to patch "adjust skb length in ath10k_sdio_mbox_rx_packet"
v4: add err handle in ath10k_sdio_mbox_rx_fetch_bundle
v5: no change
drivers/net/wireless/ath/ath10k/sdio.c | 108 ++++++++++++++++++++++-----------
drivers/net/wireless/ath/ath10k/sdio.h | 7 ++-
2 files changed, 76 insertions(+), 39 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 1127e44..d7ffcd5 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -24,6 +24,9 @@
#include "trace.h"
#include "sdio.h"
+#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
+#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
+
/* inlined helper functions */
static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
@@ -484,11 +487,11 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
return ret;
}
-static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar,
- struct ath10k_sdio_rx_data *rx_pkts,
- struct ath10k_htc_hdr *htc_hdr,
- size_t full_len, size_t act_len,
- size_t *bndl_cnt)
+static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
+ struct ath10k_sdio_rx_data *rx_pkts,
+ struct ath10k_htc_hdr *htc_hdr,
+ size_t full_len, size_t act_len,
+ size_t *bndl_cnt)
{
int ret, i;
@@ -529,6 +532,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
size_t full_len, act_len;
bool last_in_bundle;
int ret, i;
+ int pkt_cnt = 0;
if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) {
ath10k_warn(ar,
@@ -572,20 +576,22 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
*/
size_t bndl_cnt;
- ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar,
- &ar_sdio->rx_pkts[i],
- htc_hdr,
- full_len,
- act_len,
- &bndl_cnt);
+ struct ath10k_sdio_rx_data *rx_pkts =
+ &ar_sdio->rx_pkts[pkt_cnt];
+
+ ret = ath10k_sdio_mbox_alloc_bundle(ar,
+ rx_pkts,
+ htc_hdr,
+ full_len,
+ act_len,
+ &bndl_cnt);
if (ret) {
ath10k_warn(ar, "alloc_bundle error %d\n", ret);
goto err;
}
- n_lookaheads += bndl_cnt;
- i += bndl_cnt;
+ pkt_cnt += bndl_cnt;
/*Next buffer will be the last in the bundle */
last_in_bundle = true;
}
@@ -597,7 +603,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
if (htc_hdr->flags & ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK)
full_len += ATH10K_HIF_MBOX_BLOCK_SIZE;
- ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[i],
+ ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[pkt_cnt],
act_len,
full_len,
last_in_bundle,
@@ -606,9 +612,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret);
goto err;
}
+ pkt_cnt++;
}
- ar_sdio->n_rx_pkts = i;
+ ar_sdio->n_rx_pkts = pkt_cnt;
return 0;
@@ -622,10 +629,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
return ret;
}
-static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
- struct ath10k_sdio_rx_data *pkt)
+static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
struct sk_buff *skb = pkt->skb;
struct ath10k_htc_hdr *htc_hdr;
int ret;
@@ -633,46 +640,64 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
skb->data, pkt->alloc_len);
- if (!ret) {
- /* Update actual length. The original length may be incorrect,
- * as the FW will bundle multiple packets as long as their sizes
- * fit within the same aligned length (pkt->alloc_len).
- */
- htc_hdr = (struct ath10k_htc_hdr *)skb->data;
- pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
- if (pkt->act_len <= pkt->alloc_len) {
- skb_put(skb, pkt->act_len);
- } else {
- ath10k_warn(ar, "rx packet too large (%zu > %zu)\n",
- pkt->act_len, pkt->alloc_len);
- ret = -EMSGSIZE;
- }
+ if (ret) {
+ ar_sdio->n_rx_pkts = 0;
+ ath10k_sdio_mbox_free_rx_pkt(pkt);
+ return ret;
}
+ htc_hdr = (struct ath10k_htc_hdr *)skb->data;
+ pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
pkt->status = ret;
+ skb_put(skb, pkt->act_len);
return ret;
}
-static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
+static int ath10k_sdio_mbox_rx_fetch_bundle(struct ath10k *ar)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_data *pkt;
+ struct ath10k_htc_hdr *htc_hdr;
int ret, i;
+ u32 pkt_offset, virt_pkt_len;
+ virt_pkt_len = 0;
for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
- ret = ath10k_sdio_mbox_rx_packet(ar,
- &ar_sdio->rx_pkts[i]);
+ virt_pkt_len += ar_sdio->rx_pkts[i].alloc_len;
+ }
+
+ if (virt_pkt_len < ATH10K_SDIO_DMA_BUF_SIZE) {
+ ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
+ ar_sdio->vsg_buffer, virt_pkt_len);
if (ret)
goto err;
+ } else {
+ ath10k_err(ar, "size exceeding limit %d\n", virt_pkt_len);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pkt_offset = 0;
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
+ pkt = &ar_sdio->rx_pkts[i];
+ htc_hdr = (struct ath10k_htc_hdr *)(ar_sdio->vsg_buffer + pkt_offset);
+ pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr);
+
+ skb_put_data(pkt->skb, htc_hdr, pkt->act_len);
+ pkt->status = 0;
+ pkt_offset += pkt->alloc_len;
}
return 0;
err:
/* Free all packets that was not successfully fetched. */
- for (; i < ar_sdio->n_rx_pkts; i++)
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++)
ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]);
+ ar_sdio->n_rx_pkts = 0;
+
return ret;
}
@@ -715,7 +740,10 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar,
*/
*done = false;
- ret = ath10k_sdio_mbox_rx_fetch(ar);
+ if (ar_sdio->n_rx_pkts > 1)
+ ret = ath10k_sdio_mbox_rx_fetch_bundle(ar);
+ else
+ ret = ath10k_sdio_mbox_rx_fetch(ar);
/* Process fetched packets. This will potentially update
* n_lookaheads depending on if the packets contain lookahead
@@ -1123,7 +1151,7 @@ static int ath10k_sdio_bmi_get_rx_lookahead(struct ath10k *ar)
MBOX_HOST_INT_STATUS_ADDRESS,
&rx_word);
if (ret) {
- ath10k_warn(ar, "unable to read RX_LOOKAHEAD_VALID: %d\n", ret);
+ ath10k_warn(ar, "unable to read rx_lookahd: %d\n", ret);
return ret;
}
@@ -2018,6 +2046,12 @@ static int ath10k_sdio_probe(struct sdio_func *func,
goto err_core_destroy;
}
+ ar_sdio->vsg_buffer = devm_kmalloc(ar->dev, ATH10K_SDIO_VSG_BUF_SIZE, GFP_KERNEL);
+ if (!ar_sdio->vsg_buffer) {
+ ret = -ENOMEM;
+ goto err_core_destroy;
+ }
+
ar_sdio->irq_data.irq_en_reg =
devm_kzalloc(ar->dev, sizeof(struct ath10k_sdio_irq_enable_regs),
GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index b8c7ac0..4896eca 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -138,8 +138,8 @@ struct ath10k_sdio_irq_proc_regs {
u8 rx_lookahead_valid;
u8 host_int_status2;
u8 gmbox_rx_avail;
- __le32 rx_lookahead[2];
- __le32 rx_gmbox_lookahead_alias[2];
+ __le32 rx_lookahead[2 * ATH10K_HIF_MBOX_NUM_MAX];
+ __le32 int_status_enable;
};
struct ath10k_sdio_irq_enable_regs {
@@ -196,6 +196,9 @@ struct ath10k_sdio {
struct ath10k *ar;
struct ath10k_sdio_irq_data irq_data;
+ /* temporary buffer for sdio read */
+ u8 *vsg_buffer;
+
/* temporary buffer for BMI requests */
u8 *bmi_buf;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 3/8] ath10k: change max RX bundle size from 8 to 32 for sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
The max bundle size support by firmware is 32, change it from 8 to 32
will help performance. This results in significant performance
improvement on RX path.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: change macro HTC_GET_BUNDLE_COUNT
v3: change some code style
v4: add macro ATH10K_HTC_FLAG_BUNDLE_MASK
v5: no change
drivers/net/wireless/ath/ath10k/htc.h | 12 +++++++++---
drivers/net/wireless/ath/ath10k/sdio.c | 6 +++---
drivers/net/wireless/ath/ath10k/sdio.h | 4 ++--
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index f55d3ca..7055156 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -39,7 +39,7 @@
* 4-byte aligned.
*/
-#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 8
+#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
enum ath10k_htc_tx_flags {
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
@@ -48,10 +48,16 @@ enum ath10k_htc_tx_flags {
enum ath10k_htc_rx_flags {
ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK = 0x01,
- ATH10K_HTC_FLAG_TRAILER_PRESENT = 0x02,
- ATH10K_HTC_FLAG_BUNDLE_MASK = 0xF0
+ ATH10K_HTC_FLAG_TRAILER_PRESENT = 0x02
};
+#define ATH10K_HTC_FLAG_BUNDLE_MASK 0xF0
+#define ATH10K_HTC_BUNDLE_EXTRA_MASK GENMASK(3, 2)
+
+#define ATH10K_HTC_GET_BUNDLE_COUNT(flags) \
+ (FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, (flags)) + \
+ (FIELD_GET(ATH10K_HTC_BUNDLE_EXTRA_MASK, (flags)) << 4))
+
struct ath10k_htc_hdr {
u8 eid; /* @enum ath10k_htc_ep_id */
u8 flags; /* @enum ath10k_htc_tx_flags, ath10k_htc_rx_flags */
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index d7ffcd5..714b0b1 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -24,8 +24,8 @@
#include "trace.h"
#include "sdio.h"
-#define ATH10K_SDIO_DMA_BUF_SIZE (32 * 1024)
-#define ATH10K_SDIO_VSG_BUF_SIZE (32 * 1024)
+#define ATH10K_SDIO_DMA_BUF_SIZE (64 * 1024)
+#define ATH10K_SDIO_VSG_BUF_SIZE (64 * 1024)
/* inlined helper functions */
@@ -495,7 +495,7 @@ static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
{
int ret, i;
- *bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags);
+ *bndl_cnt = ATH10K_HTC_GET_BUNDLE_COUNT(htc_hdr->flags);
if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_RX_BUNDLE) {
ath10k_warn(ar,
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index 4896eca..3ca76c7 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -89,10 +89,10 @@
* to the maximum value (HTC_HOST_MAX_MSG_PER_RX_BUNDLE).
*
* in this case the driver must allocate
- * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE) skb's.
+ * (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2) skb's.
*/
#define ATH10K_SDIO_MAX_RX_MSGS \
- (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * HTC_HOST_MAX_MSG_PER_RX_BUNDLE)
+ (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2)
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
--
1.9.1
^ permalink raw reply related
* [PATCH v5 4/8] ath10k: add workqueue for RX path of sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
The thread of read rx message by sdio bus from firmware is
synchronous, it will cost much time for process the left part
of rx message which includes indicate the rx packet to uppper
net stack. It will reduce the time of read from sdio.
This patch move the indication to a workqueue, it results in
significant performance improvement on RX path.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: no change
v3: change some code style
v4: no change
v5: no change
drivers/net/wireless/ath/ath10k/sdio.c | 116 ++++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/sdio.h | 20 ++++++
2 files changed, 133 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 714b0b1..3b808a3 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -412,6 +412,66 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar,
return 0;
}
+static struct ath10k_sdio_rx_request *ath10k_sdio_alloc_rx_req(struct ath10k *ar)
+{
+ struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_request *rx_req;
+
+ spin_lock_bh(&ar_sdio->rx_lock);
+
+ if (list_empty(&ar_sdio->rx_req_freeq)) {
+ rx_req = NULL;
+ ath10k_dbg(ar, ATH10K_DBG_SDIO, "rx_req alloc fail\n");
+ goto out;
+ }
+
+ rx_req = list_first_entry(&ar_sdio->rx_req_freeq,
+ struct ath10k_sdio_rx_request, list);
+ list_del(&rx_req->list);
+
+out:
+ spin_unlock_bh(&ar_sdio->rx_lock);
+ return rx_req;
+}
+
+static void ath10k_sdio_free_rx_req(struct ath10k *ar,
+ struct ath10k_sdio_rx_request *rx_req)
+{
+ struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+
+ memset(rx_req, 0, sizeof(*rx_req));
+
+ spin_lock_bh(&ar_sdio->rx_lock);
+ list_add_tail(&rx_req->list, &ar_sdio->rx_req_freeq);
+ spin_unlock_bh(&ar_sdio->rx_lock);
+}
+
+static int ath10k_sdio_prep_async_rx_req(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_htc_ep *ep)
+{
+ struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_request *rx_req;
+
+ /* Allocate a rx request for the message and queue it on the
+ * SDIO rx workqueue.
+ */
+ rx_req = ath10k_sdio_alloc_rx_req(ar);
+ if (!rx_req) {
+ ath10k_warn(ar, "unable to allocate rx request for async request\n");
+ return -ENOMEM;
+ }
+
+ rx_req->skb = skb;
+ rx_req->ep = ep;
+
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+ list_add_tail(&rx_req->list, &ar_sdio->wr_asyncq_rx);
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+
+ return 0;
+}
+
static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
u32 lookaheads[],
int *n_lookahead)
@@ -465,10 +525,16 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar,
if (ret)
goto out;
- if (!pkt->trailer_only)
- ep->ep_ops.ep_rx_complete(ar_sdio->ar, pkt->skb);
- else
+ if (!pkt->trailer_only) {
+ ret = ath10k_sdio_prep_async_rx_req(ar, pkt->skb, ep);
+ if (ret)
+ kfree_skb(pkt->skb);
+ else
+ queue_work(ar->workqueue_aux,
+ &ar_sdio->wr_async_work_rx);
+ } else {
kfree_skb(pkt->skb);
+ }
/* The RX complete handler now owns the skb...*/
pkt->skb = NULL;
@@ -1319,6 +1385,26 @@ static void __ath10k_sdio_write_async(struct ath10k *ar,
ath10k_sdio_free_bus_req(ar, req);
}
+static void ath10k_rx_indication_async_work(struct work_struct *work)
+{
+ struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
+ wr_async_work_rx);
+ struct ath10k *ar = ar_sdio->ar;
+ struct ath10k_sdio_rx_request *req, *tmp_req;
+
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+
+ list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq_rx, list) {
+ list_del(&req->list);
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+ req->ep->ep_ops.ep_rx_complete(ar, req->skb);
+ ath10k_sdio_free_rx_req(ar, req);
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+ }
+
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+}
+
static void ath10k_sdio_write_async_work(struct work_struct *work)
{
struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio,
@@ -1807,10 +1893,24 @@ static void ath10k_sdio_irq_disable(struct ath10k *ar)
static void ath10k_sdio_hif_stop(struct ath10k *ar)
{
struct ath10k_sdio_bus_request *req, *tmp_req;
+ struct ath10k_sdio_rx_request *rx_req, *tmp_rx_req;
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
ath10k_sdio_irq_disable(ar);
+ cancel_work_sync(&ar_sdio->wr_async_work_rx);
+
+ spin_lock_bh(&ar_sdio->wr_async_lock_rx);
+
+ /* Free all RX requests that have not been handled */
+ list_for_each_entry_safe(rx_req, tmp_rx_req, &ar_sdio->wr_asyncq_rx, list) {
+ list_del(&rx_req->list);
+ rx_req->ep->ep_ops.ep_rx_complete(ar, rx_req->skb);
+ ath10k_sdio_free_rx_req(ar, rx_req);
+ }
+
+ spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
+
cancel_work_sync(&ar_sdio->wr_async_work);
spin_lock_bh(&ar_sdio->wr_async_lock);
@@ -2089,6 +2189,16 @@ static int ath10k_sdio_probe(struct sdio_func *func,
for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++)
ath10k_sdio_free_bus_req(ar, &ar_sdio->bus_req[i]);
+ spin_lock_init(&ar_sdio->rx_lock);
+ spin_lock_init(&ar_sdio->wr_async_lock_rx);
+ INIT_LIST_HEAD(&ar_sdio->rx_req_freeq);
+ INIT_LIST_HEAD(&ar_sdio->wr_asyncq_rx);
+
+ INIT_WORK(&ar_sdio->wr_async_work_rx, ath10k_rx_indication_async_work);
+
+ for (i = 0; i < ARRAY_SIZE(ar_sdio->rx_req); i++)
+ ath10k_sdio_free_rx_req(ar, &ar_sdio->rx_req[i]);
+
dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, id->device);
switch (dev_id_base) {
case QCA_MANUFACTURER_ID_AR6005_BASE:
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index 3ca76c7..9bb438e 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -38,6 +38,7 @@
#define ATH10K_HIF_MBOX_NUM_MAX 4
#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM 64
+#define ATH10K_SDIO_RX_REQUEST_MAX_NUM 1024
#define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ)
@@ -98,6 +99,12 @@
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000
+struct ath10k_sdio_rx_request {
+ struct list_head list;
+ struct sk_buff *skb;
+ struct ath10k_htc_ep *ep;
+};
+
struct ath10k_sdio_bus_request {
struct list_head list;
@@ -187,9 +194,17 @@ struct ath10k_sdio {
struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM];
/* free list of bus requests */
struct list_head bus_req_freeq;
+
/* protects access to bus_req_freeq */
spinlock_t lock;
+ /* available rx requests */
+ struct ath10k_sdio_rx_request rx_req[ATH10K_SDIO_RX_REQUEST_MAX_NUM];
+ /* free list of rx requests */
+ struct list_head rx_req_freeq;
+ /* protects access to rx_req_freeq */
+ spinlock_t rx_lock;
+
struct ath10k_sdio_rx_data rx_pkts[ATH10K_SDIO_MAX_RX_MSGS];
size_t n_rx_pkts;
@@ -209,6 +224,11 @@ struct ath10k_sdio {
struct list_head wr_asyncq;
/* protects access to wr_asyncq */
spinlock_t wr_async_lock;
+
+ struct work_struct wr_async_work_rx;
+ struct list_head wr_asyncq_rx;
+ /* protects access to wr_asyncq_rx */
+ spinlock_t wr_async_lock_rx;
};
static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar)
--
1.9.1
^ permalink raw reply related
* [PATCH v5 5/8] ath10k: disable TX complete indication of htt for sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
Tx complete message from firmware cost bus bandwidth of sdio, and bus
bandwidth is the bollteneck of throughput, it will effect the bandwidth
occupancy of data packet of TX and RX.
This patch disable TX complete indication from firmware for htt data
packet, it results in significant performance improvement on TX path.
The downside of this patch is ath10k will not know the TX status of
the data packet for poor signal situation. Although upper network stack
or application layer have retry mechanism, the retry will be later than
ath10k get the TX fail status if not disable TX complete.
This patch only effect sdio chip, it will not effect PCI, SNOC etc.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: change some code style
v3: change some code style
v4: no change
v5: no change
drivers/net/wireless/ath/ath10k/core.c | 9 ++++++++-
drivers/net/wireless/ath/ath10k/hif.h | 9 +++++++++
drivers/net/wireless/ath/ath10k/htc.c | 10 ++++++++++
drivers/net/wireless/ath/ath10k/htc.h | 3 +++
drivers/net/wireless/ath/ath10k/htt.c | 5 +++++
drivers/net/wireless/ath/ath10k/htt.h | 13 +++++++++++-
drivers/net/wireless/ath/ath10k/htt_rx.c | 34 +++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 31 +++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/hw.h | 2 +-
drivers/net/wireless/ath/ath10k/sdio.c | 23 +++++++++++++++++++++
10 files changed, 135 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index dc45d16..d56dcbd 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -30,6 +30,7 @@
static unsigned int ath10k_cryptmode_param;
static bool uart_print;
+static bool disable_tx_comp = true;
static bool skip_otp;
static bool rawmode;
static bool fw_diag_log;
@@ -41,6 +42,9 @@
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
module_param(uart_print, bool, 0644);
+
+/* If upper layer need the TX complete status, it can enable tx complete */
+module_param(disable_tx_comp, bool, 0644);
module_param(skip_otp, bool, 0644);
module_param(rawmode, bool, 0644);
module_param(fw_diag_log, bool, 0644);
@@ -688,7 +692,10 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
/* Data transfer is not initiated, when reduced Tx completion
* is used for SDIO. disable it until fixed
*/
- param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
+ if (disable_tx_comp)
+ param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
+ else
+ param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
/* Alternate credit size of 1544 as used by SDIO firmware is
* not big enough for mac80211 / native wifi frames. disable it
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 496ee34..0dd8973 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -56,6 +56,8 @@ struct ath10k_hif_ops {
int (*swap_mailbox)(struct ath10k *ar);
+ int (*get_htt_tx_complete)(struct ath10k *ar);
+
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe);
@@ -144,6 +146,13 @@ static inline int ath10k_hif_swap_mailbox(struct ath10k *ar)
return 0;
}
+static inline int ath10k_hif_get_htt_tx_complete(struct ath10k *ar)
+{
+ if (ar->hif.ops->get_htt_tx_complete)
+ return ar->hif.ops->get_htt_tx_complete(ar);
+ return 0;
+}
+
static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 1d4d1a1..4c6cdc2 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -660,6 +660,16 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
return 0;
}
+void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
+ enum ath10k_htc_ep_id eid,
+ bool enable)
+{
+ struct ath10k *ar = htc->ar;
+ struct ath10k_htc_ep *ep = &ar->htc.endpoint[eid];
+
+ ep->tx_credit_flow_enabled = enable;
+}
+
int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
struct ath10k_htc_svc_conn_resp *conn_resp)
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 7055156..d61eb6c0 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -373,6 +373,9 @@ struct ath10k_htc {
int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
struct ath10k_htc_svc_conn_resp *conn_resp);
+void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
+ enum ath10k_htc_ep_id eid,
+ bool enable);
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet);
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 7b75200..4354bf2 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -10,6 +10,7 @@
#include "htt.h"
#include "core.h"
#include "debug.h"
+#include "hif.h"
static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
[HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
@@ -153,6 +154,10 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
htt->eid = conn_resp.eid;
+ htt->disable_tx_comp = ath10k_hif_get_htt_tx_complete(htt->ar);
+ if (htt->disable_tx_comp)
+ ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 30c0800..889bf9f 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -150,9 +150,19 @@ enum htt_data_tx_desc_flags1 {
HTT_DATA_TX_DESC_FLAGS1_MORE_IN_BATCH = 1 << 12,
HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD = 1 << 13,
HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD = 1 << 14,
- HTT_DATA_TX_DESC_FLAGS1_RSVD1 = 1 << 15
+ HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE = 1 << 15
};
+#define HTT_TX_CREDIT_DELTA_ABS_M 0xffff0000
+#define HTT_TX_CREDIT_DELTA_ABS_S 16
+#define HTT_TX_CREDIT_DELTA_ABS_GET(word) \
+ (((word) & HTT_TX_CREDIT_DELTA_ABS_M) >> HTT_TX_CREDIT_DELTA_ABS_S)
+
+#define HTT_TX_CREDIT_SIGN_BIT_M 0x00000100
+#define HTT_TX_CREDIT_SIGN_BIT_S 8
+#define HTT_TX_CREDIT_SIGN_BIT_GET(word) \
+ (((word) & HTT_TX_CREDIT_SIGN_BIT_M) >> HTT_TX_CREDIT_SIGN_BIT_S)
+
enum htt_data_tx_ext_tid {
HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST = 16,
HTT_DATA_TX_EXT_TID_MGMT = 17,
@@ -2019,6 +2029,7 @@ struct ath10k_htt {
bool tx_mem_allocated;
const struct ath10k_htt_tx_ops *tx_ops;
const struct ath10k_htt_rx_ops *rx_ops;
+ bool disable_tx_comp;
};
struct ath10k_htt_tx_ops {
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 83a7fb6..5bf3179 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -3691,6 +3691,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
}
case HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION: {
struct htt_tx_done tx_done = {};
+ struct ath10k_htt *htt = &ar->htt;
+ struct ath10k_htc *htc = &ar->htc;
+ struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
int status = __le32_to_cpu(resp->mgmt_tx_completion.status);
int info = __le32_to_cpu(resp->mgmt_tx_completion.info);
@@ -3716,6 +3719,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
+ if (htt->disable_tx_comp) {
+ spin_lock_bh(&htc->tx_lock);
+ ep->tx_credits++;
+ spin_unlock_bh(&htc->tx_lock);
+ }
+
status = ath10k_txrx_tx_unref(htt, &tx_done);
if (!status) {
spin_lock_bh(&htt->tx_lock);
@@ -3790,8 +3799,31 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
return false;
}
- case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
+ case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: {
+ struct ath10k_htt *htt = &ar->htt;
+ struct ath10k_htc *htc = &ar->htc;
+ struct ath10k_htc_ep *ep = &ar->htc.endpoint[htt->eid];
+ u32 msg_word = __le32_to_cpu(*(__le32 *)resp);
+ int htt_credit_delta;
+
+ htt_credit_delta = HTT_TX_CREDIT_DELTA_ABS_GET(msg_word);
+ if (HTT_TX_CREDIT_SIGN_BIT_GET(msg_word))
+ htt_credit_delta = -htt_credit_delta;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "credit update: delta:%d\n",
+ htt_credit_delta);
+
+ if (htt->disable_tx_comp) {
+ spin_lock_bh(&htc->tx_lock);
+ ep->tx_credits += htt_credit_delta;
+ spin_unlock_bh(&htc->tx_lock);
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "credit total:%d\n",
+ ep->tx_credits);
+ }
break;
+ }
case HTT_T2H_MSG_TYPE_CHAN_CHANGE: {
u32 phymode = __le32_to_cpu(resp->chan_change.phymode);
u32 freq = __le32_to_cpu(resp->chan_change.freq);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 2ef717f1..7eb753a8 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -543,7 +543,35 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
{
+ struct ath10k_htt *htt = &ar->htt;
+ struct htt_tx_done tx_done = {0};
+ struct htt_cmd_hdr *htt_hdr;
+ struct htt_data_tx_desc *desc_hdr;
+ u16 flags1;
+
dev_kfree_skb_any(skb);
+
+ if (!htt->disable_tx_comp)
+ return;
+
+ htt_hdr = (struct htt_cmd_hdr *)skb->data;
+ if (htt_hdr->msg_type != HTT_H2T_MSG_TYPE_TX_FRM)
+ return;
+
+ desc_hdr = (struct htt_data_tx_desc *)
+ (skb->data + sizeof(*htt_hdr));
+ flags1 = __le16_to_cpu(desc_hdr->flags1);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "htt tx complete msdu id:%u ,flags1:%x\n",
+ __le16_to_cpu(desc_hdr->id), flags1);
+
+ if (flags1 & HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE)
+ return;
+
+ tx_done.status = HTT_TX_COMPL_STATE_ACK;
+ tx_done.msdu_id = __le16_to_cpu(desc_hdr->id);
+ ath10k_txrx_tx_unref(&ar->htt, &tx_done);
}
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb)
@@ -1261,6 +1289,9 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+
+ if (htt->disable_tx_comp)
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE;
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 2ae57c1..6349665 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -759,7 +759,7 @@ struct ath10k_hw_ops {
#define TARGET_TLV_NUM_TDLS_VDEVS 1
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
-#define TARGET_TLV_NUM_MSDU_DESC_HL 64
+#define TARGET_TLV_NUM_MSDU_DESC_HL 1024
#define TARGET_TLV_NUM_WOW_PATTERNS 22
#define TARGET_TLV_MGMT_NUM_MSDU_DESC (50)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 3b808a3..e01ab63 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1786,6 +1786,28 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
return 0;
}
+static int ath10k_sdio_get_htt_tx_complete(struct ath10k *ar)
+{
+ u32 addr, val;
+ int ret;
+
+ addr = host_interest_item_address(HI_ITEM(hi_acs_flags));
+
+ ret = ath10k_sdio_hif_diag_read32(ar, addr, &val);
+ if (ret) {
+ ath10k_warn(ar,
+ "unable to read hi_acs_flags for htt tx comple : %d\n", ret);
+ return ret;
+ }
+
+ ret = (val & HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK);
+
+ ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio reduce tx complete fw%sack\n",
+ ret ? " " : " not ");
+
+ return ret;
+}
+
/* HIF start/stop */
static int ath10k_sdio_hif_start(struct ath10k *ar)
@@ -2069,6 +2091,7 @@ static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar,
.start = ath10k_sdio_hif_start,
.stop = ath10k_sdio_hif_stop,
.swap_mailbox = ath10k_sdio_hif_swap_mailbox,
+ .get_htt_tx_complete = ath10k_sdio_get_htt_tx_complete,
.map_service_to_pipe = ath10k_sdio_hif_map_service_to_pipe,
.get_default_pipe = ath10k_sdio_hif_get_default_pipe,
.send_complete_check = ath10k_sdio_hif_send_complete_check,
--
1.9.1
^ permalink raw reply related
* [PATCH v5 7/8] ath10k: enable alt data of TX path for sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
The default credit size is 1792 bytes, but the IP mtu is 1500 bytes,
then it has about 290 bytes's waste for each data packet on sdio
transfer path for TX bundle, it will reduce the transmission utilization
ratio for data packet.
This patch enable the small credit size in firmware, firmware will use
the new credit size 1556 bytes, it will increase the transmission
utilization ratio for data packet on TX patch. It results in significant
performance improvement on TX path.
This patch only effect sdio chip, it will not effect PCI, SNOC etc.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00017-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: no change
v3: change some code style
v4: add macro ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK
v5: no change
drivers/net/wireless/ath/ath10k/core.c | 19 +++++++++++++++++--
drivers/net/wireless/ath/ath10k/htc.c | 12 ++++++++++--
drivers/net/wireless/ath/ath10k/htc.h | 13 +++++++++++--
3 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 9841533..9fd07c7 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -31,6 +31,7 @@
static unsigned int ath10k_cryptmode_param;
static bool uart_print;
static bool disable_tx_comp = true;
+static bool alt_data = true;
static bool skip_otp;
static bool rawmode;
static bool fw_diag_log;
@@ -45,6 +46,15 @@
/* If upper layer need the TX complete status, it can enable tx complete */
module_param(disable_tx_comp, bool, 0644);
+
+/* alt_data is only used for sdio chip, for previous version of firmware, its
+ * alt data size is 1544 which is not enough for native wifi, so it need to
+ * alt_data for the firmware.
+ * If the firmware has changed alt data size to 1556, then it can enable
+ * alt_data for the firmware.
+ * alt_data will not effect PCI, SNOC etc.
+ */
+module_param(alt_data, bool, 0644);
module_param(skip_otp, bool, 0644);
module_param(rawmode, bool, 0644);
module_param(fw_diag_log, bool, 0644);
@@ -698,9 +708,14 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)
param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
/* Alternate credit size of 1544 as used by SDIO firmware is
- * not big enough for mac80211 / native wifi frames. disable it
+ * not big enough for mac80211 / native wifi frames. disable it.
+ * If alternate credit size of 1556 as used by SDIO firmware is
+ * big enough for mac80211 / native wifi frames. enable it
*/
- param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
+ if (alt_data && mode == ATH10K_FIRMWARE_MODE_NORMAL)
+ param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
+ else
+ param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
if (mode == ATH10K_FIRMWARE_MODE_UTF)
param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 3e551e4..3bf5722 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -941,12 +941,16 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
*/
if (htc->control_resp_len >=
sizeof(msg->hdr) + sizeof(msg->ready_ext)) {
+ htc->alt_data_credit_size =
+ __le16_to_cpu(msg->ready_ext.reserved) &
+ ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK;
htc->max_msgs_per_htc_bundle =
min_t(u8, msg->ready_ext.max_msgs_per_htc_bundle,
HTC_HOST_MAX_MSG_PER_RX_BUNDLE);
ath10k_dbg(ar, ATH10K_DBG_HTC,
- "Extended ready message. RX bundle size: %d\n",
- htc->max_msgs_per_htc_bundle);
+ "Extended ready message. RX bundle size: %d, alt size:%d\n",
+ htc->max_msgs_per_htc_bundle,
+ htc->alt_data_credit_size);
}
INIT_WORK(&ar->bundle_tx_work, ath10k_htc_bundle_tx_work);
@@ -1098,6 +1102,10 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
ep->tx_credits = tx_alloc;
ep->tx_credit_size = htc->target_credit_size;
+ if (conn_req->service_id == ATH10K_HTC_SVC_ID_HTT_DATA_MSG &&
+ htc->alt_data_credit_size != 0)
+ ep->tx_credit_size = htc->alt_data_credit_size;
+
/* copy all the callbacks */
ep->ep_ops = conn_req->ep_ops;
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index ec4957a..5c21ec7 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -109,6 +109,8 @@ enum ath10k_htc_conn_flags {
#define ATH10K_HTC_CONN_FLAGS_RECV_ALLOC_LSB 8
};
+#define ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK 0xFFF
+
enum ath10k_htc_conn_svc_status {
ATH10K_HTC_CONN_SVC_STATUS_SUCCESS = 0,
ATH10K_HTC_CONN_SVC_STATUS_NOT_FOUND = 1,
@@ -141,8 +143,14 @@ struct ath10k_htc_ready_extended {
struct ath10k_htc_ready base;
u8 htc_version; /* @enum ath10k_htc_version */
u8 max_msgs_per_htc_bundle;
- u8 pad0;
- u8 pad1;
+ union {
+ __le16 reserved;
+ struct {
+ u8 pad0;
+ u8 pad1;
+ } __packed;
+ } __packed;
+
} __packed;
struct ath10k_htc_conn_svc {
@@ -379,6 +387,7 @@ struct ath10k_htc {
int total_transmit_credits;
int target_credit_size;
u8 max_msgs_per_htc_bundle;
+ int alt_data_credit_size;
};
int ath10k_htc_init(struct ath10k *ar);
--
1.9.1
^ permalink raw reply related
* [PATCH v5 6/8] ath10k: add htt TX bundle for sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
The transmission utilization ratio for sdio bus for small packet is
slow, because the space and time cost for sdio bus is same for large
length packet and small length packet. So the speed of data for large
length packet is higher than small length.
Test result of different length of data:
data packet(byte) cost time(us) calculated rate(Mbps)
256 28 73
512 33 124
1024 35 234
1792 45 318
14336 168 682
28672 333 688
57344 660 695
This patch change the TX packet from single packet to a large length
bundle packet, max size is 32, it results in significant performance
improvement on TX path.
This patch only effect sdio chip, it will not effect PCI, SNOC etc.
It only enable bundle for sdio chip.
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: no change
v3: change some code style
v4: no change
v5: change ath10k_htc_setup_tx_req to add check bundle_tx
to forbidden init 2 times
drivers/net/wireless/ath/ath10k/core.c | 14 +-
drivers/net/wireless/ath/ath10k/core.h | 4 +-
drivers/net/wireless/ath/ath10k/htc.c | 356 ++++++++++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/htc.h | 21 +-
drivers/net/wireless/ath/ath10k/htt.c | 8 +
drivers/net/wireless/ath/ath10k/htt.h | 4 +
drivers/net/wireless/ath/ath10k/htt_rx.c | 1 +
drivers/net/wireless/ath/ath10k/htt_tx.c | 7 +-
8 files changed, 378 insertions(+), 37 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index d56dcbd..9841533 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3195,6 +3195,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
if (!ar->workqueue_aux)
goto err_free_wq;
+ ar->workqueue_tx_complete =
+ create_singlethread_workqueue("ath10k_tx_complete_wq");
+ if (!ar->workqueue_tx_complete)
+ goto err_free_aux_wq;
+
mutex_init(&ar->conf_mutex);
mutex_init(&ar->dump_mutex);
spin_lock_init(&ar->data_lock);
@@ -3220,7 +3225,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ret = ath10k_coredump_create(ar);
if (ret)
- goto err_free_aux_wq;
+ goto err_free_tx_complete;
ret = ath10k_debug_create(ar);
if (ret)
@@ -3230,12 +3235,12 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
err_free_coredump:
ath10k_coredump_destroy(ar);
-
+err_free_tx_complete:
+ destroy_workqueue(ar->workqueue_tx_complete);
err_free_aux_wq:
destroy_workqueue(ar->workqueue_aux);
err_free_wq:
destroy_workqueue(ar->workqueue);
-
err_free_mac:
ath10k_mac_destroy(ar);
@@ -3251,6 +3256,9 @@ void ath10k_core_destroy(struct ath10k *ar)
flush_workqueue(ar->workqueue_aux);
destroy_workqueue(ar->workqueue_aux);
+ flush_workqueue(ar->workqueue_tx_complete);
+ destroy_workqueue(ar->workqueue_tx_complete);
+
ath10k_debug_destroy(ar);
ath10k_coredump_destroy(ar);
ath10k_htt_tx_destroy(&ar->htt);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4d7db07..be9eb37 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1079,7 +1079,7 @@ struct ath10k {
struct workqueue_struct *workqueue;
/* Auxiliary workqueue */
struct workqueue_struct *workqueue_aux;
-
+ struct workqueue_struct *workqueue_tx_complete;
/* prevents concurrent FW reconfiguration */
struct mutex conf_mutex;
@@ -1120,6 +1120,8 @@ struct ath10k {
struct work_struct register_work;
struct work_struct restart_work;
+ struct work_struct bundle_tx_work;
+ struct work_struct tx_complete_work;
/* cycle count is reported twice for each visited channel during scan.
* access protected by data_lock
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 4c6cdc2..3e551e4 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -51,10 +51,12 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
struct sk_buff *skb)
{
struct ath10k *ar = ep->htc->ar;
+ struct ath10k_htc_hdr *hdr;
ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %pK\n", __func__,
ep->eid, skb);
+ hdr = (struct ath10k_htc_hdr *)skb->data;
ath10k_htc_restore_tx_skb(ep->htc, skb);
if (!ep->ep_ops.ep_tx_complete) {
@@ -63,6 +65,11 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
return;
}
+ if (hdr->flags & ATH10K_HTC_FLAG_SEND_BUNDLE) {
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
}
EXPORT_SYMBOL(ath10k_htc_notify_tx_completion);
@@ -78,7 +85,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
hdr->flags = 0;
- if (ep->tx_credit_flow_enabled)
+ if (ep->tx_credit_flow_enabled && !ep->bundle_tx)
hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
spin_lock_bh(&ep->htc->tx_lock);
@@ -86,6 +93,64 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
spin_unlock_bh(&ep->htc->tx_lock);
}
+static int ath10k_htc_consume_credit(struct ath10k_htc_ep *ep,
+ unsigned int len,
+ bool consume)
+{
+ int credits;
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ enum ath10k_htc_ep_id eid = ep->eid;
+ int ret = 0;
+
+ if (!ep->tx_credit_flow_enabled)
+ return 0;
+
+ credits = DIV_ROUND_UP(len, ep->tx_credit_size);
+ spin_lock_bh(&htc->tx_lock);
+
+ if (ep->tx_credits < credits) {
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "htc insufficient credits ep %d required %d available %d consume %d\n",
+ eid, credits, ep->tx_credits, consume);
+ ret = -EAGAIN;
+ goto unlock;
+ }
+
+ if (consume) {
+ ep->tx_credits -= credits;
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "htc ep %d consumed %d credits (total %d)\n",
+ eid, credits, ep->tx_credits);
+ }
+
+unlock:
+ spin_unlock_bh(&htc->tx_lock);
+ return ret;
+}
+
+static void ath10k_htc_release_credit(struct ath10k_htc_ep *ep, unsigned int len)
+{
+ int credits;
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ enum ath10k_htc_ep_id eid = ep->eid;
+
+ if (!ep->tx_credit_flow_enabled)
+ return;
+
+ credits = DIV_ROUND_UP(len, ep->tx_credit_size);
+ spin_lock_bh(&htc->tx_lock);
+ ep->tx_credits += credits;
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "htc ep %d reverted %d credits back (total %d)\n",
+ eid, credits, ep->tx_credits);
+ spin_unlock_bh(&htc->tx_lock);
+
+ if (ep->ep_ops.ep_tx_credits)
+ ep->ep_ops.ep_tx_credits(htc->ar);
+}
+
int ath10k_htc_send(struct ath10k_htc *htc,
enum ath10k_htc_ep_id eid,
struct sk_buff *skb)
@@ -95,8 +160,8 @@ int ath10k_htc_send(struct ath10k_htc *htc,
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ath10k_hif_sg_item sg_item;
struct device *dev = htc->ar->dev;
- int credits = 0;
int ret;
+ unsigned int skb_len;
if (htc->ar->state == ATH10K_STATE_WEDGED)
return -ECOMM;
@@ -108,23 +173,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,
skb_push(skb, sizeof(struct ath10k_htc_hdr));
- if (ep->tx_credit_flow_enabled) {
- credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
- spin_lock_bh(&htc->tx_lock);
- if (ep->tx_credits < credits) {
- ath10k_dbg(ar, ATH10K_DBG_HTC,
- "htc insufficient credits ep %d required %d available %d\n",
- eid, credits, ep->tx_credits);
- spin_unlock_bh(&htc->tx_lock);
- ret = -EAGAIN;
- goto err_pull;
- }
- ep->tx_credits -= credits;
- ath10k_dbg(ar, ATH10K_DBG_HTC,
- "htc ep %d consumed %d credits (total %d)\n",
- eid, credits, ep->tx_credits);
- spin_unlock_bh(&htc->tx_lock);
- }
+ skb_len = skb->len;
+ ret = ath10k_htc_consume_credit(ep, skb_len, true);
+ if (ret)
+ goto err_pull;
ath10k_htc_prepare_tx_skb(ep, skb);
@@ -155,17 +207,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
err_credits:
- if (ep->tx_credit_flow_enabled) {
- spin_lock_bh(&htc->tx_lock);
- ep->tx_credits += credits;
- ath10k_dbg(ar, ATH10K_DBG_HTC,
- "htc ep %d reverted %d credits back (total %d)\n",
- eid, credits, ep->tx_credits);
- spin_unlock_bh(&htc->tx_lock);
-
- if (ep->ep_ops.ep_tx_credits)
- ep->ep_ops.ep_tx_credits(htc->ar);
- }
+ ath10k_htc_release_credit(ep, skb_len);
err_pull:
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
return ret;
@@ -581,6 +623,256 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
return allocation;
}
+static int ath10k_htc_send_bundle(struct ath10k_htc_ep *ep,
+ struct sk_buff *bundle_skb,
+ struct sk_buff_head *tx_save_head)
+{
+ struct ath10k_hif_sg_item sg_item;
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ struct sk_buff *skb;
+ int ret;
+ int cn = 0;
+ unsigned int skb_len;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle skb: len:%d\n", bundle_skb->len);
+ skb_len = bundle_skb->len;
+ ret = ath10k_htc_consume_credit(ep, skb_len, true);
+
+ if (!ret) {
+ sg_item.transfer_id = ep->eid;
+ sg_item.transfer_context = bundle_skb;
+ sg_item.vaddr = bundle_skb->data;
+ sg_item.len = bundle_skb->len;
+
+ ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1);
+ if (ret)
+ ath10k_htc_release_credit(ep, skb_len);
+ }
+
+ if (ret)
+ dev_kfree_skb_any(bundle_skb);
+
+ for (cn = 0; (skb = skb_dequeue_tail(tx_save_head)); cn++) {
+ if (ret) {
+ skb_pull(skb, sizeof(struct ath10k_htc_hdr));
+ skb_queue_head(&ep->tx_req_head, skb);
+ } else {
+ skb_queue_tail(&ep->tx_complete_head, skb);
+ }
+ }
+
+ if (!ret)
+ queue_work(ar->workqueue_tx_complete, &ar->tx_complete_work);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
+ "bundle tx status:%d, eid:%d, req count:%d, count:%d, len:%d\n",
+ ret, ep->eid, skb_queue_len(&ep->tx_req_head), cn, bundle_skb->len);
+ return ret;
+}
+
+static void ath10k_htc_send_one_skb(struct ath10k_htc_ep *ep, struct sk_buff *skb)
+{
+ struct ath10k_htc *htc = ep->htc;
+ struct ath10k *ar = htc->ar;
+ int ret;
+
+ ret = ath10k_htc_send(htc, ep->eid, skb);
+
+ if (ret)
+ skb_queue_head(&ep->tx_req_head, skb);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "tx one status:%d, eid:%d, len:%d, pending count:%d\n",
+ ret, ep->eid, skb->len, skb_queue_len(&ep->tx_req_head));
+}
+
+static int ath10k_htc_send_bundle_skbs(struct ath10k_htc_ep *ep)
+{
+ int ret = 0;
+ struct ath10k_htc *htc = ep->htc;
+ struct sk_buff *bundle_skb, *skb;
+ struct sk_buff_head tx_save_head;
+ struct ath10k_htc_hdr *hdr;
+ u8 *bundle_buf;
+ int credit_pad, credit_remainder, trans_len, bundles_left = 0;
+
+ if (htc->ar->state == ATH10K_STATE_WEDGED)
+ return -ECOMM;
+
+ if (ep->tx_credit_flow_enabled &&
+ ep->tx_credits < HTC_HOST_MIN_CREDIT_PER_TX_BUNDLE)
+ return 0;
+
+ bundles_left = HTC_HOST_MAX_MSG_PER_TX_BUNDLE * ep->tx_credit_size;
+ bundle_skb = dev_alloc_skb(bundles_left);
+
+ if (!bundle_skb)
+ return -ENOMEM;
+
+ bundle_buf = bundle_skb->data;
+ skb_queue_head_init(&tx_save_head);
+
+ while (true) {
+ skb = skb_dequeue(&ep->tx_req_head);
+ if (!skb)
+ break;
+
+ credit_pad = 0;
+ trans_len = skb->len + sizeof(*hdr);
+ credit_remainder = trans_len % ep->tx_credit_size;
+
+ if (credit_remainder != 0) {
+ credit_pad = ep->tx_credit_size - credit_remainder;
+ trans_len += credit_pad;
+ }
+
+ ret = ath10k_htc_consume_credit(ep,
+ bundle_buf + trans_len - bundle_skb->data,
+ false);
+ if (ret) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ break;
+ }
+
+ if (bundles_left < trans_len) {
+ bundle_skb->len = bundle_buf - bundle_skb->data;
+ ret = ath10k_htc_send_bundle(ep, bundle_skb, &tx_save_head);
+
+ if (ret) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ return ret;
+ }
+
+ if (skb_queue_len(&ep->tx_req_head) == 0) {
+ ath10k_htc_send_one_skb(ep, skb);
+ return ret;
+ }
+
+ if (ep->tx_credit_flow_enabled &&
+ ep->tx_credits < HTC_HOST_MIN_CREDIT_PER_TX_BUNDLE) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ return 0;
+ }
+
+ bundles_left =
+ HTC_HOST_MAX_MSG_PER_TX_BUNDLE * ep->tx_credit_size;
+ bundle_skb = dev_alloc_skb(bundles_left);
+
+ if (!bundle_skb) {
+ skb_queue_head(&ep->tx_req_head, skb);
+ return -ENOMEM;
+ }
+ bundle_buf = bundle_skb->data;
+ skb_queue_head_init(&tx_save_head);
+ }
+
+ skb_push(skb, sizeof(struct ath10k_htc_hdr));
+ ath10k_htc_prepare_tx_skb(ep, skb);
+
+ memcpy(bundle_buf, skb->data, skb->len);
+ hdr = (struct ath10k_htc_hdr *)bundle_buf;
+ hdr->flags |= ATH10K_HTC_FLAG_SEND_BUNDLE;
+ hdr->pad_len = __cpu_to_le16(credit_pad);
+ bundle_buf += trans_len;
+ bundles_left -= trans_len;
+ skb_queue_tail(&tx_save_head, skb);
+ }
+
+ if (bundle_buf != bundle_skb->data) {
+ bundle_skb->len = bundle_buf - bundle_skb->data;
+ ret = ath10k_htc_send_bundle(ep, bundle_skb, &tx_save_head);
+ } else {
+ dev_kfree_skb_any(bundle_skb);
+ }
+
+ return ret;
+}
+
+static void ath10k_htc_bundle_tx_work(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k, bundle_tx_work);
+ int i;
+ struct ath10k_htc_ep *ep;
+ enum ath10k_htc_ep_id eid;
+ struct sk_buff *skb;
+
+ for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
+ ep = &ar->htc.endpoint[i];
+ eid = ep->eid;
+
+ if (!ep->bundle_tx)
+ continue;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle tx work, eid:%d, count:%d\n",
+ ep->eid, skb_queue_len(&ep->tx_req_head));
+
+ if (skb_queue_len(&ep->tx_req_head) >=
+ HTC_HOST_MIN_MSG_PER_TX_BUNDLE) {
+ ath10k_htc_send_bundle_skbs(ep);
+ } else {
+ skb = skb_dequeue(&ep->tx_req_head);
+
+ if (!skb)
+ continue;
+ ath10k_htc_send_one_skb(ep, skb);
+ }
+ }
+}
+
+static void ath10k_htc_tx_complete_work(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k, tx_complete_work);
+ int i;
+ struct ath10k_htc_ep *ep;
+ enum ath10k_htc_ep_id eid;
+ struct sk_buff *skb;
+
+ for (i = 0; i < ARRAY_SIZE(ar->htc.endpoint); i++) {
+ ep = &ar->htc.endpoint[i];
+ eid = ep->eid;
+ if (ep->bundle_tx && eid == ar->htt.eid) {
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "bundle tx complete, eid:%d, pending complete count:%d\n",
+ ep->eid, skb_queue_len(&ep->tx_complete_head));
+
+ while (true) {
+ skb = skb_dequeue(&ep->tx_complete_head);
+ if (!skb)
+ break;
+ ath10k_htc_notify_tx_completion(ep, skb);
+ }
+ }
+ }
+}
+
+int ath10k_htc_send_hl(struct ath10k_htc *htc,
+ enum ath10k_htc_ep_id eid,
+ struct sk_buff *skb)
+{
+ struct ath10k_htc_ep *ep = &htc->endpoint[eid];
+ struct ath10k *ar = htc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc send hl: eid:%d, bundle:%d, tx count:%d, len:%d\n",
+ eid, ep->bundle_tx, skb_queue_len(&ep->tx_req_head), skb->len);
+
+ if (ep->bundle_tx) {
+ skb_queue_tail(&ep->tx_req_head, skb);
+ queue_work(ar->workqueue, &ar->bundle_tx_work);
+ return 0;
+ } else {
+ return ath10k_htc_send(htc, eid, skb);
+ }
+}
+
+void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep)
+{
+ if (ep->htc->max_msgs_per_htc_bundle >= HTC_HOST_MIN_MSG_PER_TX_BUNDLE &&
+ !ep->bundle_tx) {
+ ep->bundle_tx = true;
+ skb_queue_head_init(&ep->tx_req_head);
+ skb_queue_head_init(&ep->tx_complete_head);
+ }
+}
+
int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
struct ath10k *ar = htc->ar;
@@ -657,6 +949,9 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
htc->max_msgs_per_htc_bundle);
}
+ INIT_WORK(&ar->bundle_tx_work, ath10k_htc_bundle_tx_work);
+ INIT_WORK(&ar->tx_complete_work, ath10k_htc_tx_complete_work);
+
return 0;
}
@@ -801,6 +1096,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
ep->max_tx_queue_depth = conn_req->max_send_queue_depth;
ep->max_ep_message_len = __le16_to_cpu(resp_msg->max_msg_size);
ep->tx_credits = tx_alloc;
+ ep->tx_credit_size = htc->target_credit_size;
/* copy all the callbacks */
ep->ep_ops = conn_req->ep_ops;
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index d61eb6c0..ec4957a 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -40,6 +40,9 @@
*/
#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
+#define HTC_HOST_MAX_MSG_PER_TX_BUNDLE 32
+#define HTC_HOST_MIN_MSG_PER_TX_BUNDLE 2
+#define HTC_HOST_MIN_CREDIT_PER_TX_BUNDLE 2
enum ath10k_htc_tx_flags {
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
@@ -70,8 +73,14 @@ struct ath10k_htc_hdr {
u8 seq_no; /* for tx */
u8 control_byte1;
} __packed;
- u8 pad0;
- u8 pad1;
+ union {
+ __le16 pad_len;
+ struct {
+ u8 pad0;
+ u8 pad1;
+ } __packed;
+ } __packed;
+
} __packed __aligned(4);
enum ath10k_ath10k_htc_msg_id {
@@ -340,7 +349,12 @@ struct ath10k_htc_ep {
u8 seq_no; /* for debugging */
int tx_credits;
+ int tx_credit_size;
bool tx_credit_flow_enabled;
+ bool bundle_tx;
+ struct sk_buff_head tx_req_head;
+ struct sk_buff_head tx_complete_head;
+
};
struct ath10k_htc_svc_tx_credits {
@@ -369,6 +383,7 @@ struct ath10k_htc {
int ath10k_htc_init(struct ath10k *ar);
int ath10k_htc_wait_target(struct ath10k_htc *htc);
+void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep);
int ath10k_htc_start(struct ath10k_htc *htc);
int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
@@ -378,6 +393,8 @@ void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
bool enable);
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet);
+int ath10k_htc_send_hl(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
+ struct sk_buff *packet);
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 4354bf2..127b4e4 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -135,6 +135,8 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
{
struct ath10k_htc_svc_conn_req conn_req;
struct ath10k_htc_svc_conn_resp conn_resp;
+ struct ath10k *ar = htt->ar;
+ struct ath10k_htc_ep *ep;
int status;
memset(&conn_req, 0, sizeof(conn_req));
@@ -142,6 +144,7 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
conn_req.ep_ops.ep_tx_complete = ath10k_htt_htc_tx_complete;
conn_req.ep_ops.ep_rx_complete = ath10k_htt_htc_t2h_msg_handler;
+ conn_req.ep_ops.ep_tx_credits = ath10k_htt_op_ep_tx_credits;
/* connect to control service */
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
@@ -154,6 +157,11 @@ int ath10k_htt_connect(struct ath10k_htt *htt)
htt->eid = conn_resp.eid;
+ if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
+ ep = &ar->htc.endpoint[htt->eid];
+ ath10k_htc_setup_tx_req(ep);
+ }
+
htt->disable_tx_comp = ath10k_hif_get_htt_tx_complete(htt->ar);
if (htt->disable_tx_comp)
ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 889bf9f..4851a2e 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -2030,6 +2030,9 @@ struct ath10k_htt {
const struct ath10k_htt_tx_ops *tx_ops;
const struct ath10k_htt_rx_ops *rx_ops;
bool disable_tx_comp;
+ bool bundle_tx;
+ struct sk_buff_head tx_req_head;
+ struct sk_buff_head tx_complete_head;
};
struct ath10k_htt_tx_ops {
@@ -2276,6 +2279,7 @@ int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
__le16 fetch_seq_num,
struct htt_tx_fetch_record *records,
size_t num_records);
+void ath10k_htt_op_ep_tx_credits(struct ath10k *ar);
void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw,
struct ieee80211_txq *txq);
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 5bf3179..09825b1 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -3821,6 +3821,7 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_HTT,
"credit total:%d\n",
ep->tx_credits);
+ ep->ep_ops.ep_tx_credits(htc->ar);
}
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 7eb753a8..e619b33 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -541,6 +541,11 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
ath10k_htt_tx_destroy(htt);
}
+void ath10k_htt_op_ep_tx_credits(struct ath10k *ar)
+{
+ queue_work(ar->workqueue, &ar->bundle_tx_work);
+}
+
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -1357,7 +1362,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
*/
tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID);
- res = ath10k_htc_send(&htt->ar->htc, htt->eid, msdu);
+ res = ath10k_htc_send_hl(&htt->ar->htc, htt->eid, msdu);
out:
return res;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 8/8] ath10k: enable napi on RX path for sdio
From: Wen Gong @ 2019-09-05 10:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless
In-Reply-To: <1567679893-14029-1-git-send-email-wgong@codeaurora.org>
For tcp RX, the quantity of tcp acks to remote is 1/2 of the quantity
of tcp data from remote, then it will have many small length packets
on TX path of sdio bus, then it reduce the RX packets's bandwidth of
tcp.
This patch enable napi on RX path, then the RX packet of tcp will not
feed to tcp stack immeditely from mac80211 since GRO is enabled by
default, it will feed to tcp stack after napi complete, if rx bundle
is enabled, then it will feed to tcp stack one time for each bundle
of RX. For example, RX bundle size is 32, then tcp stack will receive
one large length packet, its length is neary 1500*32, then tcp stack
will send a tcp ack for this large packet, this will reduce the tcp
acks ratio from 1/2 to 1/32. This results in significant performance
improvement for tcp RX.
Tcp rx throughout is 240Mbps without this patch, and it arrive 390Mbps
with this patch. The cpu usage has no obvious difference with and
without NAPI.
call stack for each RX packet on GRO path:
(skb length is about 1500 bytes)
skb_gro_receive ([kernel.kallsyms])
tcp4_gro_receive ([kernel.kallsyms])
inet_gro_receive ([kernel.kallsyms])
dev_gro_receive ([kernel.kallsyms])
napi_gro_receive ([kernel.kallsyms])
ieee80211_deliver_skb ([mac80211])
ieee80211_rx_handlers ([mac80211])
ieee80211_prepare_and_rx_handle ([mac80211])
ieee80211_rx_napi ([mac80211])
ath10k_htt_rx_proc_rx_ind_hl ([ath10k_core])
ath10k_htt_rx_pktlog_completion_handler ([ath10k_core])
ath10k_sdio_napi_poll ([ath10k_sdio])
net_rx_action ([kernel.kallsyms])
softirqentry_text_start ([kernel.kallsyms])
do_softirq ([kernel.kallsyms])
call stack for napi complete and send tcp ack from tcp stack:
(skb length is about 1500*32 bytes)
_tcp_ack_snd_check ([kernel.kallsyms])
tcp_v4_do_rcv ([kernel.kallsyms])
tcp_v4_rcv ([kernel.kallsyms])
local_deliver_finish ([kernel.kallsyms])
ip_local_deliver ([kernel.kallsyms])
ip_rcv_finish ([kernel.kallsyms])
ip_rcv ([kernel.kallsyms])
netif_receive_skb_core ([kernel.kallsyms])
netif_receive_skb_one_core([kernel.kallsyms])
netif_receive_skb ([kernel.kallsyms])
netif_receive_skb_internal ([kernel.kallsyms])
napi_gro_complete ([kernel.kallsyms])
napi_gro_flush ([kernel.kallsyms])
napi_complete_done ([kernel.kallsyms])
ath10k_sdio_napi_poll ([ath10k_sdio])
net_rx_action ([kernel.kallsyms])
__softirqentry_text_start ([kernel.kallsyms])
do_softirq ([kernel.kallsyms])
Tested with QCA6174 SDIO with firmware
WLAN.RMH.4.4.1-00007-QCARMSWP-1.
Signed-off-by: Wen Gong <wgong@codeaurora.org>
---
v2: no change
v3: change some code style
v4: change some code style
v5: move skb_queue_head_init(&ar->htt.rx_indication_head)
from ath10k_htt_connect to ath10k_core_create to forbidden
init 2 times
drivers/net/wireless/ath/ath10k/core.c | 2 ++
drivers/net/wireless/ath/ath10k/htt.h | 3 +++
drivers/net/wireless/ath/ath10k/htt_rx.c | 45 ++++++++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/sdio.c | 33 +++++++++++++++++++++++
4 files changed, 75 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 9fd07c7..aff7812 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3224,6 +3224,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_waitqueue_head(&ar->htt.empty_tx_wq);
init_waitqueue_head(&ar->wmi.tx_credits_wq);
+ skb_queue_head_init(&ar->htt.rx_indication_head);
+
init_completion(&ar->offchan_tx_completed);
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
skb_queue_head_init(&ar->offchan_tx_queue);
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 4851a2e..462a25b 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1879,6 +1879,8 @@ struct ath10k_htt {
struct ath10k *ar;
enum ath10k_htc_ep_id eid;
+ struct sk_buff_head rx_indication_head;
+
u8 target_version_major;
u8 target_version_minor;
struct completion target_version_received;
@@ -2298,6 +2300,7 @@ int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
struct sk_buff *skb);
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget);
+int ath10k_htt_rx_hl_indication(struct ath10k *ar, int budget);
void ath10k_htt_set_tx_ops(struct ath10k_htt *htt);
void ath10k_htt_set_rx_ops(struct ath10k_htt *htt);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 09825b1..07b6351 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2263,7 +2263,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
rx_status->flag |= RX_FLAG_MMIC_ERROR;
- ieee80211_rx_ni(ar->hw, skb);
+ ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi);
/* We have delivered the skb to the upper layers (mac80211) so we
* must not free it.
@@ -3664,14 +3664,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_IND:
- if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL)
- return ath10k_htt_rx_proc_rx_ind_hl(htt,
- &resp->rx_ind_hl,
- skb,
- HTT_RX_PN_CHECK,
- HTT_RX_NON_TKIP_MIC);
- else
+ if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) {
ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
+ } else {
+ skb_queue_tail(&htt->rx_indication_head, skb);
+ return false;
+ }
break;
case HTT_T2H_MSG_TYPE_PEER_MAP: {
struct htt_peer_map_event ev = {
@@ -3894,6 +3892,37 @@ static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
return quota;
}
+int ath10k_htt_rx_hl_indication(struct ath10k *ar, int budget)
+{
+ struct htt_resp *resp;
+ struct ath10k_htt *htt = &ar->htt;
+ struct sk_buff *skb;
+ bool release;
+ int quota;
+
+ for (quota = 0; quota < budget; quota++) {
+ skb = skb_dequeue(&htt->rx_indication_head);
+ if (!skb)
+ break;
+
+ resp = (struct htt_resp *)skb->data;
+
+ release = ath10k_htt_rx_proc_rx_ind_hl(htt,
+ &resp->rx_ind_hl,
+ skb,
+ HTT_RX_PN_CHECK,
+ HTT_RX_NON_TKIP_MIC);
+
+ if (release)
+ dev_kfree_skb_any(skb);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "rx indication poll pending count:%d\n",
+ skb_queue_len(&htt->rx_indication_head));
+ }
+ return quota;
+}
+EXPORT_SYMBOL(ath10k_htt_rx_hl_indication);
+
int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
{
struct ath10k_htt *htt = &ar->htt;
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index e01ab63..7432d1c 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1402,6 +1402,9 @@ static void ath10k_rx_indication_async_work(struct work_struct *work)
spin_lock_bh(&ar_sdio->wr_async_lock_rx);
}
+ if (test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
+ napi_schedule(&ar->napi);
+
spin_unlock_bh(&ar_sdio->wr_async_lock_rx);
}
@@ -1815,6 +1818,8 @@ static int ath10k_sdio_hif_start(struct ath10k *ar)
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
int ret;
+ napi_enable(&ar->napi);
+
/* Sleep 20 ms before HIF interrupts are disabled.
* This will give target plenty of time to process the BMI done
* request before interrupts are disabled.
@@ -1953,6 +1958,9 @@ static void ath10k_sdio_hif_stop(struct ath10k *ar)
}
spin_unlock_bh(&ar_sdio->wr_async_lock);
+
+ napi_synchronize(&ar->napi);
+ napi_disable(&ar->napi);
}
#ifdef CONFIG_PM
@@ -2129,6 +2137,26 @@ static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend,
#endif /* CONFIG_PM_SLEEP */
+static int ath10k_sdio_napi_poll(struct napi_struct *ctx, int budget)
+{
+ struct ath10k *ar = container_of(ctx, struct ath10k, napi);
+ int done;
+
+ done = ath10k_htt_rx_hl_indication(ar, budget);
+ ath10k_dbg(ar, ATH10K_DBG_SDIO, "napi poll: done: %d, budget:%d\n", done, budget);
+
+ if (done < budget)
+ napi_complete_done(ctx, done);
+
+ return done;
+}
+
+void ath10k_sdio_init_napi(struct ath10k *ar)
+{
+ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll,
+ ATH10K_NAPI_BUDGET);
+}
+
static int ath10k_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -2154,6 +2182,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
return -ENOMEM;
}
+ ath10k_sdio_init_napi(ar);
+
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
func->num, func->vendor, func->device,
@@ -2274,6 +2304,9 @@ static void ath10k_sdio_remove(struct sdio_func *func)
func->num, func->vendor, func->device);
ath10k_core_unregister(ar);
+
+ netif_napi_del(&ar->napi);
+
ath10k_core_destroy(ar);
flush_workqueue(ar_sdio->workqueue);
--
1.9.1
^ permalink raw reply related
* RE: [PATCH v4 1/8] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet
From: Wen Gong @ 2019-09-05 10:46 UTC (permalink / raw)
To: Wen Gong, ath10k@lists.infradead.org; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1567416146-14403-2-git-send-email-wgong@codeaurora.org>
> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Wen Gong
> Sent: Monday, September 2, 2019 5:22 PM
> To: ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: [EXT] [PATCH v4 1/8] ath10k: adjust skb length in
> ath10k_sdio_mbox_rx_packet
>
Patch v5 sent without change, https://patchwork.kernel.org/patch/11132657/
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
^ permalink raw reply
* RE: [PATCH v4 2/8] ath10k: enable RX bundle receive for sdio
From: Wen Gong @ 2019-09-05 10:47 UTC (permalink / raw)
To: Wen Gong, ath10k@lists.infradead.org; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1567416146-14403-3-git-send-email-wgong@codeaurora.org>
> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Wen Gong
> Sent: Monday, September 2, 2019 5:22 PM
> To: ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: [EXT] [PATCH v4 2/8] ath10k: enable RX bundle receive for sdio
>
Patch v5 sent without change, https://patchwork.kernel.org/patch/11132661/
>
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
^ permalink raw reply
* RE: [PATCH v4 3/8] ath10k: change max RX bundle size from 8 to 32 for sdio
From: Wen Gong @ 2019-09-05 10:47 UTC (permalink / raw)
To: Wen Gong, ath10k@lists.infradead.org; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1567416146-14403-4-git-send-email-wgong@codeaurora.org>
> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Wen Gong
> Sent: Monday, September 2, 2019 5:22 PM
> To: ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: [EXT] [PATCH v4 3/8] ath10k: change max RX bundle size from 8 to
> 32 for sdio
>
Patch v5 sent without change, https://patchwork.kernel.org/patch/11132665/
>
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
^ permalink raw reply
* RE: [PATCH v4 4/8] ath10k: add workqueue for RX path of sdio
From: Wen Gong @ 2019-09-05 10:48 UTC (permalink / raw)
To: Wen Gong, ath10k@lists.infradead.org; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1567416146-14403-5-git-send-email-wgong@codeaurora.org>
> -----Original Message-----
> From: ath10k <ath10k-bounces@lists.infradead.org> On Behalf Of Wen Gong
> Sent: Monday, September 2, 2019 5:22 PM
> To: ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: [EXT] [PATCH v4 4/8] ath10k: add workqueue for RX path of sdio
>
Patch v5 sent without change, https://patchwork.kernel.org/patch/11132667/
>
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox