2018-12-02 09:44:41

by Maya Erez

[permalink] [raw]
Subject: [PATCH 00/12] wil6210 patches

The following set of patches include:
- Use platform specific configuration instead of wil6210 module parameters
- Various wil6210 fixes.

Ahmad Masri (5):
wil6210: support ndo_select_queue in net_device_ops
wil6210: add support for AC queues per station
wil6210: support up to 20 stations in AP mode
wil6210: accessing 802.3 addresses via utility functions
wil6210: prevent device memory access while in reset or suspend

Alexei Avshalom Lazar (2):
wil6210: check null pointer in _wil_cfg80211_merge_extra_ies
wil6210: align to latest auto generated wmi.h

Dedy Lansky (2):
wil6210: add option to drop Tx packets when tx ring is full
wil6210: fix invalid sta statistics update

Maya Erez (3):
wil6210: remove rtap_include_phy_info module param
wil6210: use platform specific configuration
wil6210: ignore HALP ICR if already handled

drivers/net/wireless/ath/wil6210/cfg80211.c | 41 ++-
drivers/net/wireless/ath/wil6210/debugfs.c | 46 ++-
drivers/net/wireless/ath/wil6210/interrupt.c | 10 +-
drivers/net/wireless/ath/wil6210/main.c | 160 +++++----
drivers/net/wireless/ath/wil6210/netdev.c | 75 +++-
drivers/net/wireless/ath/wil6210/pcie_bus.c | 31 +-
drivers/net/wireless/ath/wil6210/pm.c | 29 +-
drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 +-
drivers/net/wireless/ath/wil6210/trace.h | 2 +-
drivers/net/wireless/ath/wil6210/txrx.c | 405 +++++++++++++++-------
drivers/net/wireless/ath/wil6210/txrx.h | 49 ++-
drivers/net/wireless/ath/wil6210/txrx_edma.c | 12 +-
drivers/net/wireless/ath/wil6210/wil6210.h | 68 ++--
drivers/net/wireless/ath/wil6210/wil_crash_dump.c | 16 +-
drivers/net/wireless/ath/wil6210/wil_platform.h | 28 ++
drivers/net/wireless/ath/wil6210/wmi.c | 109 ++++--
drivers/net/wireless/ath/wil6210/wmi.h | 48 ++-
17 files changed, 793 insertions(+), 344 deletions(-)

--
1.9.1



2018-12-02 09:43:46

by Maya Erez

[permalink] [raw]
Subject: [PATCH 01/12] wil6210: remove rtap_include_phy_info module param

rtap_include_phy_info is not in use, hence can be removed.

Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/txrx.c | 85 +++++----------------------------
drivers/net/wireless/ath/wil6210/txrx.h | 5 --
drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
3 files changed, 13 insertions(+), 79 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 3e1c831..364f7880 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -30,11 +30,6 @@
#include "trace.h"
#include "txrx_edma.h"

-static bool rtap_include_phy_info;
-module_param(rtap_include_phy_info, bool, 0444);
-MODULE_PARM_DESC(rtap_include_phy_info,
- " Include PHY info in the radiotap header, default - no");
-
bool rx_align_2;
module_param(rx_align_2, bool, 0444);
MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no");
@@ -332,87 +327,31 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
u8 mcs_flags;
u8 mcs_index;
} __packed;
- struct wil6210_rtap_vendor {
- struct wil6210_rtap rtap;
- /* vendor */
- u8 vendor_oui[3] __aligned(2);
- u8 vendor_ns;
- __le16 vendor_skip;
- u8 vendor_data[0];
- } __packed;
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
- struct wil6210_rtap_vendor *rtap_vendor;
+ struct wil6210_rtap *rtap;
int rtap_len = sizeof(struct wil6210_rtap);
- int phy_length = 0; /* phy info header size, bytes */
- static char phy_data[128];
struct ieee80211_channel *ch = wil->monitor_chandef.chan;

- if (rtap_include_phy_info) {
- rtap_len = sizeof(*rtap_vendor) + sizeof(*d);
- /* calculate additional length */
- if (d->dma.status & RX_DMA_STATUS_PHY_INFO) {
- /**
- * PHY info starts from 8-byte boundary
- * there are 8-byte lines, last line may be partially
- * written (HW bug), thus FW configures for last line
- * to be excessive. Driver skips this last line.
- */
- int len = min_t(int, 8 + sizeof(phy_data),
- wil_rxdesc_phy_length(d));
-
- if (len > 8) {
- void *p = skb_tail_pointer(skb);
- void *pa = PTR_ALIGN(p, 8);
-
- if (skb_tailroom(skb) >= len + (pa - p)) {
- phy_length = len - 8;
- memcpy(phy_data, pa, phy_length);
- }
- }
- }
- rtap_len += phy_length;
- }
-
if (skb_headroom(skb) < rtap_len &&
pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) {
wil_err(wil, "Unable to expand headroom to %d\n", rtap_len);
return;
}

- rtap_vendor = skb_push(skb, rtap_len);
- memset(rtap_vendor, 0, rtap_len);
-
- rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
- rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len);
- rtap_vendor->rtap.rthdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_FLAGS) |
+ rtap->rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ rtap->rthdr.it_len = cpu_to_le16(rtap_len);
+ rtap->rthdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_MCS));
if (d->dma.status & RX_DMA_STATUS_ERROR)
- rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS;
-
- rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
- rtap_vendor->rtap.chnl_flags = cpu_to_le16(0);
-
- rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
- rtap_vendor->rtap.mcs_flags = 0;
- rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d);
-
- if (rtap_include_phy_info) {
- rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 <<
- IEEE80211_RADIOTAP_VENDOR_NAMESPACE);
- /* OUI for Wilocity 04:ce:14 */
- rtap_vendor->vendor_oui[0] = 0x04;
- rtap_vendor->vendor_oui[1] = 0xce;
- rtap_vendor->vendor_oui[2] = 0x14;
- rtap_vendor->vendor_ns = 1;
- /* Rx descriptor + PHY data */
- rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) +
- phy_length);
- memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d));
- memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data,
- phy_length);
- }
+ rtap->flags |= IEEE80211_RADIOTAP_F_BADFCS;
+
+ rtap->chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
+ rtap->chnl_flags = cpu_to_le16(0);
+
+ rtap->mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
+ rtap->mcs_flags = 0;
+ rtap->mcs_index = wil_rxdesc_mcs(d);
}

static bool wil_is_rx_idle(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 9d83be4..69e3bb9 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -530,11 +530,6 @@ static inline int wil_rxdesc_mcast(struct vring_rx_desc *d)
return WIL_GET_BITS(d->mac.d1, 13, 14);
}

-static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d)
-{
- return WIL_GET_BITS(d->dma.d0, 16, 29);
-}
-
static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
{
return (void *)skb->cb;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 345f059..28f740c 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -2516,7 +2516,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring)
if (ch)
cmd.sniffer_cfg.channel = ch->hw_value - 1;
cmd.sniffer_cfg.phy_info_mode =
- cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
+ cpu_to_le32(WMI_SNIFFER_PHY_INFO_DISABLED);
cmd.sniffer_cfg.phy_support =
cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS);
--
1.9.1


2018-12-02 09:43:48

by Maya Erez

[permalink] [raw]
Subject: [PATCH 03/12] wil6210: support ndo_select_queue in net_device_ops

From: Ahmad Masri <[email protected]>

Add support for Access Category to select queue for transmit packets.
The callback wil_select_queue will return the queue id [0..3] to use for
the current skb transmission.

This feature is disabled by default. Use ac_queues module param to enable.

Signed-off-by: Ahmad Masri <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/netdev.c | 43 +++++++++++++++++++++++--
drivers/net/wireless/ath/wil6210/wil_platform.h | 2 ++
2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index b99470c..bab457d 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -20,6 +20,8 @@
#include "wil6210.h"
#include "txrx.h"

+#define WIL6210_TX_QUEUES (4)
+
bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
struct net_device *ndev, bool up, bool ok)
{
@@ -91,10 +93,43 @@ static int wil_stop(struct net_device *ndev)
return rc;
}

+/**
+ * AC to queue mapping
+ *
+ * AC_VO -> queue 3
+ * AC_VI -> queue 2
+ * AC_BE -> queue 1
+ * AC_BK -> queue 0
+ */
+static u16 wil_select_queue(struct net_device *ndev,
+ struct sk_buff *skb,
+ struct net_device *sb_dev,
+ select_queue_fallback_t fallback)
+{
+ static const u16 wil_1d_to_queue[8] = {1, 0, 0, 1, 2, 2, 3, 3};
+ struct wil6210_priv *wil = ndev_to_wil(ndev);
+ u16 qid;
+
+ if (!wil->config.ac_queues)
+ return 0;
+
+ /* determine the priority */
+ if (skb->priority == 0 || skb->priority > 7)
+ skb->priority = cfg80211_classify8021d(skb, NULL);
+
+ qid = wil_1d_to_queue[skb->priority];
+
+ wil_dbg_txrx(wil, "select queue for priority %d -> queue %d\n",
+ skb->priority, qid);
+
+ return qid;
+}
+
static const struct net_device_ops wil_netdev_ops = {
.ndo_open = wil_open,
.ndo_stop = wil_stop,
.ndo_start_xmit = wil_start_xmit,
+ .ndo_select_queue = wil_select_queue,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
@@ -317,8 +352,12 @@ struct wil6210_vif *
return ERR_PTR(-EINVAL);
}

- ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
- wil_dev_setup);
+ if (wil->config.ac_queues)
+ ndev = alloc_netdev_mqs(sizeof(*vif), name, name_assign_type,
+ wil_dev_setup, WIL6210_TX_QUEUES, 1);
+ else
+ ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
+ wil_dev_setup);
if (!ndev) {
dev_err(wil_to_dev(wil), "alloc_netdev failed\n");
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index 7090e68..ac47e9d 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -59,6 +59,8 @@ struct wil_platform_config {
bool disable_ap_sme;
/* Max number of stations associated to the AP */
unsigned int max_assoc_sta;
+ /* enable access category for transmit packets, default - no */
+ bool ac_queues;
};

/**
--
1.9.1


2018-12-02 09:43:49

by Maya Erez

[permalink] [raw]
Subject: [PATCH 04/12] wil6210: add support for AC queues per station

From: Ahmad Masri <[email protected]>

Until now all stations (notably in AP mode) would share the same
queue/s exposed via netdev. This meant that whenever a single
station's ring became full all queues got stopped.

With the queues per station feature each station will have its own
net queue/s and it will not block other stations' transmission in
case its vring is full.

Driver will add queue/s per station when creating a new netdev.
The mapping between a station and its queues will be by sta cid.
Once a new sta connects the driver will open its queues
(can be one or four AC queues) for transmit. The driver uses the
same logic of ring capacity usage to wake the net queues.

Last four netdev queues are used for unclassified traffic
(e.g. when there's no cid for given DA) which is mostly multicast.

This feature is controlled by a q_per_sta module param
which is disabled by default.

Signed-off-by: Ahmad Masri <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 8 ++
drivers/net/wireless/ath/wil6210/main.c | 14 ++-
drivers/net/wireless/ath/wil6210/netdev.c | 58 +++++++---
drivers/net/wireless/ath/wil6210/txrx.c | 148 ++++++++++++++++++++++--
drivers/net/wireless/ath/wil6210/txrx_edma.c | 2 +-
drivers/net/wireless/ath/wil6210/wil6210.h | 24 +++-
drivers/net/wireless/ath/wil6210/wil_platform.h | 2 +
drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
8 files changed, 226 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index e51dc3f..2e00f10 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1776,6 +1776,10 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto err_bcast;

+ /* wake default net queue - used mainly for multicast */
+ if (wil->config.q_per_sta)
+ wil_update_cid_net_queues_bh(wil, vif, WIL6210_MAX_CID, false);
+
goto out; /* success */

err_bcast:
@@ -1965,6 +1969,10 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
memset(vif->gtk, 0, WMI_MAX_KEY_LEN);
vif->gtk_len = 0;

+ /* stop default net queue - used mainly for multicast */
+ if (wil->config.q_per_sta)
+ wil_update_cid_net_queues_bh(wil, vif, WIL6210_MAX_CID, true);
+
if (last)
__wil_down(wil);
else
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index bd687ad..c02526c 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -210,6 +210,9 @@ static void wil_disconnect_cid_complete(struct wil6210_vif *vif, int cid,
case NL80211_IFTYPE_P2P_GO:
/* AP-like interface */
cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
+ if (WIL_Q_PER_STA_USED(vif))
+ wil_update_cid_net_queues_bh(wil, vif,
+ cid, true);
break;
default:
break;
@@ -311,12 +314,14 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
if (!wil_vif_is_connected(wil, vif->mid)) {
- wil_update_net_queues_bh(wil, vif, NULL, true);
+ if (!WIL_Q_PER_STA_USED(vif))
+ wil_update_net_queues_bh(wil, vif, NULL, true);
if (test_and_clear_bit(wil_vif_fwconnected,
vif->status))
atomic_dec(&wil->connected_vifs);
- } else {
- wil_update_net_queues_bh(wil, vif, NULL, false);
+ } else if (!WIL_Q_PER_STA_USED(vif)) {
+ wil_update_net_queues_bh(wil, vif,
+ NULL, false);
}
break;
default:
@@ -433,6 +438,9 @@ void wil_disconnect_worker(struct work_struct *work)
return;
}

+ /* disconnect worker runs only from client/sta vif.
+ * stop all queues in case failed to connect
+ */
wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev);
cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index bab457d..b617059 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -20,8 +20,6 @@
#include "wil6210.h"
#include "txrx.h"

-#define WIL6210_TX_QUEUES (4)
-
bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
struct net_device *ndev, bool up, bool ok)
{
@@ -101,27 +99,53 @@ static int wil_stop(struct net_device *ndev)
* AC_BE -> queue 1
* AC_BK -> queue 0
*/
-static u16 wil_select_queue(struct net_device *ndev,
- struct sk_buff *skb,
- struct net_device *sb_dev,
- select_queue_fallback_t fallback)
+static u16 wil_select_ac_queue(struct wil6210_priv *wil, struct sk_buff *skb)
{
static const u16 wil_1d_to_queue[8] = {1, 0, 0, 1, 2, 2, 3, 3};
- struct wil6210_priv *wil = ndev_to_wil(ndev);
- u16 qid;
-
- if (!wil->config.ac_queues)
- return 0;
+ u16 ac_qid;

/* determine the priority */
if (skb->priority == 0 || skb->priority > 7)
skb->priority = cfg80211_classify8021d(skb, NULL);

- qid = wil_1d_to_queue[skb->priority];
+ ac_qid = wil_1d_to_queue[skb->priority];

wil_dbg_txrx(wil, "select queue for priority %d -> queue %d\n",
- skb->priority, qid);
+ skb->priority, ac_qid);
+
+ return ac_qid;
+}

+static u16 wil_select_queue(struct net_device *ndev,
+ struct sk_buff *skb,
+ struct net_device *sb_dev,
+ select_queue_fallback_t fallback)
+{
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct ethhdr *eth = (void *)skb->data;
+ u16 qid = 0;
+ bool mcast;
+
+ if (!WIL_Q_PER_STA_USED(vif))
+ goto out;
+
+ mcast = is_multicast_ether_addr(eth->h_dest);
+ if (mcast) {
+ qid = WIL6210_MAX_CID;
+ } else {
+ qid = wil_find_cid(wil, vif->mid, eth->h_dest);
+
+ /* the MCAST queues also used as default queues */
+ if (qid < 0)
+ qid = WIL6210_MAX_CID;
+ }
+
+out:
+ if (wil->config.ac_queues) {
+ qid *= WIL6210_TX_AC_QUEUES;
+ qid += wil_select_ac_queue(wil, skb);
+ }
return qid;
}

@@ -345,6 +369,7 @@ struct wil6210_vif *
struct wireless_dev *wdev;
struct wil6210_vif *vif;
u8 mid;
+ u16 num_of_queues = 1;

mid = wil_vif_find_free_mid(wil);
if (mid == U8_MAX) {
@@ -353,8 +378,13 @@ struct wil6210_vif *
}

if (wil->config.ac_queues)
+ num_of_queues = WIL6210_TX_AC_QUEUES;
+ if (wil->config.q_per_sta)
+ num_of_queues *= (WIL6210_MAX_CID + 1);
+
+ if (num_of_queues > 1)
ndev = alloc_netdev_mqs(sizeof(*vif), name, name_assign_type,
- wil_dev_setup, WIL6210_TX_QUEUES, 1);
+ wil_dev_setup, num_of_queues, 1);
else
ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
wil_dev_setup);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index e49fe30..714ca0f 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1155,12 +1155,21 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct sk_buff *skb)
{
- int i;
+ int i, cid;
struct ethhdr *eth = (void *)skb->data;
- int cid = wil_find_cid(wil, vif->mid, eth->h_dest);
int min_ring_id = wil_get_min_tx_ring_id(wil);

- if (cid < 0)
+ if (WIL_Q_PER_STA_USED(vif))
+ /* assuming skb->queue_mapping was set according to cid
+ * after calling to net_device_ops.ndo_select_queue
+ */
+ cid = wil->config.ac_queues ?
+ skb_get_queue_mapping(skb) / WIL6210_TX_AC_QUEUES :
+ skb_get_queue_mapping(skb);
+ else
+ cid = wil_find_cid(wil, vif->mid, eth->h_dest);
+
+ if (cid < 0 || cid >= WIL6210_MAX_CID)
return NULL;

/* TODO: fix for multiple TID */
@@ -1934,6 +1943,91 @@ static int wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif,
return rc;
}

+static int wil_get_cid_by_ring(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ struct wil_ring *ring)
+{
+ int ring_index = ring - wil->ring_tx;
+
+ if (unlikely(ring_index < 0 || ring_index >= WIL6210_MAX_TX_RINGS)) {
+ wil_err(wil, "cid by ring 0x%p: invalid ring index %d\n",
+ ring, ring_index);
+ return WIL6210_MAX_CID;
+ }
+
+ return wil->ring2cid_tid[ring_index][0];
+}
+
+static void wil_tx_stop_cid_queues(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ int cid)
+{
+ struct net_device *ndev = vif_to_ndev(vif);
+ u16 start_qid, qid, queues_per_cid;
+
+ queues_per_cid = wil->config.ac_queues ? WIL6210_TX_AC_QUEUES : 1;
+ start_qid = cid * queues_per_cid;
+
+ wil_dbg_txrx(wil, "stop queues for cid=%d queues (%d .. %d)\n",
+ cid, start_qid, start_qid + queues_per_cid - 1);
+
+ for (qid = start_qid; qid < start_qid + queues_per_cid; qid++) {
+ struct netdev_queue *txq = netdev_get_tx_queue(ndev, qid);
+
+ netif_tx_stop_queue(txq);
+ }
+ if (cid < WIL6210_MAX_CID)
+ wil->sta[cid].net_queue_stopped = true;
+}
+
+static void wil_tx_wake_cid_queues(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ int cid)
+{
+ struct net_device *ndev = vif_to_ndev(vif);
+ u16 start_qid, qid, queues_per_cid;
+
+ queues_per_cid = wil->config.ac_queues ? WIL6210_TX_AC_QUEUES : 1;
+ start_qid = cid * queues_per_cid;
+
+ wil_dbg_txrx(wil, "wake queues for cid=%d queues (%d .. %d)\n",
+ cid, start_qid, start_qid + queues_per_cid - 1);
+
+ for (qid = start_qid; qid < start_qid + queues_per_cid; qid++) {
+ struct netdev_queue *txq = netdev_get_tx_queue(ndev, qid);
+
+ netif_tx_wake_queue(txq);
+ }
+ if (cid < WIL6210_MAX_CID)
+ wil->sta[cid].net_queue_stopped = false;
+}
+
+static inline void __wil_update_net_queues_per_sta(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ struct wil_ring *ring,
+ bool check_stop)
+{
+ int cid;
+
+ /* ring is not null - checked by caller */
+ cid = wil_get_cid_by_ring(wil, vif, ring);
+ if (cid < WIL6210_MAX_CID &&
+ check_stop == wil->sta[cid].net_queue_stopped)
+ /* net queues already in desired state */
+ return;
+
+ if (check_stop) {
+ /* check not enough room in the vring */
+ if (unlikely(wil_ring_avail_low(ring)))
+ wil_tx_stop_cid_queues(wil, vif, cid);
+ return;
+ }
+
+ /* check for enough room in the vring */
+ if (wil_ring_avail_high(ring))
+ wil_tx_wake_cid_queues(wil, vif, cid);
+}
+
/**
* Check status of tx vrings and stop/wake net queues if needed
* It will start/stop net queues of a specific VIF net_device.
@@ -1963,13 +2057,18 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
return;

if (ring)
- wil_dbg_txrx(wil, "vring %d, mid %d, check_stop=%d, stopped=%d",
+ wil_dbg_txrx(wil, "ring %d, mid %d, check_stop=%d, stopped=%d",
(int)(ring - wil->ring_tx), vif->mid, check_stop,
vif->net_queue_stopped);
else
wil_dbg_txrx(wil, "check_stop=%d, mid=%d, stopped=%d",
check_stop, vif->mid, vif->net_queue_stopped);

+ if (ring && WIL_Q_PER_STA_USED(vif)) {
+ __wil_update_net_queues_per_sta(wil, vif, ring, check_stop);
+ return;
+ }
+
if (check_stop == vif->net_queue_stopped)
/* net queues already in desired state */
return;
@@ -1979,6 +2078,9 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
/* not enough room in the vring */
netif_tx_stop_all_queues(vif_to_ndev(vif));
vif->net_queue_stopped = true;
+ if (WIL_Q_PER_STA_USED(vif))
+ for (i = 0; i < WIL6210_MAX_CID; i++)
+ wil->sta[i].net_queue_stopped = true;
wil_dbg_txrx(wil, "netif_tx_stop called\n");
}
return;
@@ -2010,25 +2112,55 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
wil_dbg_txrx(wil, "calling netif_tx_wake\n");
netif_tx_wake_all_queues(vif_to_ndev(vif));
vif->net_queue_stopped = false;
+ if (WIL_Q_PER_STA_USED(vif))
+ for (i = 0; i < WIL6210_MAX_CID; i++)
+ wil->sta[i].net_queue_stopped = false;
}
}

-void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
- struct wil_ring *ring, bool check_stop)
+void wil_update_net_queues(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ struct wil_ring *ring,
+ bool check_stop)
{
spin_lock(&wil->net_queue_lock);
__wil_update_net_queues(wil, vif, ring, check_stop);
spin_unlock(&wil->net_queue_lock);
}

-void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
- struct wil_ring *ring, bool check_stop)
+void wil_update_net_queues_bh(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ struct wil_ring *ring,
+ bool check_stop)
{
spin_lock_bh(&wil->net_queue_lock);
__wil_update_net_queues(wil, vif, ring, check_stop);
spin_unlock_bh(&wil->net_queue_lock);
}

+void wil_update_cid_net_queues_bh(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ int cid,
+ bool should_stop)
+{
+ if (!WIL_Q_PER_STA_USED(vif)) {
+ wil_update_net_queues_bh(wil, vif, NULL, should_stop);
+ return;
+ }
+
+ if (cid < WIL6210_MAX_CID &&
+ should_stop == wil->sta[cid].net_queue_stopped)
+ /* net queues already in desired state */
+ return;
+
+ spin_lock_bh(&wil->net_queue_lock);
+ if (should_stop)
+ wil_tx_stop_cid_queues(wil, vif, cid);
+ else
+ wil_tx_wake_cid_queues(wil, vif, cid);
+ spin_unlock_bh(&wil->net_queue_lock);
+}
+
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_vif *vif = ndev_to_vif(ndev);
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index 05a8348..4b0c9f8 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -1269,7 +1269,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,

/* shall we wake net queues? */
if (desc_cnt)
- wil_update_net_queues(wil, vif, NULL, false);
+ wil_update_net_queues(wil, vif, ring, false);

/* Update the HW tail ptr (RD ptr) */
wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index f8b8492..6bd5198 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -63,6 +63,8 @@
*/
#define WIL_MAX_VIFS 4

+#define WIL6210_TX_AC_QUEUES (4)
+
/**
* extract bits [@b0:@b1] (inclusive) from the value @x
* it should be @b0 <= @b1, or result is incorrect
@@ -752,6 +754,7 @@ struct wil_sta_info {
struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM];
struct wil_tid_crypto_rx group_crypto_rx;
u8 aid; /* 1-254; 0 if unknown/not reported */
+ bool net_queue_stopped; /* used when q_per_sta enabled */
};

enum {
@@ -866,7 +869,7 @@ struct wil6210_vif {
struct list_head probe_client_pending;
struct mutex probe_client_mutex; /* protect @probe_client_pending */
struct work_struct probe_client_worker;
- int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
+ int net_queue_stopped; /* used when q_per_sta disabled */
bool fw_stats_ready; /* per-cid statistics are ready inside sta_info */
u64 fw_stats_tsf; /* measurement timestamp */
};
@@ -1053,6 +1056,8 @@ struct wil6210_priv {
#define vif_to_wil(v) (v->wil)
#define vif_to_ndev(v) (v->ndev)
#define vif_to_wdev(v) (&v->wdev)
+#define WIL_Q_PER_STA_USED(v) (vif_to_wil(v)->config.q_per_sta && \
+ v->wdev.iftype == NL80211_IFTYPE_AP)

static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil,
struct wireless_dev *wdev)
@@ -1330,10 +1335,19 @@ void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid,
void wil_bcast_fini(struct wil6210_vif *vif);
void wil_bcast_fini_all(struct wil6210_priv *wil);

-void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
- struct wil_ring *ring, bool should_stop);
-void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
- struct wil_ring *ring, bool check_stop);
+void wil_update_net_queues(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ struct wil_ring *ring,
+ bool check_stop);
+void wil_update_net_queues_bh(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ struct wil_ring *ring,
+ bool check_stop);
+void wil_update_cid_net_queues_bh(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ int cid,
+ bool check_stop);
+
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
int wil_tx_complete(struct wil6210_vif *vif, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index ac47e9d..60b4abc 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -61,6 +61,8 @@ struct wil_platform_config {
unsigned int max_assoc_sta;
/* enable access category for transmit packets, default - no */
bool ac_queues;
+ /* enable allocating tx queue(s) per station, default - no */
+ bool q_per_sta;
};

/**
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 2e36c7c..d42849f 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1077,7 +1077,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
wil->sta[evt->cid].aid = evt->aid;
if (!test_and_set_bit(wil_vif_fwconnected, vif->status))
atomic_inc(&wil->connected_vifs);
- wil_update_net_queues_bh(wil, vif, NULL, false);
+ wil_update_cid_net_queues_bh(wil, vif, evt->cid, false);

out:
if (rc) {
--
1.9.1


2018-12-02 09:43:50

by Maya Erez

[permalink] [raw]
Subject: [PATCH 05/12] wil6210: add option to drop Tx packets when tx ring is full

From: Dedy Lansky <[email protected]>

In AP mode with multiple clients, driver stops net queue
(netif_tx_stop_queue) upon first ring (serving specific client)
becoming full. This can have negative effect on transmission to
other clients which may still have room in their corresponding rings.

Implement new policy in which stop/wake net queue are not used. In
case there is no room in the ring for a transmitted packet, drop the
packet.
New policy is disabled by default and can be enabled with new
drop_if_ring_full module param.

Signed-off-by: Dedy Lansky <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/txrx.c | 6 ++++++
drivers/net/wireless/ath/wil6210/wil_platform.h | 2 ++
2 files changed, 8 insertions(+)

diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 714ca0f..1e715ba 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -2064,6 +2064,10 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
wil_dbg_txrx(wil, "check_stop=%d, mid=%d, stopped=%d",
check_stop, vif->mid, vif->net_queue_stopped);

+ if (ring && wil->config.drop_if_ring_full)
+ /* no need to stop/wake net queues */
+ return;
+
if (ring && WIL_Q_PER_STA_USED(vif)) {
__wil_update_net_queues_per_sta(wil, vif, ring, check_stop);
return;
@@ -2227,6 +2231,8 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
case -ENOMEM:
+ if (wil->config.drop_if_ring_full)
+ goto drop;
return NETDEV_TX_BUSY;
default:
break; /* goto drop; */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index 60b4abc..c90ab7577 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -63,6 +63,8 @@ struct wil_platform_config {
bool ac_queues;
/* enable allocating tx queue(s) per station, default - no */
bool q_per_sta;
+ /* drop Tx packets in case tx ring is full, default - no */
+ bool drop_if_ring_full;
};

/**
--
1.9.1


2018-12-02 09:43:50

by Maya Erez

[permalink] [raw]
Subject: [PATCH 02/12] wil6210: use platform specific configuration

Some of wil6210 configuration variables are platform specific.
Add platform op to allow the platform driver to change the wil6210
default configuration.

Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 13 +---
drivers/net/wireless/ath/wil6210/main.c | 94 ++++++++++---------------
drivers/net/wireless/ath/wil6210/netdev.c | 2 +-
drivers/net/wireless/ath/wil6210/pcie_bus.c | 31 ++++----
drivers/net/wireless/ath/wil6210/pm.c | 2 +-
drivers/net/wireless/ath/wil6210/txrx.c | 15 ++--
drivers/net/wireless/ath/wil6210/wil6210.h | 11 ++-
drivers/net/wireless/ath/wil6210/wil_platform.h | 22 ++++++
drivers/net/wireless/ath/wil6210/wmi.c | 23 +++---
9 files changed, 105 insertions(+), 108 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 9b2f9f5..e51dc3f 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -25,10 +25,6 @@

#define WIL_MAX_ROC_DURATION_MS 5000

-bool disable_ap_sme;
-module_param(disable_ap_sme, bool, 0444);
-MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
-
#ifdef CONFIG_PM
static struct wiphy_wowlan_support wil_wowlan_support = {
.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
@@ -1991,7 +1987,7 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
mac, params->aid, vif->mid,
params->sta_flags_mask, params->sta_flags_set);

- if (!disable_ap_sme) {
+ if (!wil->config.disable_ap_sme) {
wil_err(wil, "not supported with AP SME enabled\n");
return -EOPNOTSUPP;
}
@@ -2036,7 +2032,7 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy,
mac, params->sta_flags_mask, params->sta_flags_set,
vif->mid);

- if (!disable_ap_sme) {
+ if (!wil->config.disable_ap_sme) {
wil_dbg_misc(wil, "not supported with AP SME enabled\n");
return -EOPNOTSUPP;
}
@@ -2411,10 +2407,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_PS_ON_BY_DEFAULT;
- if (!disable_ap_sme)
- wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
- dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
- __func__, wiphy->flags);
+
wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index ba6a2ee..bd687ad 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -31,10 +31,6 @@
#define WIL_DEFAULT_NUM_RX_STATUS_RINGS 1
#define WIL_BOARD_FILE_MAX_NAMELEN 128

-bool debug_fw; /* = false; */
-module_param(debug_fw, bool, 0444);
-MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
-
static u8 oob_mode;
module_param(oob_mode, byte, 0444);
MODULE_PARM_DESC(oob_mode,
@@ -44,14 +40,6 @@
module_param(no_fw_recovery, bool, 0644);
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");

-/* if not set via modparam, will be set to default value of 1/8 of
- * rx ring size during init flow
- */
-unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
-module_param(rx_ring_overflow_thrsh, ushort, 0444);
-MODULE_PARM_DESC(rx_ring_overflow_thrsh,
- " RX ring overflow threshold in descriptors.");
-
/* We allow allocation of more than 1 page buffers to support large packets.
* It is suboptimal behavior performance wise in case MTU above page size.
*/
@@ -81,39 +69,6 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp)
module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
MODULE_PARM_DESC(mtu_max, " Max MTU value.");

-static uint rx_ring_order;
-static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
-static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
-
-static int ring_order_set(const char *val, const struct kernel_param *kp)
-{
- int ret;
- uint x;
-
- ret = kstrtouint(val, 0, &x);
- if (ret)
- return ret;
-
- if ((x < WIL_RING_SIZE_ORDER_MIN) || (x > WIL_RING_SIZE_ORDER_MAX))
- return -EINVAL;
-
- *((uint *)kp->arg) = x;
-
- return 0;
-}
-
-static const struct kernel_param_ops ring_order_ops = {
- .set = ring_order_set,
- .get = param_get_uint,
-};
-
-module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, 0444);
-MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
-module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, 0444);
-MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
-module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, 0444);
-MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
-
enum {
WIL_BOOT_ERR,
WIL_BOOT_VANILLA,
@@ -390,7 +345,8 @@ static int wil_disconnect_cid(struct wil6210_vif *vif, int cid,
}

/* inform lower layers */
- if (wdev->iftype == NL80211_IFTYPE_AP && disable_ap_sme)
+ if (wdev->iftype == NL80211_IFTYPE_AP &&
+ wil->config.disable_ap_sme)
del_sta = true;

/* disconnect by sending command disconnect/del_sta and wait
@@ -618,7 +574,12 @@ int wil_ring_init_tx(struct wil6210_vif *vif, int cid)
wil_dbg_wmi(wil, "Configure for connection CID %d MID %d ring %d\n",
cid, vif->mid, ringid);

- rc = wil->txrx_ops.ring_init_tx(vif, ringid, 1 << tx_ring_order,
+ if (wil->config.tx_ring_order < WIL_RING_SIZE_ORDER_MIN ||
+ wil->config.tx_ring_order > WIL_RING_SIZE_ORDER_MAX)
+ wil->config.tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
+
+ rc = wil->txrx_ops.ring_init_tx(vif, ringid,
+ 1 << wil->config.tx_ring_order,
cid, 0);
if (rc)
wil_err(wil, "init TX for CID %d MID %d vring %d failed\n",
@@ -640,8 +601,14 @@ int wil_bcast_init(struct wil6210_vif *vif)
if (ri < 0)
return ri;

+ if (wil->config.bcast_ring_order < WIL_RING_SIZE_ORDER_MIN ||
+ wil->config.bcast_ring_order > WIL_RING_SIZE_ORDER_MAX)
+ wil->config.bcast_ring_order =
+ WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
+
vif->bcast_ring = ri;
- rc = wil->txrx_ops.ring_init_bcast(vif, ri, 1 << bcast_ring_order);
+ rc = wil->txrx_ops.ring_init_bcast(vif, ri,
+ 1 << wil->config.bcast_ring_order);
if (rc)
vif->bcast_ring = -1;

@@ -720,9 +687,6 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;

- if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
- rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
-
wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT;

wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
@@ -1237,6 +1201,12 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
if (test_bit(WMI_FW_CAPABILITY_TX_REQ_EXT, wil->fw_capabilities))
wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX;

+ if (!wil->config.disable_ap_sme)
+ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
+
+ dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
+ __func__, wiphy->flags);
+
if (wil->platform_ops.set_features) {
features = (test_bit(WMI_FW_CAPABILITY_REF_CLOCK_CONTROL,
wil->fw_capabilities) &&
@@ -1568,7 +1538,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
WARN_ON(!mutex_is_locked(&wil->mutex));
WARN_ON(test_bit(wil_status_napi_en, wil->status));

- if (debug_fw) {
+ if (wil->config.debug_fw) {
static const u8 mac[ETH_ALEN] = {
0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
};
@@ -1789,12 +1759,14 @@ int __wil_up(struct wil6210_priv *wil)
return rc;

/* Rx RING. After MAC and beacon */
- if (rx_ring_order == 0)
- rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ?
+ if (wil->config.rx_ring_order == 0 ||
+ wil->config.rx_ring_order < WIL_RING_SIZE_ORDER_MIN ||
+ wil->config.rx_ring_order > WIL_RING_SIZE_ORDER_MAX)
+ wil->config.rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ?
WIL_RX_RING_SIZE_ORDER_DEFAULT :
WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT;

- rc = wil->txrx_ops.rx_init(wil, rx_ring_order);
+ rc = wil->txrx_ops.rx_init(wil, wil->config.rx_ring_order);
if (rc)
return rc;

@@ -1967,3 +1939,15 @@ void wil_init_txrx_ops(struct wil6210_priv *wil)
else
wil_init_txrx_ops_legacy_dma(wil);
}
+
+void wil_init_configuration(struct wil6210_priv *wil)
+{
+ /* set default config values */
+ wil->config.n_msi = 3;
+ wil->config.max_assoc_sta = WIL6210_MAX_CID;
+
+ /* update the configuration with platform specific configuration */
+ if (wil->platform_ops.get_config)
+ wil->platform_ops.get_config(wil->platform_handle,
+ &wil->config);
+}
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index b4e0eb1..b99470c 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -54,7 +54,7 @@ static int wil_open(struct net_device *ndev)

wil_dbg_misc(wil, "open\n");

- if (debug_fw ||
+ if (wil->config.debug_fw ||
test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
wil_err(wil, "while in debug_fw or wmi_only mode\n");
return -EINVAL;
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index c8c6613..8dbf3fb 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -24,10 +24,6 @@
#include <linux/rtnetlink.h>
#include <linux/pm_runtime.h>

-static int n_msi = 3;
-module_param(n_msi, int, 0444);
-MODULE_PARM_DESC(n_msi, " Use MSI interrupt: 0 - use INTx, 1 - single, or 3 - (default) ");
-
bool ftm_mode;
module_param(ftm_mode, bool, 0444);
MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
@@ -201,31 +197,34 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
pci_set_master(pdev);

/* how many MSI interrupts to request? */
- switch (n_msi) {
+ switch (wil->config.n_msi) {
case 3:
case 1:
- wil_dbg_misc(wil, "Setup %d MSI interrupts\n", n_msi);
+ wil_dbg_misc(wil, "Setup %d MSI interrupts\n",
+ wil->config.n_msi);
break;
case 0:
wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
break;
default:
- wil_err(wil, "Invalid n_msi=%d, default to 1\n", n_msi);
- n_msi = 1;
+ wil_err(wil, "Invalid n_msi=%d, default to 1\n",
+ wil->config.n_msi);
+ wil->config.n_msi = 1;
}

- if (n_msi == 3 &&
- pci_alloc_irq_vectors(pdev, n_msi, n_msi, PCI_IRQ_MSI) < n_msi) {
+ if (wil->config.n_msi == 3 &&
+ pci_alloc_irq_vectors(pdev, wil->config.n_msi, wil->config.n_msi,
+ PCI_IRQ_MSI) < wil->config.n_msi) {
wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
- n_msi = 1;
+ wil->config.n_msi = 1;
}

- if (n_msi == 1 && pci_enable_msi(pdev)) {
+ if (wil->config.n_msi == 1 && pci_enable_msi(pdev)) {
wil_err(wil, "pci_enable_msi failed, use INTx\n");
- n_msi = 0;
+ wil->config.n_msi = 0;
}

- wil->n_msi = n_msi;
+ wil->n_msi = wil->config.n_msi;

if (wil->n_msi == 0 && msi_only) {
wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
@@ -346,6 +345,10 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
wil_err(wil, "wil_platform_init failed\n");
goto if_free;
}
+
+ /* Set default config and update it with platform configuration */
+ wil_init_configuration(wil);
+
/* rollback to err_plat */
rc = pci_enable_device(pdev);
if (rc && pdev->msi_enabled == 0) {
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 75fe932..14fd635 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -90,7 +90,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)

wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");

- if (wmi_only || debug_fw) {
+ if (wmi_only || wil->config.debug_fw) {
wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
wmi_only ? "wmi_only" : "debug_fw");
rc = -EBUSY;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 364f7880..e49fe30 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -30,17 +30,13 @@
#include "trace.h"
#include "txrx_edma.h"

-bool rx_align_2;
-module_param(rx_align_2, bool, 0444);
-MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no");
-
bool rx_large_buf;
module_param(rx_large_buf, bool, 0444);
MODULE_PARM_DESC(rx_large_buf, " allocate 8KB RX buffers, default - no");

-static inline uint wil_rx_snaplen(void)
+static inline uint wil_rx_snaplen(struct wil6210_priv *wil)
{
- return rx_align_2 ? 6 : 0;
+ return wil->config.rx_align_2 ? 6 : 0;
}

/* wil_ring_wmark_low - low watermark for available descriptor space */
@@ -265,7 +261,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct wil_ring *vring,
u32 i, int headroom)
{
struct device *dev = wil_to_dev(wil);
- unsigned int sz = wil->rx_buf_len + ETH_HLEN + wil_rx_snaplen();
+ unsigned int sz = wil->rx_buf_len + ETH_HLEN + wil_rx_snaplen(wil);
struct vring_rx_desc dd, *d = &dd;
volatile struct vring_rx_desc *_d = &vring->va[i].rx.legacy;
dma_addr_t pa;
@@ -383,7 +379,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
struct vring_rx_desc *d;
struct sk_buff *skb;
dma_addr_t pa;
- unsigned int snaplen = wil_rx_snaplen();
+ unsigned int snaplen = wil_rx_snaplen(wil);
unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen;
u16 dmalen;
u8 ftype;
@@ -823,6 +819,9 @@ static int wil_rx_init(struct wil6210_priv *wil, uint order)
return -EINVAL;
}

+ if (wil->config.rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
+ wil->config.rx_ring_overflow_thrsh = 1 << (order - 3);
+
wil_rx_buf_len_init(wil);

vring->size = 1 << order;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 0f3be3ff..f8b8492 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -31,12 +31,8 @@

extern bool no_fw_recovery;
extern unsigned int mtu_max;
-extern unsigned short rx_ring_overflow_thrsh;
extern int agg_wsize;
-extern bool rx_align_2;
extern bool rx_large_buf;
-extern bool debug_fw;
-extern bool disable_ap_sme;
extern bool ftm_mode;

struct wil6210_priv;
@@ -143,8 +139,7 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
#define WIL6210_SCAN_TO msecs_to_jiffies(10000)
#define WIL6210_DISCONNECT_TO_MS (2000)
#define WIL6210_RX_HIGH_TRSH_INIT (0)
-#define WIL6210_RX_HIGH_TRSH_DEFAULT \
- (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
+
#define WIL_MAX_DMG_AID 254 /* for DMG only 1-254 allowed (see
* 802.11REVmc/D5.0, section 9.4.1.8)
*/
@@ -1045,6 +1040,8 @@ struct wil6210_priv {

u32 max_agg_wsize;
u32 max_ampdu_size;
+
+ struct wil_platform_config config;
};

#define wil_to_wiphy(i) (i->wiphy)
@@ -1402,4 +1399,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,

void update_supported_bands(struct wil6210_priv *wil);

+void wil_init_configuration(struct wil6210_priv *wil);
+
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index bca0906..7090e68 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -40,6 +40,27 @@ enum wil_platform_capa {
WIL_PLATFORM_CAPA_MAX,
};

+struct wil_platform_config {
+ /* use MSI interrupt: 0 - use INTx, 1 - single, or 3 - (default) */
+ int n_msi;
+ /* align Rx buffers on 4*n+2, default - no */
+ bool rx_align_2;
+ /* do not perform card reset. For FW debug, default - no */
+ bool debug_fw;
+ /* RX ring overflow threshold in descriptors */
+ unsigned short rx_ring_overflow_thrsh;
+ /* Rx ring order; size = 1 << order, default 10 */
+ uint rx_ring_order;
+ /* Tx ring order; size = 1 << order, default 12 */
+ uint tx_ring_order;
+ /* Bcast ring order; size = 1 << order, default 7 */
+ uint bcast_ring_order;
+ /* let user space handle AP mode SME */
+ bool disable_ap_sme;
+ /* Max number of stations associated to the AP */
+ unsigned int max_assoc_sta;
+};
+
/**
* struct wil_platform_ops - wil platform module calls from this
* driver to platform driver
@@ -52,6 +73,7 @@ struct wil_platform_ops {
int (*notify)(void *handle, enum wil_platform_event evt);
int (*get_capa)(void *handle);
void (*set_features)(void *handle, int features);
+ void (*get_config)(void *handle, struct wil_platform_config *config);
};

/**
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 28f740c..2e36c7c 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -24,10 +24,6 @@
#include "wmi.h"
#include "trace.h"

-static uint max_assoc_sta = WIL6210_MAX_CID;
-module_param(max_assoc_sta, uint, 0644);
-MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
-
int agg_wsize; /* = 0; */
module_param(agg_wsize, int, 0644);
MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
@@ -1049,7 +1045,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {

if (rc) {
- if (disable_ap_sme)
+ if (wil->config.disable_ap_sme)
/* notify new_sta has failed */
cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
goto out;
@@ -1113,7 +1109,7 @@ static void wmi_evt_disconnect(struct wil6210_vif *vif, int id,

mutex_lock(&wil->mutex);
wil6210_disconnect_complete(vif, evt->bssid, reason_code);
- if (disable_ap_sme) {
+ if (wil->config.disable_ap_sme) {
struct wireless_dev *wdev = vif_to_wdev(vif);
struct net_device *ndev = vif_to_ndev(vif);

@@ -1204,7 +1200,7 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
return;
}

- if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme ||
+ if (wdev->iftype != NL80211_IFTYPE_AP || !wil->config.disable_ap_sme ||
test_bit(wil_vif_ft_roam, vif->status))
/* in AP mode with disable_ap_sme that is not FT,
* this is done by wil_cfg80211_change_station()
@@ -2100,10 +2096,10 @@ int wmi_pcp_start(struct wil6210_vif *vif,
.network_type = wmi_nettype,
.disable_sec_offload = 1,
.channel = chan - 1,
- .pcp_max_assoc_sta = max_assoc_sta,
+ .pcp_max_assoc_sta = wil->config.max_assoc_sta,
.hidden_ssid = hidden_ssid,
.is_go = is_go,
- .ap_sme_offload_mode = disable_ap_sme ?
+ .ap_sme_offload_mode = wil->config.disable_ap_sme ?
WMI_AP_SME_OFFLOAD_PARTIAL :
WMI_AP_SME_OFFLOAD_FULL,
.abft_len = wil->abft_len,
@@ -2122,11 +2118,12 @@ int wmi_pcp_start(struct wil6210_vif *vif,
(cmd.pcp_max_assoc_sta <= 0)) {
wil_info(wil,
"Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
- max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
+ wil->config.max_assoc_sta, WIL6210_MAX_CID,
+ WIL6210_MAX_CID);
cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
}

- if (disable_ap_sme &&
+ if (wil->config.disable_ap_sme &&
!test_bit(WMI_FW_CAPABILITY_AP_SME_OFFLOAD_PARTIAL,
wil->fw_capabilities)) {
wil_err(wil, "disable_ap_sme not supported by FW\n");
@@ -2499,7 +2496,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring)
.mid = 0, /* TODO - what is it? */
.decap_trans_type = WMI_DECAP_TYPE_802_3,
.reorder_type = WMI_RX_SW_REORDER,
- .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
+ .host_thrsh = cpu_to_le16(wil->config.rx_ring_overflow_thrsh),
};
struct {
struct wmi_cmd_hdr wmi;
@@ -2528,7 +2525,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring)
cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
}

- if (rx_align_2)
+ if (wil->config.rx_align_2)
cmd.l2_802_3_offload_ctrl |=
L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;

--
1.9.1


2018-12-02 09:43:51

by Maya Erez

[permalink] [raw]
Subject: [PATCH 07/12] wil6210: accessing 802.3 addresses via utility functions

From: Ahmad Masri <[email protected]>

Rearrange the code by having functions to access 802.3 header
members, source and destination addresses.

Signed-off-by: Ahmad Masri <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/netdev.c | 6 +++---
drivers/net/wireless/ath/wil6210/txrx.c | 33 ++++++++++++++-----------------
drivers/net/wireless/ath/wil6210/txrx.h | 18 +++++++++++++++--
3 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 74e90a3..41620c2 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -123,18 +123,18 @@ static u16 wil_select_queue(struct net_device *ndev,
{
struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = vif_to_wil(vif);
- struct ethhdr *eth = (void *)skb->data;
+ const u8 *da = wil_skb_get_da(skb);
u16 qid = 0;
bool mcast;

if (!WIL_Q_PER_STA_USED(vif))
goto out;

- mcast = is_multicast_ether_addr(eth->h_dest);
+ mcast = is_multicast_ether_addr(da);
if (mcast) {
qid = wil->config.max_assoc_sta;
} else {
- qid = wil_find_cid(wil, vif->mid, eth->h_dest);
+ qid = wil_find_cid(wil, vif->mid, da);

/* the MCAST queues also used as default queues */
if (qid < 0)
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 471f85e..4c833fc 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -373,7 +373,6 @@ static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb)
*/
int cid = wil_rxdesc_cid(d);
unsigned int snaplen = wil_rx_snaplen(wil);
- struct ethhdr *eth;
struct ieee80211_hdr_3addr *hdr;
int i;
unsigned char *ta;
@@ -391,8 +390,7 @@ static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb)
skb->len);
return -ENOENT;
}
- eth = (void *)skb->data;
- ta = eth->h_source;
+ ta = wil_skb_get_sa(skb);
} else {
if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) {
wil_err_ratelimited(wil, "Short frame, len = %d\n",
@@ -730,11 +728,11 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
unsigned int len = skb->len;
int cid;
int security;
- struct ethhdr *eth = (void *)skb->data;
+ u8 *sa, *da = wil_skb_get_da(skb);
/* here looking for DA, not A1, thus Rxdesc's 'mcast' indication
* is not suitable, need to look at data
*/
- int mcast = is_multicast_ether_addr(eth->h_dest);
+ int mcast = is_multicast_ether_addr(da);
struct wil_net_stats *stats;
struct sk_buff *xmit_skb = NULL;
static const char * const gro_res_str[] = {
@@ -765,7 +763,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
}

if (wdev->iftype == NL80211_IFTYPE_STATION) {
- if (mcast && ether_addr_equal(eth->h_source, ndev->dev_addr)) {
+ sa = wil_skb_get_sa(skb);
+ if (mcast && ether_addr_equal(sa, ndev->dev_addr)) {
/* mcast packet looped back to us */
rc = GRO_DROP;
dev_kfree_skb(skb);
@@ -778,8 +777,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
*/
xmit_skb = skb_copy(skb, GFP_ATOMIC);
} else {
- int xmit_cid = wil_find_cid(wil, vif->mid,
- eth->h_dest);
+ int xmit_cid = wil_find_cid(wil, vif->mid, da);

if (xmit_cid >= 0) {
/* The destination station is associated to
@@ -1234,7 +1232,7 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil,
struct sk_buff *skb)
{
int i, cid;
- struct ethhdr *eth = (void *)skb->data;
+ const u8 *da = wil_skb_get_da(skb);
int min_ring_id = wil_get_min_tx_ring_id(wil);

if (WIL_Q_PER_STA_USED(vif))
@@ -1245,7 +1243,7 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil,
skb_get_queue_mapping(skb) / WIL6210_TX_AC_QUEUES :
skb_get_queue_mapping(skb);
else
- cid = wil_find_cid(wil, vif->mid, eth->h_dest);
+ cid = wil_find_cid(wil, vif->mid, da);

if (cid < 0 || cid >= wil->config.max_assoc_sta)
return NULL;
@@ -1260,7 +1258,7 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil,
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];

wil_dbg_txrx(wil, "find_tx_ucast: (%pM) -> [%d]\n",
- eth->h_dest, i);
+ da, i);
if (v->va && txdata->enabled) {
return v;
} else {
@@ -1351,10 +1349,10 @@ static struct wil_ring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
static void wil_set_da_for_vring(struct wil6210_priv *wil,
struct sk_buff *skb, int vring_index)
{
- struct ethhdr *eth = (void *)skb->data;
+ u8 *da = wil_skb_get_da(skb);
int cid = wil->ring2cid_tid[vring_index][0];

- ether_addr_copy(eth->h_dest, wil->sta[cid].addr);
+ ether_addr_copy(da, wil->sta[cid].addr);
}

static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
@@ -1365,8 +1363,7 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
struct sk_buff *skb2;
int i;
u8 cid;
- struct ethhdr *eth = (void *)skb->data;
- char *src = eth->h_source;
+ const u8 *src = wil_skb_get_sa(skb);
struct wil_ring_tx_data *txdata, *txdata2;
int min_ring_id = wil_get_min_tx_ring_id(wil);

@@ -2247,8 +2244,8 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = vif_to_wil(vif);
- struct ethhdr *eth = (void *)skb->data;
- bool bcast = is_multicast_ether_addr(eth->h_dest);
+ const u8 *da = wil_skb_get_da(skb);
+ bool bcast = is_multicast_ether_addr(da);
struct wil_ring *ring;
static bool pr_once_fw;
int rc;
@@ -2295,7 +2292,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ring = wil_find_tx_ucast(wil, vif, skb);
}
if (unlikely(!ring)) {
- wil_dbg_txrx(wil, "No Tx RING found for %pM\n", eth->h_dest);
+ wil_dbg_txrx(wil, "No Tx RING found for %pM\n", da);
goto drop;
}
/* set up vring entry */
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index b8869db..4d9014a 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -567,11 +567,25 @@ static inline int wil_ring_is_full(struct wil_ring *ring)
return wil_ring_next_tail(ring) == ring->swhead;
}

-static inline bool wil_need_txstat(struct sk_buff *skb)
+static inline u8 *wil_skb_get_da(struct sk_buff *skb)
+{
+ struct ethhdr *eth = (void *)skb->data;
+
+ return eth->h_dest;
+}
+
+static inline u8 *wil_skb_get_sa(struct sk_buff *skb)
{
struct ethhdr *eth = (void *)skb->data;

- return is_unicast_ether_addr(eth->h_dest) && skb->sk &&
+ return eth->h_source;
+}
+
+static inline bool wil_need_txstat(struct sk_buff *skb)
+{
+ const u8 *da = wil_skb_get_da(skb);
+
+ return is_unicast_ether_addr(da) && skb->sk &&
(skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS);
}

--
1.9.1


2018-12-02 09:43:52

by Maya Erez

[permalink] [raw]
Subject: [PATCH 08/12] wil6210: fix invalid sta statistics update

From: Dedy Lansky <[email protected]>

Upon status ring handling, in case there are both unicast and
multicast (cid == max) status messages to handle, wrong sta statistics
might get updated.
Fix this by setting stats to NULL upon invalid cid
(e.g. == max_assoc_sta).

Signed-off-by: Dedy Lansky <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/txrx_edma.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index ac03526..abcf6dd 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -1137,7 +1137,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
/* Total number of completed descriptors in all descriptor rings */
int desc_cnt = 0;
int cid;
- struct wil_net_stats *stats = NULL;
+ struct wil_net_stats *stats;
struct wil_tx_enhanced_desc *_d;
unsigned int ring_id;
unsigned int num_descs;
@@ -1187,8 +1187,8 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
ndev = vif_to_ndev(vif);

cid = wil->ring2cid_tid[ring_id][0];
- if (cid < wil->config.max_assoc_sta)
- stats = &wil->sta[cid].stats;
+ stats = (cid < wil->config.max_assoc_sta ?
+ &wil->sta[cid].stats : NULL);

wil_dbg_txrx(wil,
"tx_status: completed desc_ring (%d), num_descs (%d)\n",
--
1.9.1


2018-12-02 09:43:53

by Maya Erez

[permalink] [raw]
Subject: [PATCH 06/12] wil6210: support up to 20 stations in AP mode

From: Ahmad Masri <[email protected]>

New FW added support for upto 20 clients in AP mode. Change the driver
to support this as well. FW reports it's max supported associations in
WMI_READY_EVENT. Some WMI commands/events use cidxtid field which is
limited to 16 cids. Use new cid/tid fields instead.

For Rx packets cid from rx descriptor is limited to 3 bits (0..7),
to find the real cid, compare transmitter address with the stored
stations mac address in the driver sta array.

EDMA FW still supports 8 stations. Extending the support to 20
stations will come later.

Signed-off-by: Ahmad Masri <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 10 +-
drivers/net/wireless/ath/wil6210/debugfs.c | 20 ++--
drivers/net/wireless/ath/wil6210/main.c | 8 +-
drivers/net/wireless/ath/wil6210/netdev.c | 4 +-
drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 +-
drivers/net/wireless/ath/wil6210/trace.h | 2 +-
drivers/net/wireless/ath/wil6210/txrx.c | 142 ++++++++++++++++++++------
drivers/net/wireless/ath/wil6210/txrx.h | 26 +++++
drivers/net/wireless/ath/wil6210/txrx_edma.c | 6 +-
drivers/net/wireless/ath/wil6210/wil6210.h | 27 ++---
drivers/net/wireless/ath/wil6210/wmi.c | 79 +++++++++++---
11 files changed, 242 insertions(+), 90 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 2e00f10..ad5ac7d 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -391,7 +391,7 @@ static int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx)
{
int i;

- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
if (wil->sta[i].status == wil_sta_unused)
continue;
if (wil->sta[i].mid != mid)
@@ -1778,7 +1778,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,

/* wake default net queue - used mainly for multicast */
if (wil->config.q_per_sta)
- wil_update_cid_net_queues_bh(wil, vif, WIL6210_MAX_CID, false);
+ wil_update_cid_net_queues_bh(wil, vif,
+ wil->config.max_assoc_sta, false);

goto out; /* success */

@@ -1971,7 +1972,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,

/* stop default net queue - used mainly for multicast */
if (wil->config.q_per_sta)
- wil_update_cid_net_queues_bh(wil, vif, WIL6210_MAX_CID, true);
+ wil_update_cid_net_queues_bh(wil, vif,
+ wil->config.max_assoc_sta, true);

if (last)
__wil_down(wil);
@@ -3008,7 +3010,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
wil, vif->mid, WMI_INVALID_RF_SECTOR_INDEX,
sector_type, WIL_CID_ALL);
if (rc == -EINVAL) {
- for (i = 0; i < WIL6210_MAX_CID; i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
if (wil->sta[i].mid != vif->mid)
continue;
rc = wil_rf_sector_wmi_set_selected(
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 20dd4d0..4980678 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -162,7 +162,7 @@ static int wil_ring_debugfs_show(struct seq_file *s, void *data)

snprintf(name, sizeof(name), "tx_%2d", i);

- if (cid < WIL6210_MAX_CID)
+ if (cid < wil->config.max_assoc_sta)
seq_printf(s,
"\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
wil->sta[cid].addr, cid, tid,
@@ -836,14 +836,14 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
"BACK: del_rx require at least 2 params\n");
return -EINVAL;
}
- if (p1 < 0 || p1 >= WIL6210_MAX_CID) {
+ if (p1 < 0 || p1 >= wil->config.max_assoc_sta) {
wil_err(wil, "BACK: invalid CID %d\n", p1);
return -EINVAL;
}
if (rc < 4)
p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
sta = &wil->sta[p1];
- wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3);
+ wmi_delba_rx(wil, sta->mid, p1, p2, p3);
} else {
wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
return -EINVAL;
@@ -1322,7 +1322,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)

memset(&reply, 0, sizeof(reply));

- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
u32 status;

cmd.cid = i;
@@ -1452,7 +1452,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
if (!sinfo)
return -ENOMEM;

- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
struct wil6210_vif *vif;
@@ -1676,7 +1676,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
struct wil6210_priv *wil = s->private;
int i, tid, mcs;

- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
u8 aid = 0;
@@ -1807,7 +1807,7 @@ static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data)
struct wil6210_priv *wil = s->private;
int i, bin;

- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
u8 aid = 0;
@@ -1896,7 +1896,7 @@ static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf,
size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;

wil->tx_latency_res = val;
- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
struct wil_sta_info *sta = &wil->sta[i];

kfree(sta->tx_latency_bins);
@@ -1981,7 +1981,7 @@ static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
}

seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
if (wil->sta[i].status == wil_sta_unused)
continue;
if (wil->sta[i].mid != vif->mid)
@@ -2595,7 +2595,7 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
wil->debug = NULL;

kfree(wil->dbg_data.data_arr);
- for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
+ for (i = 0; i < wil->config.max_assoc_sta; i++)
kfree(wil->sta[i].tx_latency_bins);

/* free pmc memory without sending command to fw, as it will
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index c02526c..14c908f 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -174,7 +174,7 @@ static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
{
int i;

- for (i = 0; i < WIL6210_MAX_CID; i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
if (wil->sta[i].mid == mid &&
wil->sta[i].status == wil_sta_connected)
return true;
@@ -280,7 +280,7 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
wil_disconnect_cid_complete(vif, cid, reason_code);
} else { /* all */
wil_dbg_misc(wil, "Disconnect complete all\n");
- for (cid = 0; cid < WIL6210_MAX_CID; cid++)
+ for (cid = 0; cid < wil->config.max_assoc_sta; cid++)
wil_disconnect_cid_complete(vif, cid, reason_code);
}

@@ -397,7 +397,7 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
wil_disconnect_cid(vif, cid, reason_code);
} else { /* all */
wil_dbg_misc(wil, "Disconnect all\n");
- for (cid = 0; cid < WIL6210_MAX_CID; cid++)
+ for (cid = 0; cid < wil->config.max_assoc_sta; cid++)
wil_disconnect_cid(vif, cid, reason_code);
}

@@ -1877,7 +1877,7 @@ int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac)
int i;
int rc = -ENOENT;

- for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ for (i = 0; i < wil->config.max_assoc_sta; i++) {
if (wil->sta[i].mid == mid &&
wil->sta[i].status != wil_sta_unused &&
ether_addr_equal(wil->sta[i].addr, mac)) {
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index b617059..74e90a3 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -132,13 +132,13 @@ static u16 wil_select_queue(struct net_device *ndev,

mcast = is_multicast_ether_addr(eth->h_dest);
if (mcast) {
- qid = WIL6210_MAX_CID;
+ qid = wil->config.max_assoc_sta;
} else {
qid = wil_find_cid(wil, vif->mid, eth->h_dest);

/* the MCAST queues also used as default queues */
if (qid < 0)
- qid = WIL6210_MAX_CID;
+ qid = wil->config.max_assoc_sta;
}

out:
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 983bd00..a826902 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -307,8 +307,8 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
}

/* Block Ack - Rx side (recipient) */
-int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
- u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
+ u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
@@ -316,7 +316,6 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
u16 agg_timeout = le16_to_cpu(ba_timeout);
u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl);
struct wil_sta_info *sta;
- u8 cid, tid;
u16 agg_wsize = 0;
/* bit 0: A-MSDU supported
* bit 1: policy (should be 0 for us)
@@ -335,10 +334,9 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
int rc = 0;

might_sleep();
- parse_cidxtid(cidxtid, &cid, &tid);

/* sanity checks */
- if (cid >= WIL6210_MAX_CID) {
+ if (cid >= wil->config.max_assoc_sta) {
wil_err(wil, "BACK: invalid CID %d\n", cid);
rc = -EINVAL;
goto out;
diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h
index 853abc3..381775a 100644
--- a/drivers/net/wireless/ath/wil6210/trace.h
+++ b/drivers/net/wireless/ath/wil6210/trace.h
@@ -181,7 +181,7 @@
__entry->seq = wil_rxdesc_seq(d);
__entry->mcs = wil_rxdesc_mcs(d);
),
- TP_printk("index %d len %d mid %d cid %d tid %d mcs %d seq 0x%03x"
+ TP_printk("index %d len %d mid %d cid (%%8) %d tid %d mcs %d seq 0x%03x"
" type 0x%1x subtype 0x%1x", __entry->index, __entry->len,
__entry->mid, __entry->cid, __entry->tid, __entry->mcs,
__entry->seq, __entry->type, __entry->subtype)
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 1e715ba..471f85e 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -362,6 +362,79 @@ static bool wil_is_rx_idle(struct wil6210_priv *wil)
return true;
}

+static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb)
+{
+ struct vring_rx_desc *d = wil_skb_rxdesc(skb);
+ int mid = wil_rxdesc_mid(d);
+ struct wil6210_vif *vif = wil->vifs[mid];
+ /* cid from DMA descriptor is limited to 3 bits.
+ * In case of cid>=8, the value would be cid modulo 8 and we need to
+ * find real cid by locating the transmitter (ta) inside sta array
+ */
+ int cid = wil_rxdesc_cid(d);
+ unsigned int snaplen = wil_rx_snaplen(wil);
+ struct ethhdr *eth;
+ struct ieee80211_hdr_3addr *hdr;
+ int i;
+ unsigned char *ta;
+ u8 ftype;
+
+ /* in monitor mode there are no connections */
+ if (vif->wdev.iftype == NL80211_IFTYPE_MONITOR)
+ return cid;
+
+ ftype = wil_rxdesc_ftype(d) << 2;
+ if (likely(ftype == IEEE80211_FTYPE_DATA)) {
+ if (unlikely(skb->len < ETH_HLEN + snaplen)) {
+ wil_err_ratelimited(wil,
+ "Short data frame, len = %d\n",
+ skb->len);
+ return -ENOENT;
+ }
+ eth = (void *)skb->data;
+ ta = eth->h_source;
+ } else {
+ if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) {
+ wil_err_ratelimited(wil, "Short frame, len = %d\n",
+ skb->len);
+ return -ENOENT;
+ }
+ hdr = (void *)skb->data;
+ ta = hdr->addr2;
+ }
+
+ if (wil->config.max_assoc_sta <= WIL6210_RX_DESC_MAX_CID)
+ return cid;
+
+ /* assuming no concurrency between AP interfaces and STA interfaces.
+ * multista is used only in P2P_GO or AP mode. In other modes return
+ * cid from the rx descriptor
+ */
+ if (vif->wdev.iftype != NL80211_IFTYPE_P2P_GO &&
+ vif->wdev.iftype != NL80211_IFTYPE_AP)
+ return cid;
+
+ /* For Rx packets cid from rx descriptor is limited to 3 bits (0..7),
+ * to find the real cid, compare transmitter address with the stored
+ * stations mac address in the driver sta array
+ */
+ for (i = cid; i < wil->config.max_assoc_sta;
+ i += WIL6210_RX_DESC_MAX_CID) {
+ if (wil->sta[i].status != wil_sta_unused &&
+ ether_addr_equal(wil->sta[i].addr, ta)) {
+ cid = i;
+ break;
+ }
+ }
+ if (i >= wil->config.max_assoc_sta) {
+ wil_err_ratelimited(wil, "Could not find cid for frame with transmit addr = %pM, iftype = %d, frametype = %d, len = %d\n",
+ ta, vif->wdev.iftype, ftype, skb->len);
+ cid = -ENOENT;
+ }
+
+ return cid;
+}
+
/**
* reap 1 frame from @swhead
*
@@ -387,7 +460,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
int i;
struct wil_net_stats *stats;

- BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
+ BUILD_BUG_ON(sizeof(struct skb_rx_info) > sizeof(skb->cb));

again:
if (unlikely(wil_ring_is_empty(vring)))
@@ -419,7 +492,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
wil_hex_dump_txrx("RxD ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);

- cid = wil_rxdesc_cid(d);
mid = wil_rxdesc_mid(d);
vif = wil->vifs[mid];

@@ -430,11 +502,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
goto again;
}
ndev = vif_to_ndev(vif);
- stats = &wil->sta[cid].stats;
-
if (unlikely(dmalen > sz)) {
- wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
- stats->rx_large_frame++;
+ wil_err_ratelimited(wil, "Rx size too large: %d bytes!\n",
+ dmalen);
kfree_skb(skb);
goto again;
}
@@ -445,6 +515,14 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);

+ cid = wil_rx_get_cid_by_skb(wil, skb);
+ if (cid == -ENOENT) {
+ kfree_skb(skb);
+ goto again;
+ }
+ wil_skb_set_cid(skb, (u8)cid);
+ stats = &wil->sta[cid].stats;
+
stats->last_mcs_rx = wil_rxdesc_mcs(d);
if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
stats->rx_per_mcs[stats->last_mcs_rx]++;
@@ -491,13 +569,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
goto again;
}

- if (unlikely(skb->len < ETH_HLEN + snaplen)) {
- wil_err(wil, "Short frame, len = %d\n", skb->len);
- stats->rx_short_frame++;
- kfree_skb(skb);
- goto again;
- }
-
/* L4 IDENT is on when HW calculated checksum, check status
* and in case of error drop the packet
* higher stack layers will handle retransmission (if required)
@@ -594,7 +665,7 @@ int reverse_memcmp(const void *cs, const void *ct, size_t count)
static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
{
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
- int cid = wil_rxdesc_cid(d);
+ int cid = wil_skb_get_cid(skb);
int tid = wil_rxdesc_tid(d);
int key_id = wil_rxdesc_key_id(d);
int mc = wil_rxdesc_mcast(d);
@@ -642,7 +713,7 @@ static void wil_get_netif_rx_params(struct sk_buff *skb, int *cid,
{
struct vring_rx_desc *d = wil_skb_rxdesc(skb);

- *cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
+ *cid = wil_skb_get_cid(skb);
*security = wil_rxdesc_security(d);
}

@@ -909,7 +980,6 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
.ring_size = cpu_to_le16(size),
},
.ringid = id,
- .cidxtid = mk_cidxtid(cid, tid),
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
.mac_ctrl = 0,
.to_resolution = 0,
@@ -929,6 +999,14 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
struct wil_ring *vring = &wil->ring_tx[id];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[id];

+ if (cid >= WIL6210_RX_DESC_MAX_CID) {
+ cmd.vring_cfg.cidxtid = CIDXTID_EXTENDED_CID_TID;
+ cmd.vring_cfg.cid = cid;
+ cmd.vring_cfg.tid = tid;
+ } else {
+ cmd.vring_cfg.cidxtid = mk_cidxtid(cid, tid);
+ }
+
wil_dbg_misc(wil, "vring_init_tx: max_mpdu_size %d\n",
cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
lockdep_assert_held(&wil->mutex);
@@ -981,7 +1059,7 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
wil_vring_free(wil, vring);
- wil->ring2cid_tid[id][0] = WIL6210_MAX_CID;
+ wil->ring2cid_tid[id][0] = wil->config.max_assoc_sta;
wil->ring2cid_tid[id][1] = 0;

out:
@@ -1066,7 +1144,7 @@ static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
txdata->dot1x_open = false;
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
- wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
+ wil->ring2cid_tid[ring_id][0] = wil->config.max_assoc_sta;
wil->ring2cid_tid[ring_id][1] = 0;
return rc;
}
@@ -1113,7 +1191,7 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
if (rc)
goto out;

- wil->ring2cid_tid[id][0] = WIL6210_MAX_CID; /* CID */
+ wil->ring2cid_tid[id][0] = wil->config.max_assoc_sta; /* CID */
wil->ring2cid_tid[id][1] = 0; /* TID */

cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
@@ -1169,7 +1247,7 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil,
else
cid = wil_find_cid(wil, vif->mid, eth->h_dest);

- if (cid < 0 || cid >= WIL6210_MAX_CID)
+ if (cid < 0 || cid >= wil->config.max_assoc_sta)
return NULL;

/* TODO: fix for multiple TID */
@@ -1221,7 +1299,7 @@ static struct wil_ring *wil_find_tx_ring_sta(struct wil6210_priv *wil,
continue;

cid = wil->ring2cid_tid[i][0];
- if (cid >= WIL6210_MAX_CID) /* skip BCAST */
+ if (cid >= wil->config.max_assoc_sta) /* skip BCAST */
continue;

if (!wil->ring_tx_data[i].dot1x_open &&
@@ -1300,7 +1378,7 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
continue;

cid = wil->ring2cid_tid[i][0];
- if (cid >= WIL6210_MAX_CID) /* skip BCAST */
+ if (cid >= wil->config.max_assoc_sta) /* skip BCAST */
continue;
if (!wil->ring_tx_data[i].dot1x_open &&
skb->protocol != cpu_to_be16(ETH_P_PAE))
@@ -1328,7 +1406,7 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
if (!v2->va || txdata2->mid != vif->mid)
continue;
cid = wil->ring2cid_tid[i][0];
- if (cid >= WIL6210_MAX_CID) /* skip BCAST */
+ if (cid >= wil->config.max_assoc_sta) /* skip BCAST */
continue;
if (!wil->ring_tx_data[i].dot1x_open &&
skb->protocol != cpu_to_be16(ETH_P_PAE))
@@ -1952,7 +2030,7 @@ static int wil_get_cid_by_ring(struct wil6210_priv *wil,
if (unlikely(ring_index < 0 || ring_index >= WIL6210_MAX_TX_RINGS)) {
wil_err(wil, "cid by ring 0x%p: invalid ring index %d\n",
ring, ring_index);
- return WIL6210_MAX_CID;
+ return wil->config.max_assoc_sta;
}

return wil->ring2cid_tid[ring_index][0];
@@ -1976,7 +2054,7 @@ static void wil_tx_stop_cid_queues(struct wil6210_priv *wil,

netif_tx_stop_queue(txq);
}
- if (cid < WIL6210_MAX_CID)
+ if (cid < wil->config.max_assoc_sta)
wil->sta[cid].net_queue_stopped = true;
}

@@ -1998,7 +2076,7 @@ static void wil_tx_wake_cid_queues(struct wil6210_priv *wil,

netif_tx_wake_queue(txq);
}
- if (cid < WIL6210_MAX_CID)
+ if (cid < wil->config.max_assoc_sta)
wil->sta[cid].net_queue_stopped = false;
}

@@ -2011,7 +2089,7 @@ static inline void __wil_update_net_queues_per_sta(struct wil6210_priv *wil,

/* ring is not null - checked by caller */
cid = wil_get_cid_by_ring(wil, vif, ring);
- if (cid < WIL6210_MAX_CID &&
+ if (cid < wil->config.max_assoc_sta &&
check_stop == wil->sta[cid].net_queue_stopped)
/* net queues already in desired state */
return;
@@ -2083,7 +2161,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
netif_tx_stop_all_queues(vif_to_ndev(vif));
vif->net_queue_stopped = true;
if (WIL_Q_PER_STA_USED(vif))
- for (i = 0; i < WIL6210_MAX_CID; i++)
+ for (i = 0; i < wil->config.max_assoc_sta; i++)
wil->sta[i].net_queue_stopped = true;
wil_dbg_txrx(wil, "netif_tx_stop called\n");
}
@@ -2117,7 +2195,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
netif_tx_wake_all_queues(vif_to_ndev(vif));
vif->net_queue_stopped = false;
if (WIL_Q_PER_STA_USED(vif))
- for (i = 0; i < WIL6210_MAX_CID; i++)
+ for (i = 0; i < wil->config.max_assoc_sta; i++)
wil->sta[i].net_queue_stopped = false;
}
}
@@ -2152,7 +2230,7 @@ void wil_update_cid_net_queues_bh(struct wil6210_priv *wil,
return;
}

- if (cid < WIL6210_MAX_CID &&
+ if (cid < wil->config.max_assoc_sta &&
should_stop == wil->sta[cid].net_queue_stopped)
/* net queues already in desired state */
return;
@@ -2304,7 +2382,7 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid)

used_before_complete = wil_ring_used_tx(vring);

- if (cid < WIL6210_MAX_CID)
+ if (cid < wil->config.max_assoc_sta)
stats = &wil->sta[cid].stats;

while (!wil_ring_is_empty(vring)) {
@@ -2413,7 +2491,7 @@ static void wil_get_reorder_params(struct wil6210_priv *wil,
struct vring_rx_desc *d = wil_skb_rxdesc(skb);

*tid = wil_rxdesc_tid(d);
- *cid = wil_rxdesc_cid(d);
+ *cid = wil_skb_get_cid(skb);
*mid = wil_rxdesc_mid(d);
*seq = wil_rxdesc_seq(d);
*mcast = wil_rxdesc_mcast(d);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 69e3bb9..b8869db 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -458,6 +458,18 @@ struct vring_rx_desc {
union wil_rx_desc rx;
} __packed;

+struct packet_rx_info {
+ u8 cid;
+};
+
+/* this struct will be stored in the skb cb buffer
+ * max length of the struct is limited to 48 bytes
+ */
+struct skb_rx_info {
+ struct vring_rx_desc rx_desc;
+ struct packet_rx_info rx_info;
+};
+
static inline int wil_rxdesc_tid(struct vring_rx_desc *d)
{
return WIL_GET_BITS(d->mac.d0, 0, 3);
@@ -605,6 +617,20 @@ static inline bool wil_val_in_range(int val, int min, int max)
return val >= min && val < max;
}

+static inline u8 wil_skb_get_cid(struct sk_buff *skb)
+{
+ struct skb_rx_info *skb_rx_info = (void *)skb->cb;
+
+ return skb_rx_info->rx_info.cid;
+}
+
+static inline void wil_skb_set_cid(struct sk_buff *skb, u8 cid)
+{
+ struct skb_rx_info *skb_rx_info = (void *)skb->cb;
+
+ skb_rx_info->rx_info.cid = cid;
+}
+
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index 4b0c9f8..ac03526 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -727,7 +727,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
wil_ring_free_edma(wil, ring);
- wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
+ wil->ring2cid_tid[ring_id][0] = wil->config.max_assoc_sta;
wil->ring2cid_tid[ring_id][1] = 0;

out:
@@ -932,7 +932,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
eop = wil_rx_status_get_eop(msg);

cid = wil_rx_status_get_cid(msg);
- if (unlikely(!wil_val_in_range(cid, 0, WIL6210_MAX_CID))) {
+ if (unlikely(!wil_val_in_range(cid, 0, wil->config.max_assoc_sta))) {
wil_err(wil, "Corrupt cid=%d, sring->swhead=%d\n",
cid, sring->swhead);
rxdata->skipping = true;
@@ -1187,7 +1187,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
ndev = vif_to_ndev(vif);

cid = wil->ring2cid_tid[ring_id][0];
- if (cid < WIL6210_MAX_CID)
+ if (cid < wil->config.max_assoc_sta)
stats = &wil->sta[cid].stats;

wil_dbg_txrx(wil,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 6bd5198..d614f57 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -87,7 +87,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL_RING_SIZE_ORDER_MIN (5)
#define WIL_RING_SIZE_ORDER_MAX (15)
#define WIL6210_MAX_TX_RINGS (24) /* HW limit */
-#define WIL6210_MAX_CID (8) /* HW limit */
+#define WIL6210_MAX_CID (20) /* max number of stations */
+#define WIL6210_RX_DESC_MAX_CID (8) /* HW limit */
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */
#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */
@@ -448,15 +449,6 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid)
*tid = (cidxtid >> 4) & 0xf;
}

-/**
- * wil_cid_valid - check cid is valid
- * @cid: CID value
- */
-static inline bool wil_cid_valid(u8 cid)
-{
- return cid < WIL6210_MAX_CID;
-}
-
struct wil6210_mbox_ring {
u32 base;
u16 entry_size; /* max. size of mbox entry, incl. all headers */
@@ -1170,6 +1162,15 @@ void wil_hex_dump_misc(const char *prefix_str, int prefix_type, int rowsize,
}
#endif /* defined(CONFIG_DYNAMIC_DEBUG) */

+/**
+ * wil_cid_valid - check cid is valid
+ * @cid: CID value
+ */
+static inline bool wil_cid_valid(struct wil6210_priv *wil, u8 cid)
+{
+ return (cid >= 0 && cid < wil->config.max_assoc_sta);
+}
+
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count);
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
@@ -1237,7 +1238,7 @@ int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason,
int wmi_addba(struct wil6210_priv *wil, u8 mid,
u8 ringid, u8 size, u16 timeout);
int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason);
-int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason);
+int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u16 reason);
int wmi_addba_rx_resp(struct wil6210_priv *wil,
u8 mid, u8 cid, u8 tid, u8 token,
u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
@@ -1250,8 +1251,8 @@ int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
const u8 *mac, enum nl80211_iftype iftype);
int wmi_port_delete(struct wil6210_priv *wil, u8 mid);
int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval);
-int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
- u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
+ u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl);
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);

diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index d42849f..509a255 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -766,6 +766,7 @@ static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len)
struct wil6210_priv *wil = vif_to_wil(vif);
struct wiphy *wiphy = wil_to_wiphy(wil);
struct wmi_ready_event *evt = d;
+ u8 fw_max_assoc_sta;

wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
wil->fw_version, le32_to_cpu(evt->sw_version),
@@ -783,6 +784,27 @@ static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len)
evt->rfc_read_calib_result);
wil->fw_calib_result = evt->rfc_read_calib_result;
}
+
+ fw_max_assoc_sta = WIL6210_RX_DESC_MAX_CID;
+ if (len > offsetof(struct wmi_ready_event, max_assoc_sta) &&
+ evt->max_assoc_sta > 0) {
+ fw_max_assoc_sta = evt->max_assoc_sta;
+ wil_dbg_wmi(wil, "fw reported max assoc sta %d\n",
+ fw_max_assoc_sta);
+
+ if (fw_max_assoc_sta > WIL6210_MAX_CID) {
+ wil_dbg_wmi(wil,
+ "fw max assoc sta %d exceeds max driver supported %d\n",
+ fw_max_assoc_sta, WIL6210_MAX_CID);
+ fw_max_assoc_sta = WIL6210_MAX_CID;
+ }
+ }
+
+ wil->config.max_assoc_sta = min_t(uint, wil->config.max_assoc_sta,
+ fw_max_assoc_sta);
+ wil_dbg_wmi(wil, "setting max assoc sta to %d\n",
+ wil->config.max_assoc_sta);
+
wil_set_recovery_state(wil, fw_recovery_idle);
set_bit(wil_status_fwready, wil->status);
/* let the reset sequence continue */
@@ -948,7 +970,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
evt->assoc_req_len, evt->assoc_resp_len);
return;
}
- if (evt->cid >= WIL6210_MAX_CID) {
+ if (evt->cid >= wil->config.max_assoc_sta) {
wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
return;
}
@@ -1210,7 +1232,7 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
return;

cid = wil->ring2cid_tid[vri][0];
- if (!wil_cid_valid(cid)) {
+ if (!wil_cid_valid(wil, cid)) {
wil_err(wil, "invalid cid %d for vring %d\n", cid, vri);
return;
}
@@ -1267,9 +1289,16 @@ static void wmi_evt_addba_rx_req(struct wil6210_vif *vif, int id,
void *d, int len)
{
struct wil6210_priv *wil = vif_to_wil(vif);
+ u8 cid, tid;
struct wmi_rcp_addba_req_event *evt = d;

- wil_addba_rx_request(wil, vif->mid, evt->cidxtid, evt->dialog_token,
+ if (evt->cidxtid != CIDXTID_EXTENDED_CID_TID) {
+ parse_cidxtid(evt->cidxtid, &cid, &tid);
+ } else {
+ cid = evt->cid;
+ tid = evt->tid;
+ }
+ wil_addba_rx_request(wil, vif->mid, cid, tid, evt->dialog_token,
evt->ba_param_set, evt->ba_timeout,
evt->ba_seq_ctrl);
}
@@ -1285,7 +1314,13 @@ static void wmi_evt_delba(struct wil6210_vif *vif, int id, void *d, int len)
struct wil_tid_ampdu_rx *r;

might_sleep();
- parse_cidxtid(evt->cidxtid, &cid, &tid);
+
+ if (evt->cidxtid != CIDXTID_EXTENDED_CID_TID) {
+ parse_cidxtid(evt->cidxtid, &cid, &tid);
+ } else {
+ cid = evt->cid;
+ tid = evt->tid;
+ }
wil_dbg_wmi(wil, "DELBA MID %d CID %d TID %d from %s reason %d\n",
vif->mid, cid, tid,
evt->from_initiator ? "originator" : "recipient",
@@ -1400,7 +1435,7 @@ static void wil_link_stats_store_basic(struct wil6210_vif *vif,
u8 cid = basic->cid;
struct wil_sta_info *sta;

- if (cid < 0 || cid >= WIL6210_MAX_CID) {
+ if (cid < 0 || cid >= wil->config.max_assoc_sta) {
wil_err(wil, "invalid cid %d\n", cid);
return;
}
@@ -1550,7 +1585,7 @@ static int wil_find_cid_ringid_sta(struct wil6210_priv *wil,
continue;

lcid = wil->ring2cid_tid[i][0];
- if (lcid >= WIL6210_MAX_CID) /* skip BCAST */
+ if (lcid >= wil->config.max_assoc_sta) /* skip BCAST */
continue;

wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid);
@@ -2116,11 +2151,9 @@ int wmi_pcp_start(struct wil6210_vif *vif,

if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
(cmd.pcp_max_assoc_sta <= 0)) {
- wil_info(wil,
- "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
- wil->config.max_assoc_sta, WIL6210_MAX_CID,
- WIL6210_MAX_CID);
- cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
+ wil_err(wil, "unexpected max_assoc_sta %d\n",
+ cmd.pcp_max_assoc_sta);
+ return -EOPNOTSUPP;
}

if (wil->config.disable_ap_sme &&
@@ -2648,15 +2681,22 @@ int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason)
return wmi_send(wil, WMI_RING_BA_DIS_CMDID, mid, &cmd, sizeof(cmd));
}

-int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason)
+int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u16 reason)
{
struct wmi_rcp_delba_cmd cmd = {
- .cidxtid = cidxtid,
.reason = cpu_to_le16(reason),
};

- wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
- (cidxtid >> 4) & 0xf, reason);
+ if (cid >= WIL6210_RX_DESC_MAX_CID) {
+ cmd.cidxtid = CIDXTID_EXTENDED_CID_TID;
+ cmd.cid = cid;
+ cmd.tid = tid;
+ } else {
+ cmd.cidxtid = mk_cidxtid(cid, tid);
+ }
+
+ wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cid,
+ tid, reason);

return wmi_send(wil, WMI_RCP_DELBA_CMDID, mid, &cmd, sizeof(cmd));
}
@@ -2667,7 +2707,6 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil,
{
int rc;
struct wmi_rcp_addba_resp_cmd cmd = {
- .cidxtid = mk_cidxtid(cid, tid),
.dialog_token = token,
.status_code = cpu_to_le16(status),
/* bit 0: A-MSDU supported
@@ -2686,6 +2725,14 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil,
.evt = {.status = cpu_to_le16(WMI_FW_STATUS_FAILURE)},
};

+ if (cid >= WIL6210_RX_DESC_MAX_CID) {
+ cmd.cidxtid = CIDXTID_EXTENDED_CID_TID;
+ cmd.cid = cid;
+ cmd.tid = tid;
+ } else {
+ cmd.cidxtid = mk_cidxtid(cid, tid);
+ }
+
wil_dbg_wmi(wil,
"ADDBA response for MID %d CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
mid, cid, tid, agg_wsize,
--
1.9.1


2018-12-02 09:43:53

by Maya Erez

[permalink] [raw]
Subject: [PATCH 10/12] wil6210: check null pointer in _wil_cfg80211_merge_extra_ies

From: Alexei Avshalom Lazar <[email protected]>

ies1 or ies2 might be null when code inside
_wil_cfg80211_merge_extra_ies access them.
Add explicit check for null and make sure ies1/ies2 are not accessed in
such a case.
spos might be null and be accessed inside _wil_cfg80211_merge_extra_ies.
Add explicit check for null in the while condition statement and make
sure spos is not accessed in such a case.

Signed-off-by: Alexei Avshalom Lazar <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index ad5ac7d..f3fa1a0 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1576,6 +1576,12 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
u8 *buf, *dpos;
const u8 *spos;

+ if (!ies1)
+ ies1_len = 0;
+
+ if (!ies2)
+ ies2_len = 0;
+
if (ies1_len == 0 && ies2_len == 0) {
*merged_ies = NULL;
*merged_len = 0;
@@ -1585,17 +1591,19 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
buf = kmalloc(ies1_len + ies2_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy(buf, ies1, ies1_len);
+ if (ies1)
+ memcpy(buf, ies1, ies1_len);
dpos = buf + ies1_len;
spos = ies2;
- while (spos + 1 < ies2 + ies2_len) {
+ while (spos && (spos + 1 < ies2 + ies2_len)) {
/* IE tag at offset 0, length at offset 1 */
u16 ielen = 2 + spos[1];

if (spos + ielen > ies2 + ies2_len)
break;
if (spos[0] == WLAN_EID_VENDOR_SPECIFIC &&
- !_wil_cfg80211_find_ie(ies1, ies1_len, spos, ielen)) {
+ (!ies1 || !_wil_cfg80211_find_ie(ies1, ies1_len,
+ spos, ielen))) {
memcpy(dpos, spos, ielen);
dpos += ielen;
}
--
1.9.1


2018-12-02 09:43:56

by Maya Erez

[permalink] [raw]
Subject: [PATCH 12/12] wil6210: prevent device memory access while in reset or suspend

From: Ahmad Masri <[email protected]>

Accessing some of the memory of the device while the device is
resetting or suspending may cause unexpected error as the HW is still
not in a stable state. Prevent this access to guarantee successful
read/write memory operations.

Signed-off-by: Ahmad Masri <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/debugfs.c | 26 +++++++++++---
drivers/net/wireless/ath/wil6210/main.c | 41 +++++++++++++++++------
drivers/net/wireless/ath/wil6210/pm.c | 27 +++++++++------
drivers/net/wireless/ath/wil6210/wil6210.h | 5 ++-
drivers/net/wireless/ath/wil6210/wil_crash_dump.c | 16 +++------
5 files changed, 79 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 4980678..3373e54 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -280,6 +280,11 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,

wil_halp_vote(wil);

+ if (wil_mem_access_lock(wil)) {
+ wil_halp_unvote(wil);
+ return;
+ }
+
wil_memcpy_fromio_32(&r, off, sizeof(r));
wil_mbox_ring_le2cpus(&r);
/*
@@ -345,6 +350,7 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
}
out:
seq_puts(s, "}\n");
+ wil_mem_access_unlock(wil);
wil_halp_unvote(wil);
}

@@ -634,6 +640,12 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data)
if (ret < 0)
return ret;

+ ret = wil_mem_access_lock(wil);
+ if (ret) {
+ wil_pm_runtime_put(wil);
+ return ret;
+ }
+
a = wmi_buffer(wil, cpu_to_le32(mem_addr));

if (a)
@@ -641,6 +653,8 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data)
else
seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);

+ wil_mem_access_unlock(wil);
+
wil_pm_runtime_put(wil);

return 0;
@@ -670,10 +684,6 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
size_t unaligned_bytes, aligned_count, ret;
int rc;

- if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
- test_bit(wil_status_suspended, wil_blob->wil->status))
- return 0;
-
if (pos < 0)
return -EINVAL;

@@ -700,11 +710,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
return rc;
}

+ rc = wil_mem_access_lock(wil);
+ if (rc) {
+ kfree(buf);
+ wil_pm_runtime_put(wil);
+ return rc;
+ }
+
wil_memcpy_fromio_32(buf, (const void __iomem *)
wil_blob->blob.data + aligned_pos, aligned_count);

ret = copy_to_user(user_buf, buf + unaligned_bytes, count);

+ wil_mem_access_unlock(wil);
wil_pm_runtime_put(wil);

kfree(buf);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 524e0ef..cb97766 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -139,6 +139,28 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
}
}

+/* Device memory access is prohibited while reset or suspend.
+ * wil_mem_access_lock protects accessing device memory in these cases
+ */
+int wil_mem_access_lock(struct wil6210_priv *wil)
+{
+ if (!down_read_trylock(&wil->mem_lock))
+ return -EBUSY;
+
+ if (test_bit(wil_status_suspending, wil->status) ||
+ test_bit(wil_status_suspended, wil->status)) {
+ up_read(&wil->mem_lock);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+void wil_mem_access_unlock(struct wil6210_priv *wil)
+{
+ up_read(&wil->mem_lock);
+}
+
static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
{
struct wil_ring *ring = &wil->ring_tx[id];
@@ -680,6 +702,7 @@ int wil_priv_init(struct wil6210_priv *wil)
spin_lock_init(&wil->wmi_ev_lock);
spin_lock_init(&wil->net_queue_lock);
init_waitqueue_head(&wil->wq);
+ init_rwsem(&wil->mem_lock);

wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
if (!wil->wmi_wq)
@@ -1579,15 +1602,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
}

set_bit(wil_status_resetting, wil->status);
- if (test_bit(wil_status_collecting_dumps, wil->status)) {
- /* Device collects crash dump, cancel the reset.
- * following crash dump collection, reset would take place.
- */
- wil_dbg_misc(wil, "reject reset while collecting crash dump\n");
- rc = -EBUSY;
- goto out;
- }
-
mutex_lock(&wil->vif_mutex);
wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex);
@@ -1762,7 +1776,9 @@ int __wil_up(struct wil6210_priv *wil)

WARN_ON(!mutex_is_locked(&wil->mutex));

+ down_write(&wil->mem_lock);
rc = wil_reset(wil, true);
+ up_write(&wil->mem_lock);
if (rc)
return rc;

@@ -1836,6 +1852,7 @@ int wil_up(struct wil6210_priv *wil)

int __wil_down(struct wil6210_priv *wil)
{
+ int rc;
WARN_ON(!mutex_is_locked(&wil->mutex));

set_bit(wil_status_resetting, wil->status);
@@ -1855,7 +1872,11 @@ int __wil_down(struct wil6210_priv *wil)
wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex);

- return wil_reset(wil, false);
+ down_write(&wil->mem_lock);
+ rc = wil_reset(wil, false);
+ up_write(&wil->mem_lock);
+
+ return rc;
}

int wil_down(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 14fd635..fe559e1 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -195,14 +195,18 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
wil_dbg_pm(wil, "suspend keep radio on\n");

/* Prevent handling of new tx and wmi commands */
- set_bit(wil_status_suspending, wil->status);
- if (test_bit(wil_status_collecting_dumps, wil->status)) {
- /* Device collects crash dump, cancel the suspend */
- wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
- clear_bit(wil_status_suspending, wil->status);
+ rc = down_write_trylock(&wil->mem_lock);
+ if (!rc) {
+ wil_err(wil,
+ "device is busy. down_write_trylock failed, returned (0x%x)\n",
+ rc);
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}
+
+ set_bit(wil_status_suspending, wil->status);
+ up_write(&wil->mem_lock);
+
wil_pm_stop_all_net_queues(wil);

if (!wil_is_tx_idle(wil)) {
@@ -310,15 +314,18 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)

wil_dbg_pm(wil, "suspend radio off\n");

- set_bit(wil_status_suspending, wil->status);
- if (test_bit(wil_status_collecting_dumps, wil->status)) {
- /* Device collects crash dump, cancel the suspend */
- wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
- clear_bit(wil_status_suspending, wil->status);
+ rc = down_write_trylock(&wil->mem_lock);
+ if (!rc) {
+ wil_err(wil,
+ "device is busy. down_write_trylock failed, returned (0x%x)\n",
+ rc);
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}

+ set_bit(wil_status_suspending, wil->status);
+ up_write(&wil->mem_lock);
+
/* if netif up, hardware is alive, shut it down */
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index f9eacfd..0eda63f 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -646,7 +646,6 @@ enum { /* for wil6210_priv.status */
wil_status_suspending, /* suspend in progress */
wil_status_suspended, /* suspend completed, device is suspended */
wil_status_resuming, /* resume in progress */
- wil_status_collecting_dumps, /* crashdump collection in progress */
wil_status_last /* keep last */
};

@@ -979,6 +978,8 @@ struct wil6210_priv {
struct wil_txrx_ops txrx_ops;

struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
+ /* for synchronizing device memory access while reset or suspend */
+ struct rw_semaphore mem_lock;
/* statistics */
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */
@@ -1176,6 +1177,8 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count);
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count);
+int wil_mem_access_lock(struct wil6210_priv *wil);
+void wil_mem_access_unlock(struct wil6210_priv *wil);

struct wil6210_vif *
wil_vif_alloc(struct wil6210_priv *wil, const char *name,
diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
index dc33a0b..f1e1a39 100644
--- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
+++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
@@ -57,7 +57,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,

int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
{
- int i;
+ int i, rc;
const struct fw_map *map;
void *data;
u32 host_min, dump_size, offset, len;
@@ -73,14 +73,9 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
return -EINVAL;
}

- set_bit(wil_status_collecting_dumps, wil->status);
- if (test_bit(wil_status_suspending, wil->status) ||
- test_bit(wil_status_suspended, wil->status) ||
- test_bit(wil_status_resetting, wil->status)) {
- wil_err(wil, "cannot collect fw dump during suspend/reset\n");
- clear_bit(wil_status_collecting_dumps, wil->status);
- return -EINVAL;
- }
+ rc = wil_mem_access_lock(wil);
+ if (rc)
+ return rc;

/* copy to crash dump area */
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
@@ -100,8 +95,7 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
wil_memcpy_fromio_32((void * __force)(dest + offset),
(const void __iomem * __force)data, len);
}
-
- clear_bit(wil_status_collecting_dumps, wil->status);
+ wil_mem_access_unlock(wil);

return 0;
}
--
1.9.1


2018-12-02 09:43:57

by Maya Erez

[permalink] [raw]
Subject: [PATCH 09/12] wil6210: ignore HALP ICR if already handled

HALP ICR is set as long as the FW should stay awake.
To prevent its multiple handling the driver masks this IRQ bit.
However, if there is a different MISC ICR before the driver clears
this bit, there is a risk of race condition between HALP mask and
unmask. This race leads to HALP timeout, in case it is mistakenly
masked.
Add a flag to indicate if HALP ICR should be handled.

Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/interrupt.c | 10 +++++++---
drivers/net/wireless/ath/wil6210/main.c | 3 +++
drivers/net/wireless/ath/wil6210/wil6210.h | 1 +
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 5d287a8..e0eaeea 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -575,10 +575,14 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
}

if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
- wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
- wil6210_mask_halp(wil);
isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
- complete(&wil->halp.comp);
+ if (wil->halp.handle_icr) {
+ /* no need to handle HALP ICRs until next vote */
+ wil->halp.handle_icr = false;
+ wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
+ wil6210_mask_halp(wil);
+ complete(&wil->halp.comp);
+ }
}

wil->isr_misc = isr;
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 14c908f..524e0ef 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1901,11 +1901,14 @@ void wil_halp_vote(struct wil6210_priv *wil)

if (++wil->halp.ref_cnt == 1) {
reinit_completion(&wil->halp.comp);
+ /* mark to IRQ context to handle HALP ICR */
+ wil->halp.handle_icr = true;
wil6210_set_halp(wil);
rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
if (!rc) {
wil_err(wil, "HALP vote timed out\n");
/* Mask HALP as done in case the interrupt is raised */
+ wil->halp.handle_icr = false;
wil6210_mask_halp(wil);
} else {
wil_dbg_irq(wil,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index d614f57..f9eacfd 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -781,6 +781,7 @@ struct wil_halp {
struct mutex lock; /* protect halp ref_cnt */
unsigned int ref_cnt;
struct completion comp;
+ bool handle_icr;
};

struct wil_blob_wrapper {
--
1.9.1


2018-12-02 09:43:54

by Maya Erez

[permalink] [raw]
Subject: [PATCH 11/12] wil6210: align to latest auto generated wmi.h

From: Alexei Avshalom Lazar <[email protected]>

Align to latest version of the auto generated wmi file
describing the interface with FW.

Signed-off-by: Alexei Avshalom Lazar <[email protected]>
Signed-off-by: Maya Erez <[email protected]>
---
drivers/net/wireless/ath/wil6210/wmi.c | 7 +++++
drivers/net/wireless/ath/wil6210/wmi.h | 48 +++++++++++++++++++++++++++++++++-
2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 509a255..88269e3 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -2954,6 +2954,10 @@ static const char *suspend_status2name(u8 status)
switch (status) {
case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
return "LINK_NOT_IDLE";
+ case WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT:
+ return "DISCONNECT";
+ case WMI_TRAFFIC_SUSPEND_REJECTED_OTHER:
+ return "OTHER";
default:
return "Untracked status";
}
@@ -3043,6 +3047,9 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size)

if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
strlcat(string, " WMI_EVT", str_size);
+
+ if (triggers & WMI_RESUME_TRIGGER_DISCONNECT)
+ strlcat(string, " DISCONNECT", str_size);
}

int wmi_resume(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index b668758..cce5270 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1982,6 +1982,7 @@ enum wmi_event_id {
WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
+ WMI_BF_TRIG_EVENTID = 0x183A,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
@@ -2267,7 +2268,9 @@ struct wmi_notify_req_done_event {
__le32 status;
__le64 tsf;
s8 rssi;
- u8 reserved0[3];
+ /* enum wmi_edmg_tx_mode */
+ u8 tx_mode;
+ u8 reserved0[2];
__le32 tx_tpt;
__le32 tx_goodput;
__le32 rx_goodput;
@@ -3168,6 +3171,30 @@ struct wmi_brp_set_ant_limit_event {
u8 reserved[3];
} __packed;

+enum wmi_bf_type {
+ WMI_BF_TYPE_SLS = 0x00,
+ WMI_BF_TYPE_BRP_RX = 0x01,
+};
+
+/* WMI_BF_TRIG_CMDID */
+struct wmi_bf_trig_cmd {
+ /* enum wmi_bf_type - type of requested beamforming */
+ u8 bf_type;
+ /* used only for WMI_BF_TYPE_BRP_RX */
+ u8 cid;
+ /* used only for WMI_BF_TYPE_SLS */
+ u8 dst_mac[WMI_MAC_LEN];
+ u8 reserved[4];
+} __packed;
+
+/* WMI_BF_TRIG_EVENTID */
+struct wmi_bf_trig_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 cid;
+ u8 reserved[2];
+} __packed;
+
/* broadcast connection ID */
#define WMI_LINK_MAINTAIN_CFG_CID_BROADCAST (0xFFFFFFFF)

@@ -3263,6 +3290,8 @@ struct wmi_link_maintain_cfg_read_done_event {
enum wmi_traffic_suspend_status {
WMI_TRAFFIC_SUSPEND_APPROVED = 0x0,
WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1,
+ WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT = 0x2,
+ WMI_TRAFFIC_SUSPEND_REJECTED_OTHER = 0x3,
};

/* WMI_TRAFFIC_SUSPEND_EVENTID */
@@ -3282,6 +3311,7 @@ enum wmi_resume_trigger {
WMI_RESUME_TRIGGER_UCAST_RX = 0x2,
WMI_RESUME_TRIGGER_BCAST_RX = 0x4,
WMI_RESUME_TRIGGER_WMI_EVT = 0x8,
+ WMI_RESUME_TRIGGER_DISCONNECT = 0x10,
};

/* WMI_TRAFFIC_RESUME_EVENTID */
@@ -4057,4 +4087,20 @@ struct wmi_set_vring_priority_event {
u8 reserved[3];
} __packed;

+/* WMI_RADAR_PCI_CTRL_BLOCK struct */
+struct wmi_radar_pci_ctrl_block {
+ /* last fw tail address index */
+ __le32 fw_tail_index;
+ /* last SW head address index known to FW */
+ __le32 sw_head_index;
+ __le32 last_wr_pulse_tsf_low;
+ __le32 last_wr_pulse_count;
+ __le32 last_wr_in_bytes;
+ __le32 last_wr_pulse_id;
+ __le32 last_wr_burst_id;
+ /* When pre overflow detected, advance sw head in unit of pulses */
+ __le32 sw_head_inc;
+ __le32 reserved[8];
+} __packed;
+
#endif /* __WILOCITY_WMI_H__ */
--
1.9.1