* [PATCH 5.2 1/2] mwifiex: Don't abort on small, spec-compliant vendor IEs
From: Brian Norris @ 2019-06-15 0:13 UTC (permalink / raw)
To: Ganapathi Bhat, Nishant Sarmukadam, Amitkumar Karwar, Xinming Hu
Cc: linux-kernel, linux-wireless, Takashi Iwai, Guenter Roeck,
Brian Norris
Per the 802.11 specification, vendor IEs are (at minimum) only required
to contain an OUI. A type field is also included in ieee80211.h (struct
ieee80211_vendor_ie) but doesn't appear in the specification. The
remaining fields (subtype, version) are a convention used in WMM
headers.
Thus, we should not reject vendor-specific IEs that have only the
minimum length (3 bytes) -- we should skip over them (since we only want
to match longer IEs, that match either WMM or WPA formats). We can
reject elements that don't have the minimum-required 3 byte OUI.
While we're at it, move the non-standard subtype and version fields into
the WMM structs, to avoid this confusion in the future about generic
"vendor header" attributes.
Fixes: 685c9b7750bf ("mwifiex: Abort at too short BSS descriptor element")
Cc: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
It appears that commit 685c9b7750bf is on its way to 5.2, so I labeled
this bugfix for 5.2 as well.
drivers/net/wireless/marvell/mwifiex/fw.h | 12 +++++++++---
drivers/net/wireless/marvell/mwifiex/scan.c | 18 +++++++++++-------
.../net/wireless/marvell/mwifiex/sta_ioctl.c | 4 ++--
drivers/net/wireless/marvell/mwifiex/wmm.c | 2 +-
4 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index b73f99dc5a72..1fb76d2f5d3f 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -1759,9 +1759,10 @@ struct mwifiex_ie_types_wmm_queue_status {
struct ieee_types_vendor_header {
u8 element_id;
u8 len;
- u8 oui[4]; /* 0~2: oui, 3: oui_type */
- u8 oui_subtype;
- u8 version;
+ struct {
+ u8 oui[3];
+ u8 oui_type;
+ } __packed oui;
} __packed;
struct ieee_types_wmm_parameter {
@@ -1775,6 +1776,9 @@ struct ieee_types_wmm_parameter {
* Version [1]
*/
struct ieee_types_vendor_header vend_hdr;
+ u8 oui_subtype;
+ u8 version;
+
u8 qos_info_bitmap;
u8 reserved;
struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
@@ -1792,6 +1796,8 @@ struct ieee_types_wmm_info {
* Version [1]
*/
struct ieee_types_vendor_header vend_hdr;
+ u8 oui_subtype;
+ u8 version;
u8 qos_info_bitmap;
} __packed;
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index c269a0de9413..e2786ab612ca 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -1361,21 +1361,25 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_VENDOR_SPECIFIC:
- if (element_len + 2 < sizeof(vendor_ie->vend_hdr))
- return -EINVAL;
-
vendor_ie = (struct ieee_types_vendor_specific *)
current_ptr;
- if (!memcmp
- (vendor_ie->vend_hdr.oui, wpa_oui,
- sizeof(wpa_oui))) {
+ /* 802.11 requires at least 3-byte OUI. */
+ if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
+ return -EINVAL;
+
+ /* Not long enough for a match? Skip it. */
+ if (element_len < sizeof(wpa_oui))
+ break;
+
+ if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(wpa_oui))) {
bss_entry->bcn_wpa_ie =
(struct ieee_types_vendor_specific *)
current_ptr;
bss_entry->wpa_offset = (u16)
(current_ptr - bss_entry->beacon_buf);
- } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+ } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
sizeof(wmm_oui))) {
if (total_ie_len ==
sizeof(struct ieee_types_wmm_parameter) ||
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index ebc0e41e5d3b..74e50566db1f 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -1351,7 +1351,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
/* Test to see if it is a WPA IE, if not, then
* it is a gen IE
*/
- if (!memcmp(pvendor_ie->oui, wpa_oui,
+ if (!memcmp(&pvendor_ie->oui, wpa_oui,
sizeof(wpa_oui))) {
/* IE is a WPA/WPA2 IE so call set_wpa function
*/
@@ -1361,7 +1361,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
goto next_ie;
}
- if (!memcmp(pvendor_ie->oui, wps_oui,
+ if (!memcmp(&pvendor_ie->oui, wps_oui,
sizeof(wps_oui))) {
/* Test to see if it is a WPS IE,
* if so, enable wps session flag
diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c
index 407b9932ca4d..64916ba15df5 100644
--- a/drivers/net/wireless/marvell/mwifiex/wmm.c
+++ b/drivers/net/wireless/marvell/mwifiex/wmm.c
@@ -240,7 +240,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
mwifiex_dbg(priv->adapter, INFO,
"info: WMM Parameter IE: version=%d,\t"
"qos_info Parameter Set Count=%d, Reserved=%#x\n",
- wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+ wmm_ie->version, wmm_ie->qos_info_bitmap &
IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
wmm_ie->reserved);
--
2.22.0.410.gd8fdbe21b5-goog
^ permalink raw reply related
* Re: [PATCH 2/2] mwifiex: Abort at too short BSS descriptor element
From: Brian Norris @ 2019-06-15 0:19 UTC (permalink / raw)
To: Takashi Iwai
Cc: linux-wireless, Amitkumar Karwar, Nishant Sarmukadam,
Ganapathi Bhat, Xinming Hu, Kalle Valo, huangwen, Solar Designer,
Marcus Meissner
In-Reply-To: <20190613174938.GA260350@google.com>
Hi,
On Thu, Jun 13, 2019 at 10:49 AM Brian Norris <briannorris@chromium.org> wrote:
> "element_len + 2" would be much more readable as "total_ie_len". (Same for
> several other usages in this patch.) I can send such a patch myself as a
> follow-up I suppose.
[...]
> It seems like we should only be validating the standard pieces (e.g., up to the
> length/OUI), and only after an appropriate OUI match, *then* validating the rest of
> the vendor element (the pieces we'll use later).
So I just decided to send some patches myself, for both of my notes:
[PATCH 5.2 1/2] mwifiex: Don't abort on small, spec-compliant vendor IEs
https://patchwork.kernel.org/patch/10996895/
[PATCH 2/2] mwifiex: use 'total_ie_len' in mwifiex_update_bss_desc_with_ie()
https://patchwork.kernel.org/patch/10996893/
I'd appreciate your review.
Regards,
Brian
^ permalink raw reply
* Re: [PATCH v3 wireless-drivers 3/3] mt76: usb: do not always copy the first part of received frames
From: Stanislaw Gruszka @ 2019-06-15 9:40 UTC (permalink / raw)
To: Lorenzo Bianconi; +Cc: Lorenzo Bianconi, kvalo, linux-wireless, nbd
In-Reply-To: <20190614124635.GD2669@localhost.localdomain>
On Fri, Jun 14, 2019 at 02:46:36PM +0200, Lorenzo Bianconi wrote:
> > >
> > > ack, right. I think patch 2/3 and 3/3 can go directly in Felix's tree
> > >
> > > >
> > > > > + int i, data_size;
> > > > >
> > > > > + data_size = rounddown(SKB_WITH_OVERHEAD(q->buf_size),
> > > > > + dev->usb.in_ep[MT_EP_IN_PKT_RX].max_packet);
> > > > > for (i = 0; i < nsgs; i++) {
> > > > > struct page *page;
> > > > > void *data;
> > > > > @@ -302,7 +304,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
> > > > >
> > > > > page = virt_to_head_page(data);
> > > > > offset = data - page_address(page);
> > > > > - sg_set_page(&urb->sg[i], page, q->buf_size, offset);
> > > > > + sg_set_page(&urb->sg[i], page, data_size, offset);
> > > > <snip>
> > > > > - q->buf_size = dev->usb.sg_en ? MT_RX_BUF_SIZE : PAGE_SIZE;
> > > > > q->ndesc = MT_NUM_RX_ENTRIES;
> > > > > + q->buf_size = PAGE_SIZE;
> > > > > +
> > > >
> > > > This should be associated with decrease of MT_SG_MAX_SIZE to value that
> > > > is actually needed and currently this is 2 for 4k AMSDU.
> > >
> > > MT_SG_MAX_SIZE is used even on tx side and I do not think we will end up with a
> > > huge difference here
> >
> > So use different value as argument for mt76u_fill_rx_sg() in
> > mt76u_rx_urb_alloc(). After changing buf_size to PAGE_SIZE we will
> > allocate 8 pages per rx queue entry, but only 2 pages will be used
> > (with data_size change, 1 without data_size change). Or I'm wrong?
>
> yes, it is right (we will use two pages with data_size change). Maybe better to
> use 4 pages for each rx queue entry? (otherwise we will probably change it in
> the future)
We should not allocate more than is required. If support for bigger
rx AMSDUs will be added and announced in vht/ht capabilities to remote
stations, then increase of number of segments will be needed.
> > > > However I don't think allocating 2 pages to avoid ieee80211 header and SNAP
> > > > copy is worth to do. For me best approach would be allocate 1 page for
> > > > 4k AMSDU, 2 for 8k and 3 for 12k (still using sg, but without data_size
> > > > change to avoid 32B copying).
> > >
> > > From my point of view it is better to avoid copying if it is possible. Are you
> > > sure there is no difference?
> >
> > I do not understand what you mean by difference here.
>
> tpt differences, not sure if there are any
I would not expect any measurable difference in tpt nor in cpu usage
either way.
But I think, if some AMSDU subframe will be spited into two fragments,
data most likely will need to be linearised/copied, at some point before
passed to application, what will overcome any benefit of avoiding coping
802.11 header. Thought, I don't think this somehow will be visible in
benchmarking.
Stanislaw
^ permalink raw reply
* [PATCH] carl9170: remove dead branch in op_conf_tx callback
From: Christian Lamparter @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless; +Cc: Kalle Valo
This patch removes the error branch for (queue > ar->hw->queues).
It is no longer needed anymore as the "queue" value is validated by
cfg80211's parse_txq_params() before the driver code gets called.
Some background:
In the old days (linux 2.6 and early 3.x), the parse_txq_params()
function did not verify the "queue" value. That's why these drivers
had to do it.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
drivers/net/wireless/ath/carl9170/main.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 7f1bdea742b8..40a8054f8aa6 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1387,13 +1387,8 @@ static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
int ret;
mutex_lock(&ar->mutex);
- if (queue < ar->hw->queues) {
- memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
- ret = carl9170_set_qos(ar);
- } else {
- ret = -EINVAL;
- }
-
+ memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
+ ret = carl9170_set_qos(ar);
mutex_unlock(&ar->mutex);
return ret;
}
--
2.20.1
^ permalink raw reply related
* [PATCH] p54: remove dead branch in op_conf_tx callback
From: Christian Lamparter @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless; +Cc: Kalle Valo
In-Reply-To: <20190615100009.14654-1-chunkeey@gmail.com>
This patch removes the error branch for (queue > dev->queues).
It is no longer needed anymore as the "queue" value is validated by
cfg80211's parse_txq_params() before the driver code gets called.
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
drivers/net/wireless/intersil/p54/main.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
index 1c6d428515a4..4cc0ece0cd0e 100644
--- a/drivers/net/wireless/intersil/p54/main.c
+++ b/drivers/net/wireless/intersil/p54/main.c
@@ -414,12 +414,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev,
int ret;
mutex_lock(&priv->conf_mutex);
- if (queue < dev->queues) {
- P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
- params->cw_min, params->cw_max, params->txop);
- ret = p54_set_edcf(priv);
- } else
- ret = -EINVAL;
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(priv);
mutex_unlock(&priv->conf_mutex);
return ret;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v2 0/7] rt2800: add experimental watchdog implementation
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
Add watchdog to address some remaining problems of Ralink devices
random hungs.
RFC -> v1
- better description for module parameter
- fix white space
v1 -> v2:
- rebase on latest tree.
Stanislaw Gruszka (7):
rt2x00: allow to specify watchdog interval
rt2800: add helpers for reading dma done index
rt2800: initial watchdog implementation
rt2800: add pre_reset_hw callback
rt2800: do not nullify initialization vector data
rt2x00: add restart hw
rt2800: do not enable watchdog by default
.../net/wireless/ralink/rt2x00/rt2800lib.c | 96 ++++++++++++++++++-
.../net/wireless/ralink/rt2x00/rt2800lib.h | 11 +++
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 31 ++++++
.../net/wireless/ralink/rt2x00/rt2800mmio.h | 2 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 3 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 3 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 11 +++
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 10 ++
.../net/wireless/ralink/rt2x00/rt2x00debug.c | 35 +++++++
.../net/wireless/ralink/rt2x00/rt2x00dev.c | 10 +-
.../net/wireless/ralink/rt2x00/rt2x00link.c | 15 ++-
.../net/wireless/ralink/rt2x00/rt2x00queue.h | 6 ++
12 files changed, 221 insertions(+), 12 deletions(-)
--
2.20.1
^ permalink raw reply
* [PATCH v2 1/7] rt2x00: allow to specify watchdog interval
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
Allow subdriver to change watchdog interval by intialize
link->watchdog_interval value before rt2x00link_register().
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00link.c | 13 +++++++++----
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 64a792a8fb2c..2b551dbe9844 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -325,6 +325,7 @@ struct link {
* to bring the device/driver back into the desired state.
*/
struct delayed_work watchdog_work;
+ unsigned int watchdog_interval;
/*
* Work structure for scheduling periodic AGC adjustments.
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
index 939cfa5141c6..15ebebf88e72 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -387,7 +387,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
rt2x00dev->ops->lib->watchdog)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
- WATCHDOG_INTERVAL);
+ link->watchdog_interval);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -413,11 +413,16 @@ static void rt2x00link_watchdog(struct work_struct *work)
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
- WATCHDOG_INTERVAL);
+ link->watchdog_interval);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
- INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
- INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
+ struct link *link = &rt2x00dev->link;
+
+ INIT_DELAYED_WORK(&link->work, rt2x00link_tuner);
+ INIT_DELAYED_WORK(&link->watchdog_work, rt2x00link_watchdog);
+
+ if (link->watchdog_interval == 0)
+ link->watchdog_interval = WATCHDOG_INTERVAL;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/7] rt2800: add helpers for reading dma done index
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
For mmio we do not properlly trace dma done Q_INDEX_DMA_DONE index
for TX queues. That would require implementing INT_SOURCE_CSR_*_DMA_DONE
interrupts, what is rather not worth to do due to adding extra
CPU load (small but still somewhat not necessary otherwise).
We can just read TX DMA done indexes from registers directly. What
will be used by watchdog.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800lib.h | 8 +++++
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 31 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800mmio.h | 2 ++
.../net/wireless/ralink/rt2x00/rt2800pci.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 9 ++++++
6 files changed, 52 insertions(+)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index 48adc6cc3233..dbb413ec8b08 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -65,6 +65,7 @@ struct rt2800_ops {
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
+ unsigned int (*drv_get_dma_done)(struct data_queue *queue);
};
static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -166,6 +167,13 @@ static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
return rt2800ops->drv_get_txwi(entry);
}
+static inline unsigned int rt2800_drv_get_dma_done(struct data_queue *queue)
+{
+ const struct rt2800_ops *rt2800ops = queue->rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_get_dma_done(queue);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
index d1de8e2ff690..110bb391c372 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -24,6 +24,37 @@
#include "rt2800lib.h"
#include "rt2800mmio.h"
+unsigned int rt2800mmio_get_dma_done(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry;
+ int idx, qid;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ qid = queue->qid;
+ idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(qid));
+ break;
+ case QID_MGMT:
+ idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(5));
+ break;
+ case QID_RX:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ idx = entry->entry_idx;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ idx = 0;
+ break;
+ }
+
+ return idx;
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_get_dma_done);
+
/*
* TX descriptor initialization
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
index 29b5cfd2856f..adcd9d54ac1c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
@@ -114,6 +114,8 @@
#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000)
#define RXD_W3_PLCP_RSSI FIELD32(0x00040000)
+unsigned int rt2800mmio_get_dma_done(struct data_queue *queue);
+
/* TX descriptor initialization */
__le32 *rt2800mmio_get_txwi(struct queue_entry *entry);
void rt2800mmio_write_tx_desc(struct queue_entry *entry,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index ead8bd3e9236..71ef8f07b47b 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -326,6 +326,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
+ .drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
index 230557d36c52..34e9291d949c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -171,6 +171,7 @@ static const struct rt2800_ops rt2800soc_rt2800_ops = {
.drv_write_firmware = rt2800soc_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
+ .drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
index 551427b83775..9f23b18c50bb 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -379,6 +379,14 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
return retval;
}
+static unsigned int rt2800usb_get_dma_done(struct data_queue *queue)
+{
+ struct queue_entry *entry;
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ return entry->entry_idx;
+}
+
/*
* TX descriptor initialization
*/
@@ -661,6 +669,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
.drv_get_txwi = rt2800usb_get_txwi,
+ .drv_get_dma_done = rt2800usb_get_dma_done,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
--
2.20.1
^ permalink raw reply related
* [PATCH v2 3/7] rt2800: initial watchdog implementation
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
Add watchdog for rt2800 devices. For now it only detect hung
and print error.
[Note: I verified that printing messages from process context is
fine on MT7620 (WT3020) platform that have problem when printk
is called from interrupt context].
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 56 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800lib.h | 2 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 1 +
.../net/wireless/ralink/rt2x00/rt2x00queue.h | 6 ++
6 files changed, 67 insertions(+)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 621cd4ce69e2..d420d759a877 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1212,6 +1212,60 @@ void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
+static int rt2800_check_hung(struct data_queue *queue)
+{
+ unsigned int cur_idx = rt2800_drv_get_dma_done(queue);
+
+ if (queue->wd_idx != cur_idx)
+ queue->wd_count = 0;
+ else
+ queue->wd_count++;
+
+ return queue->wd_count > 16;
+}
+
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ bool hung_tx = false;
+ bool hung_rx = false;
+
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ return;
+
+ queue_for_each(rt2x00dev, queue) {
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_MGMT:
+ if (rt2x00queue_empty(queue))
+ continue;
+ hung_tx = rt2800_check_hung(queue);
+ break;
+ case QID_RX:
+ /* For station mode we should reactive at least
+ * beacons. TODO: need to find good way detect
+ * RX hung for AP mode.
+ */
+ if (rt2x00dev->intf_sta_count == 0)
+ continue;
+ hung_rx = rt2800_check_hung(queue);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (hung_tx)
+ rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");
+
+ if (hung_rx)
+ rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
+}
+EXPORT_SYMBOL_GPL(rt2800_watchdog);
+
static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
unsigned int index)
{
@@ -10211,6 +10265,8 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
+ rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+
/*
* Set the rssi offset.
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index dbb413ec8b08..f35f4e20d5aa 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -197,6 +197,8 @@ void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev);
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index 71ef8f07b47b..df6345a92f72 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -351,6 +351,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
index 34e9291d949c..1054ade65af2 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -196,6 +196,7 @@ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
index 9f23b18c50bb..da813dfa9a91 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -687,6 +687,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2800usb_stop_queue,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
index 099e747f70e7..23739dd0bc9b 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
@@ -435,6 +435,9 @@ enum data_queue_flags {
* @length: Number of frames in queue.
* @index: Index pointers to entry positions in the queue,
* use &enum queue_index to get a specific index field.
+ * @wd_count: watchdog counter number of times entry does change
+ * in the queue
+ * @wd_idx: index of queue entry saved by watchdog
* @txop: maximum burst time.
* @aifs: The aifs value for outgoing frames (field ignored in RX queue).
* @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
@@ -462,6 +465,9 @@ struct data_queue {
unsigned short length;
unsigned short index[Q_INDEX_MAX];
+ unsigned short wd_count;
+ unsigned int wd_idx;
+
unsigned short txop;
unsigned short aifs;
unsigned short cw_min;
--
2.20.1
^ permalink raw reply related
* [PATCH v2 4/7] rt2800: add pre_reset_hw callback
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
Add routine to cleanup interfaces data before hw reset as
ieee80211_restart_hw() will do setup interfaces again.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 19 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800lib.h | 1 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
6 files changed, 24 insertions(+)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index d420d759a877..499e9afa0026 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1843,6 +1843,25 @@ int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(rt2800_sta_remove);
+void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+ struct data_queue *queue = rt2x00dev->bcn;
+ struct queue_entry *entry;
+ int i, wcid;
+
+ for (wcid = WCID_START; wcid < WCID_END; wcid++) {
+ drv_data->wcid_to_sta[wcid - WCID_START] = NULL;
+ __clear_bit(wcid - WCID_START, drv_data->sta_ids);
+ }
+
+ for (i = 0; i < queue->limit; i++) {
+ entry = &queue->entries[i];
+ clear_bit(ENTRY_BCN_ASSIGNED, &entry->flags);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_pre_reset_hw);
+
void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index f35f4e20d5aa..1139405c0ebb 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -257,5 +257,6 @@ void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev,
unsigned short *txwi_size,
unsigned short *rxwi_size);
+void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev);
#endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index df6345a92f72..a23c26574002 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -368,6 +368,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800pci_ops = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
index 1054ade65af2..7b931bb96a9e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -213,6 +213,7 @@ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800soc_ops = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
index da813dfa9a91..fdf0504b5f1d 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -706,6 +706,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static void rt2800usb_queue_init(struct data_queue *queue)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 2b551dbe9844..dc6b79e4be3b 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -616,6 +616,7 @@ struct rt2x00lib_ops {
void (*config) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int changed_flags);
+ void (*pre_reset_hw) (struct rt2x00_dev *rt2x00dev);
int (*sta_add) (struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
--
2.20.1
^ permalink raw reply related
* [PATCH v2 5/7] rt2800: do not nullify initialization vector data
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
If we restart hw we should keep existing IV (initialization vector)
otherwise HW encryption will be broken after restart.
Also fix some coding style issues on the way.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 499e9afa0026..32a4b84e6e05 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1647,14 +1647,15 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
- memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+ rt2800_register_multiread(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
if ((crypto->cipher == CIPHER_TKIP) ||
(crypto->cipher == CIPHER_TKIP_NO_MIC) ||
(crypto->cipher == CIPHER_AES))
iveiv_entry.iv[3] |= 0x20;
iveiv_entry.iv[3] |= key->keyidx << 6;
rt2800_register_multiwrite(rt2x00dev, offset,
- &iveiv_entry, sizeof(iveiv_entry));
+ &iveiv_entry, sizeof(iveiv_entry));
}
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -6079,13 +6080,11 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
* ASIC will keep garbage value after boot, clear encryption keys.
*/
for (i = 0; i < 4; i++)
- rt2800_register_write(rt2x00dev,
- SHARED_KEY_MODE_ENTRY(i), 0);
+ rt2800_register_write(rt2x00dev, SHARED_KEY_MODE_ENTRY(i), 0);
for (i = 0; i < 256; i++) {
rt2800_config_wcid(rt2x00dev, NULL, i);
rt2800_delete_wcid_attr(rt2x00dev, i);
- rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
}
/*
--
2.20.1
^ permalink raw reply related
* [PATCH v2 6/7] rt2x00: add restart hw
From: Stanislaw Gruszka @ 2019-06-15 10:00 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
Add ieee80211_restart_hw() to watchdog and debugfs file for testing
if restart works as expected.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 4 +++
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 7 ++++
.../net/wireless/ralink/rt2x00/rt2x00debug.c | 35 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2x00dev.c | 10 ++++--
4 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 32a4b84e6e05..0fb519f2b83f 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1263,6 +1263,9 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
if (hung_rx)
rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
+
+ if (hung_tx || hung_rx)
+ ieee80211_restart_hw(rt2x00dev->hw);
}
EXPORT_SYMBOL_GPL(rt2800_watchdog);
@@ -10283,6 +10286,7 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
+ __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index dc6b79e4be3b..7c7cced009bd 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -712,6 +712,7 @@ enum rt2x00_capability_flags {
CAPABILITY_VCO_RECALIBRATION,
CAPABILITY_EXTERNAL_PA_TX0,
CAPABILITY_EXTERNAL_PA_TX1,
+ CAPABILITY_RESTART_HW,
};
/*
@@ -1268,6 +1269,12 @@ rt2x00_has_cap_vco_recalibration(struct rt2x00_dev *rt2x00dev)
return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_VCO_RECALIBRATION);
}
+static inline bool
+rt2x00_has_cap_restart_hw(struct rt2x00_dev *rt2x00dev)
+{
+ return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_RESTART_HW);
+}
+
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @entry: Pointer to &struct queue_entry
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
index aac3aae7afaa..ef5f51512212 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -52,6 +52,7 @@ struct rt2x00debug_intf {
* - chipset file
* - device state flags file
* - device capability flags file
+ * - hardware restart file
* - register folder
* - csr offset/value files
* - eeprom offset/value files
@@ -68,6 +69,7 @@ struct rt2x00debug_intf {
struct dentry *chipset_entry;
struct dentry *dev_flags;
struct dentry *cap_flags;
+ struct dentry *restart_hw;
struct dentry *register_folder;
struct dentry *csr_off_entry;
struct dentry *csr_val_entry;
@@ -566,6 +568,34 @@ static const struct file_operations rt2x00debug_fop_cap_flags = {
.llseek = default_llseek,
};
+static ssize_t rt2x00debug_write_restart_hw(struct file *file,
+ const char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ struct rt2x00_dev *rt2x00dev = intf->rt2x00dev;
+ static unsigned long last_reset;
+
+ if (!rt2x00_has_cap_restart_hw(rt2x00dev))
+ return -EOPNOTSUPP;
+
+ if (time_before(jiffies, last_reset + msecs_to_jiffies(2000)))
+ return -EBUSY;
+
+ last_reset = jiffies;
+
+ ieee80211_restart_hw(rt2x00dev->hw);
+ return length;
+}
+
+static const struct file_operations rt2x00debug_restart_hw = {
+ .owner = THIS_MODULE,
+ .write = rt2x00debug_write_restart_hw,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
static struct dentry *rt2x00debug_create_file_driver(const char *name,
struct rt2x00debug_intf
*intf,
@@ -661,6 +691,10 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf->driver_folder, intf,
&rt2x00debug_fop_cap_flags);
+ intf->restart_hw = debugfs_create_file("restart_hw", 0200,
+ intf->driver_folder, intf,
+ &rt2x00debug_restart_hw);
+
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
@@ -742,6 +776,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
debugfs_remove(intf->csr_off_entry);
debugfs_remove(intf->register_folder);
debugfs_remove(intf->dev_flags);
+ debugfs_remove(intf->restart_hw);
debugfs_remove(intf->cap_flags);
debugfs_remove(intf->chipset_entry);
debugfs_remove(intf->driver_entry);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index a6c374c483c2..35414f97a978 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1258,8 +1258,14 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
{
int retval;
- if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
- return 0;
+ if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
+ /*
+ * This is special case for ieee80211_restart_hw(), otherwise
+ * mac80211 never call start() two times in row without stop();
+ */
+ rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
+ rt2x00lib_stop(rt2x00dev);
+ }
/*
* If this is the first interface which is added,
--
2.20.1
^ permalink raw reply related
* [PATCH v2 7/7] rt2800: do not enable watchdog by default
From: Stanislaw Gruszka @ 2019-06-15 10:01 UTC (permalink / raw)
To: linux-wireless
Cc: Tomislav Požega, Daniel Golle, Felix Fietkau, Mathias Kresin
In-Reply-To: <20190615100100.29800-1-sgruszka@redhat.com>
Make watchdog disabled by default and add module parameter to enable it.
User will have to create file in /etc/modprobe.d/ with
options rt2800lib watchdog=1
to enable the watchdog or load "rt2800lib watchdog=1" module manually
before loading rt2800{soc,pci,usb} module.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 12 ++++++++++--
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00link.c | 2 +-
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 0fb519f2b83f..c9b957ac5733 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -30,6 +30,10 @@
#include "rt2800lib.h"
#include "rt2800.h"
+static bool modparam_watchdog;
+module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO);
+MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected");
+
/*
* Register access.
* All access to the CSR registers will go through the methods
@@ -10286,8 +10290,12 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
- __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
- rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+ if (modparam_watchdog) {
+ __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
+ rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+ } else {
+ rt2x00dev->link.watchdog_disabled = true;
+ }
/*
* Set the rssi offset.
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 7c7cced009bd..7e43690a861c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -326,6 +326,7 @@ struct link {
*/
struct delayed_work watchdog_work;
unsigned int watchdog_interval;
+ bool watchdog_disabled;
/*
* Work structure for scheduling periodic AGC adjustments.
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
index 15ebebf88e72..b052c96347d6 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -384,7 +384,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
struct link *link = &rt2x00dev->link;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->watchdog)
+ rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
link->watchdog_interval);
--
2.20.1
^ permalink raw reply related
* Re: [PATCH v3 wireless-drivers 1/3] mt76: usb: fix rx A-MSDU support
From: Lorenzo Bianconi @ 2019-06-15 12:06 UTC (permalink / raw)
To: Stanislaw Gruszka
Cc: Johannes Berg, Lorenzo Bianconi, Kalle Valo, linux-wireless,
Felix Fietkau
In-Reply-To: <20190614113120.GC17298@redhat.com>
>
> On Fri, Jun 14, 2019 at 12:20:59PM +0200, Johannes Berg wrote:
> > On Fri, 2019-06-14 at 12:11 +0200, Lorenzo Bianconi wrote:
> >
> > > Looking at __ieee80211_amsdu_copy() now I got why other drivers copy hdrlen +
> > > 8, thx :)
> > > In our case reuse_frag is true in __ieee80211_amsdu_copy, so we will end up
> > > copying 32B + ether_len. Anyway I think 32 is a little bit too low and we could get
> > > better performances increasing it a little bit.
> > > A typical use case (e.g IPv6 + TCP):
> > >
> > > IPv6 = 40B, TCP = 32B --> so 72B..I guess 128B is a good value :)
> > > @Felix, Johannes: what do you think?
> >
> > I think while we might *allocate* more, I don't think we should *copy*
> > more, since then the TCP payload will no longer be in pages.
> >
> > It'd probably be better to implement leaving enough tailroom (allocate
> > 128), but copying nothing, unless the *entire* packet fits.
>
> iwl4965 put entire packet in fragment in il4965_pass_packet_to_mac80211() .
> Initially I thought this is a bug, since mac80211 require header be
> in the linear area, but looks like ieee80211_rx_monitor() copy header
> before rest of mac80211 check it, so 4965 is fine.
>
> Anyway I think the driver should put ieee80211 header in linear area
> and iwlwifi & mt7601u implementation is somewhat optimal.
Actually the case is a little bit different for mt76 since we need
even mt76x02_rxwi in the linear area of the received skb.
Taking that into account the requested size to copy will be:
32 + 802.11 hdr + SNAP hdr = ~ 70B
Moreover to pass rxwi size to usb module we need to add a field in
mt76_driver_ops (e.g rxwi_size).
I will carry out some tests and if there are no differences I will
post a single patch to wireless-drivers using 128B as default size
Regards,
Lorenzo
>
> Stanislaw
^ permalink raw reply
* Re: rtw88: M.2 RTL8822BE not working - rfe 3 isn't supported
From: g.schlmm @ 2019-06-15 12:50 UTC (permalink / raw)
To: Tony Chuang, Stanislaw Gruszka, g.schlmm; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <F7CD281DE3E379468C6D07993EA72F84D180639E@RTITMBSVM04.realtek.com.tw>
On 14.06.19 10:24, Tony Chuang wrote:
>> Subject: Re: rtw88: M.2 RTL8822BE not working - rfe 3 isn't supported
>>
>> Cc Tony
>>
>> On Sat, Jun 08, 2019 at 02:26:51PM +0200, g.schlmm wrote:
>>> my RTL8822BE M.2 card is not working with linux 5.2rc3
>>>
>>> the staging r8822be driver in linux 5.1 was working for this card
>>>
>>> from dmesg:
>>>> [ 8.001186] rtw_pci 0000:04:00.0: rfe 3 isn't supported
>>>> [ 8.003870] rtw_pci 0000:04:00.0: failed to setup chip efuse info
>>>> [ 8.006405] rtw_pci 0000:04:00.0: failed to setup chip information
>>>
>>> lspci:
>>>> 04:00.0 Unassigned class [ff00]: Realtek Semiconductor Co., Ltd.
>> RTL8822BE 802.11a/b/g/n/ac WiFi adapter
>>>> Subsystem: Lenovo RTL8822BE 802.11a/b/g/n/ac WiFi adapter
>>>> Flags: fast devsel, IRQ 19
>>>> I/O ports at c000 [size=256]
>>>> Memory at 81200000 (64-bit, non-prefetchable) [size=64K]
>>>> Capabilities: [40] Power Management version 3
>>>> Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit+
>>>> Capabilities: [70] Express Endpoint, MSI 00
>>>> Capabilities: [100] Advanced Error Reporting
>>>> Capabilities: [148] Device Serial Number
>> 00-e0-4c-ff-fe-b8-22-01
>>>> Capabilities: [158] Latency Tolerance Reporting
>>>> Capabilities: [160] L1 PM Substates
>>>> Kernel modules: rtwpci
>>
>
> Hi,
>
> Please use the attached patch. And RFE type 3 has not been well tested,
> I am not sure if the quality is expected. But it should work fine I guess.
> If there is any further problems, just tell me, thanks.
>
> Yan-Hsuan
>
Hello,
Thanks for the patch. i applied it on top of 5.2rc4 and everything is
playing nice so far.
i use the card as a hotspot with hostapd
the download speed changed from ~10Mbit/s (with the 5.1 staging driver)
to ~100Mbit/s
very nice work!
^ permalink raw reply
* [PATCH v4 wireless-drivers] mt76: usb: fix rx A-MSDU support
From: Lorenzo Bianconi @ 2019-06-15 14:03 UTC (permalink / raw)
To: kvalo; +Cc: nbd, lorenzo.bianconi, linux-wireless, sgruszka
Commit f8f527b16db5 ("mt76: usb: use EP max packet aligned buffer sizes
for rx") breaks A-MSDU support. When A-MSDU is enable the device can
receive frames up to q->buf_size but they will be discarded in
mt76u_process_rx_entry since there is no enough room for
skb_shared_info. Fix the issue reallocating the skb and copying in the
linear area the first 128B of the received frames and in the frag_list
the remaining part
Fixes: f8f527b16db5 ("mt76: usb: use EP max packet aligned buffer sizes for rx")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
Changes since v3:
- drop patch 2/3 and 3/3
Changes since v2:
- simplify mt76u_build_rx_skb
- add patch 2/3: mt76u: introduce mt76u_ep data structure
- align usb buffer size to usb max endpoint length
- set buf_size to PAGE_SIZE even for sg case
Changes since v1:
- do not allocate multiple page buffers but rely on fragmented skbs
if there is no enough space to manage the AMSDU rx packets
---
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
drivers/net/wireless/mediatek/mt76/usb.c | 46 ++++++++++++++++++-----
2 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 8ecbf81a906f..889b76deb703 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -30,6 +30,7 @@
#define MT_TX_RING_SIZE 256
#define MT_MCU_RING_SIZE 32
#define MT_RX_BUF_SIZE 2048
+#define MT_SKB_HEAD_LEN 128
struct mt76_dev;
struct mt76_wcid;
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index bbaa1365bbda..dd90427b2d67 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -429,6 +429,42 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
return dma_len;
}
+static struct sk_buff *
+mt76u_build_rx_skb(void *data, int len, int buf_size)
+{
+ struct sk_buff *skb;
+
+ if (SKB_WITH_OVERHEAD(buf_size) < MT_DMA_HDR_LEN + len) {
+ struct page *page;
+
+ /* slow path, not enough space for data and
+ * skb_shared_info
+ */
+ skb = alloc_skb(MT_SKB_HEAD_LEN, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+
+ skb_put_data(skb, data + MT_DMA_HDR_LEN, MT_SKB_HEAD_LEN);
+ data += (MT_DMA_HDR_LEN + MT_SKB_HEAD_LEN);
+ page = virt_to_head_page(data);
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+ page, data - page_address(page),
+ len - MT_SKB_HEAD_LEN, buf_size);
+
+ return skb;
+ }
+
+ /* fast path */
+ skb = build_skb(data, buf_size);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+ __skb_put(skb, len);
+
+ return skb;
+}
+
static int
mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb)
{
@@ -446,19 +482,11 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb)
return 0;
data_len = min_t(int, len, data_len - MT_DMA_HDR_LEN);
- if (MT_DMA_HDR_LEN + data_len > SKB_WITH_OVERHEAD(q->buf_size)) {
- dev_err_ratelimited(dev->dev, "rx data too big %d\n", data_len);
- return 0;
- }
-
- skb = build_skb(data, q->buf_size);
+ skb = mt76u_build_rx_skb(data, data_len, q->buf_size);
if (!skb)
return 0;
- skb_reserve(skb, MT_DMA_HDR_LEN);
- __skb_put(skb, data_len);
len -= data_len;
-
while (len > 0 && nsgs < urb->num_sgs) {
data_len = min_t(int, len, urb->sg[nsgs].length);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
--
2.21.0
^ permalink raw reply related
* wpa_supplicant 2.8 fails in brcmf_cfg80211_set_pmk
From: Stefan Wahren @ 2019-06-15 17:01 UTC (permalink / raw)
To: Arend van Spriel, Franky Lin, Hante Meuleman, Chi-Hsien Lin,
Wright Feng, linux-wireless, brcm80211-dev-list.pdl,
brcm80211-dev-list
Hi,
i was able to reproduce an (maybe older issue) with 4-way handshake
offloading for 802.1X in the brcmfmac driver. My setup consists of
Raspberry Pi 3 B (current linux-next, arm64/defconfig) on STA side and a
Raspberry Pi 3 A+ (Linux 4.19) on AP side. The issue occurs on the STA
side with wpa_supplicant 2.8, which gives the following output:
Configure PMK for driver-based RSN 4-way handshake
EAPOL: Successfully fetched key (len=32)
RSN: Configure PMK for driver-based 4-way handshake - hexdump(len=32):
[REMOVED]
wpa_driver_nl80211_set_key: ifindex=3 (wlan0) alg=5 addr=(nil) key_idx=0
set_tx=0 seq_len=0 key_len=32
nl80211: Set PMK to the driver for b8:27:eb:6c:5e:c9
nl80211: PMK - hexdump(len=32): [REMOVED]
nl80211: Set PMK failed: ret=-22 (Invalid argument)
During this the kernel also gave this warning:
[ 874.485374] WARNING: CPU: 0 PID: 460 at
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:5208
brcmf_cfg80211_set_pmk+0x3c/0x58 [brcmfmac]
[ 874.504523] Modules linked in: 8021q garp stp mrp llc bcm2835_v4l2(C)
brcmfmac vc4 v4l2_common videobuf2_vmalloc videobuf2_memops
videobuf2_v4l2 cec videobuf2_common drm_kms_helper videodev brcmutil
hci_uart cfg80211 mc btbcm drm snd_bcm2835(C) bluetooth smsc95xx
crct10dif_ce usbnet ecdh_generic ecc drm_panel_orientation_quirks
raspberrypi_hwmon rfkill bcm2835_rng bcm2835_thermal pwm_bcm2835
i2c_bcm2835 rng_core vchiq(C) ip_tables x_tables ipv6 nf_defrag_ipv6
[ 874.558134] CPU: 0 PID: 460 Comm: wpa_supplicant Tainted: G
WC 5.2.0-rc4-next-20190614-g65beedb66 #3
[ 874.574984] Hardware name: Raspberry Pi 3 Model B (DT)
[ 874.586546] pstate: 80000005 (Nzcv daif -PAN -UAO)
[ 874.597817] pc : brcmf_cfg80211_set_pmk+0x3c/0x58 [brcmfmac]
[ 874.610049] lr : nl80211_set_pmk+0x16c/0x1a8 [cfg80211]
[ 874.621776] sp : ffff000011aab910
[ 874.631533] x29: ffff000011aab910 x28: ffff80002ec5a000
[ 874.643326] x27: 0000000000000014 x26: ffff80002fd9c300
[ 874.655094] x25: ffff80002fd9c000 x24: ffff80002ec5c000
[ 874.666843] x23: 00000000ffffff95 x22: ffff80002ec5d050
[ 874.678580] x21: ffff80002ec5d008 x20: ffff000011aaba30
[ 874.690336] x19: ffff000011349000 x18: 0000000000000000
[ 874.702080] x17: 0000000000000000 x16: 0000000000000000
[ 874.713809] x15: 0000000000000000 x14: be1127680d12277d
[ 874.725547] x13: 8ba575fc53793d9f x12: ffff000008dff8a8
[ 874.737297] x11: 0000000000000fe0 x10: 0000000000000000
[ 874.749059] x9 : ffff000010c12068 x8 : ffff000010c12050
[ 874.760832] x7 : ffff000008dfe8c8 x6 : 000000000000003f
[ 874.772598] x5 : 0000000000000008 x4 : 000000006ceb27b8
[ 874.784349] x3 : ffff000008ef1eb0 x2 : ffff000011aab978
[ 874.796091] x1 : 0000000000000000 x0 : ffff80002ec5c7c0
[ 874.807853] Call trace:
[ 874.816698] brcmf_cfg80211_set_pmk+0x3c/0x58 [brcmfmac]
[ 874.828399] nl80211_set_pmk+0x16c/0x1a8 [cfg80211]
[ 874.839327] genl_family_rcv_msg+0x364/0x460
[ 874.849343] genl_rcv_msg+0x5c/0xc0
[ 874.858282] netlink_rcv_skb+0x5c/0x128
[ 874.867486] genl_rcv+0x34/0x48
[ 874.875956] netlink_unicast+0x190/0x1f8
[ 874.885203] netlink_sendmsg+0x2cc/0x348
[ 874.894397] sock_sendmsg+0x18/0x30
[ 874.903124] ___sys_sendmsg+0x28c/0x2c8
[ 874.912216] __sys_sendmsg+0x6c/0xc8
[ 874.921040] __arm64_sys_sendmsg+0x20/0x28
[ 874.930408] el0_svc_common.constprop.0+0x64/0x160
[ 874.940520] el0_svc_handler+0x28/0x78
[ 874.949552] el0_svc+0x8/0xc
[ 874.957674] ---[ end trace 72f634728d4e750f ]---
Here are the information about the used firmware:
[ 11.622355] brcmfmac: brcmf_fw_alloc_request: using
brcm/brcmfmac43430-sdio for chip BCM43430/1
[ 11.637498] brcmfmac: brcmf_c_process_clm_blob: no clm_blob available
(err=-2), device may have limited channels available
[ 11.658814] brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM43430/1
wl0: Oct 23 2017 03:55:53 version 7.45.98.38 (r674442 CY) FWID 01-e58d219f
The actual STA configuration can be found here [1] and other report of
this issue here [2].
Any ideas how to fix this?
[1] - https://gist.github.com/lategoodbye/d4b5da60e905cbdf069affbd41cd14ab'
[2] - https://archlinuxarm.org/forum/viewtopic.php?f=60&t=13644
^ permalink raw reply
* Re: wpa_supplicant 2.8 fails in brcmf_cfg80211_set_pmk
From: Stefan Wahren @ 2019-06-15 17:21 UTC (permalink / raw)
To: Arend van Spriel, Franky Lin, Hante Meuleman, Chi-Hsien Lin,
Wright Feng, linux-wireless, brcm80211-dev-list.pdl,
brcm80211-dev-list
In-Reply-To: <06f7bda7-eeaf-536b-a583-7c9bc5f681f5@gmx.net>
Am 15.06.19 um 19:01 schrieb Stefan Wahren:
> Hi,
>
> i was able to reproduce an (maybe older issue) with 4-way handshake
> offloading for 802.1X in the brcmfmac driver. My setup consists of
> Raspberry Pi 3 B (current linux-next, arm64/defconfig) on STA side and a
> Raspberry Pi 3 A+ (Linux 4.19) on AP side.
Looks like Raspberry Pi isn't the only affected platform [3], [4].
[3] - https://bugzilla.redhat.com/show_bug.cgi?id=1665608
[4] - https://bugzilla.kernel.org/show_bug.cgi?id=202521
^ permalink raw reply
* Re: [PATCH] wireless: airo: switch to skcipher interface
From: Eric Biggers @ 2019-06-16 7:12 UTC (permalink / raw)
To: Ard Biesheuvel; +Cc: linux-wireless, kvalo, linux-crypto, herbert
In-Reply-To: <20190614093603.22771-1-ard.biesheuvel@linaro.org>
On Fri, Jun 14, 2019 at 11:36:03AM +0200, Ard Biesheuvel wrote:
> The AIRO driver applies a ctr(aes) on a buffer of considerable size
> (2400 bytes), and instead of invoking the crypto API to handle this
> in its entirety, it open codes the counter manipulation and invokes
> the AES block cipher directly.
>
> Let's fix this, by switching to the sync skcipher API instead.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> NOTE: build tested only, since I don't have the hardware
>
> drivers/net/wireless/cisco/airo.c | 57 ++++++++++----------
> 1 file changed, 27 insertions(+), 30 deletions(-)
>
Need to also select CRYPTO_CTR in drivers/net/wireless/cisco/Kconfig under
AIRO_CS, and I think also CRYPTO_BLKCIPHER under AIRO.
> diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
> index 3f5a14112c6b..2d29ad10505b 100644
> --- a/drivers/net/wireless/cisco/airo.c
> +++ b/drivers/net/wireless/cisco/airo.c
> @@ -49,6 +49,9 @@
> #include <linux/kthread.h>
> #include <linux/freezer.h>
>
> +#include <crypto/aes.h>
> +#include <crypto/skcipher.h>
> +
> #include <net/cfg80211.h>
> #include <net/iw_handler.h>
>
> @@ -951,7 +954,7 @@ typedef struct {
> } mic_statistics;
>
> typedef struct {
> - u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
> + __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
> u64 accum; // accumulated mic, reduced to u32 in final()
> int position; // current position (byte offset) in message
> union {
> @@ -1216,7 +1219,7 @@ struct airo_info {
> struct iw_spy_data spy_data;
> struct iw_public_data wireless_data;
> /* MIC stuff */
> - struct crypto_cipher *tfm;
> + struct crypto_sync_skcipher *tfm;
> mic_module mod[2];
> mic_statistics micstats;
> HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
> @@ -1291,14 +1294,14 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev);
> static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
> static void MoveWindow(miccntx *context, u32 micSeq);
> static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
> - struct crypto_cipher *tfm);
> + struct crypto_sync_skcipher *tfm);
> static void emmh32_init(emmh32_context *context);
> static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
> static void emmh32_final(emmh32_context *context, u8 digest[4]);
> static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
>
> static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len,
> - struct crypto_cipher *tfm)
> + struct crypto_sync_skcipher *tfm)
> {
> /* If the current MIC context is valid and its key is the same as
> * the MIC register, there's nothing to do.
> @@ -1359,7 +1362,7 @@ static int micsetup(struct airo_info *ai) {
> int i;
>
> if (ai->tfm == NULL)
> - ai->tfm = crypto_alloc_cipher("aes", 0, 0);
> + ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0);
>
> if (IS_ERR(ai->tfm)) {
> airo_print_err(ai->dev->name, "failed to load transform for AES");
> @@ -1624,37 +1627,31 @@ static void MoveWindow(miccntx *context, u32 micSeq)
>
> /* mic accumulate */
> #define MIC_ACCUM(val) \
> - context->accum += (u64)(val) * context->coeff[coeff_position++];
> -
> -static unsigned char aes_counter[16];
> + context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]);
You could alternatively call be32_to_cpu_array() after the AES encryption.
But this works too.
>
> /* expand the key to fill the MMH coefficient array */
> static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
> - struct crypto_cipher *tfm)
> + struct crypto_sync_skcipher *tfm)
> {
> /* take the keying material, expand if necessary, truncate at 16-bytes */
> /* run through AES counter mode to generate context->coeff[] */
>
> - int i,j;
> - u32 counter;
> - u8 *cipher, plain[16];
> -
> - crypto_cipher_setkey(tfm, pkey, 16);
> - counter = 0;
> - for (i = 0; i < ARRAY_SIZE(context->coeff); ) {
> - aes_counter[15] = (u8)(counter >> 0);
> - aes_counter[14] = (u8)(counter >> 8);
> - aes_counter[13] = (u8)(counter >> 16);
> - aes_counter[12] = (u8)(counter >> 24);
> - counter++;
> - memcpy (plain, aes_counter, 16);
> - crypto_cipher_encrypt_one(tfm, plain, plain);
> - cipher = plain;
> - for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
> - context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]);
> - j += 4;
> - }
> - }
> + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
> + struct scatterlist dst, src;
> + u8 iv[AES_BLOCK_SIZE] = {};
> + int ret;
> +
> + crypto_sync_skcipher_setkey(tfm, pkey, 16);
> +
> + sg_init_one(&dst, context->coeff, sizeof(context->coeff));
> + sg_init_one(&src, page_address(ZERO_PAGE(0)), sizeof(context->coeff));
Should add:
BUILD_BUG_ON(sizeof(context->coeff) > PAGE_SIZE);
Or alternatively, instead of using ZERO_PAGE, just memset() the buffer to zero
and encrypt it in-place. That would be less fragile.
> +
> + skcipher_request_set_sync_tfm(req, tfm);
> + skcipher_request_set_callback(req, 0, NULL, NULL);
> + skcipher_request_set_crypt(req, &src, &dst, sizeof(context->coeff), iv);
> +
> + ret = crypto_skcipher_encrypt(req);
> + WARN_ON_ONCE(ret);
> }
>
> /* prepare for calculation of a new mic */
> @@ -2415,7 +2412,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
> ai->shared, ai->shared_dma);
> }
> }
> - crypto_free_cipher(ai->tfm);
> + crypto_free_sync_skcipher(ai->tfm);
> del_airo_dev(ai);
> free_netdev( dev );
> }
> --
> 2.20.1
>
Otherwise this patch looks correct to me.
The actual crypto in this driver, on the other hand, looks very outdated and
broken. Apparently it's implementing some Cisco proprietary extension to WEP
that uses a universal hashing based MAC, where the hash key is generated from
AES-CTR. But the MAC is only 32 bits, and the universal hash (MMH) is
implemented incorrectly: there's an off-by-one error in emmh32_final() in the
code that is supposed to be an optimized version of 'sum % ((1ULL << 32) + 15)'.
Do we know whether anyone is actually using this, or is this just another old
driver that's sitting around unused?
- Eric
^ permalink raw reply
* [PATCH 11/11] wil6210: drop old event after wmi_call timeout
From: Maya Erez @ 2019-06-16 7:26 UTC (permalink / raw)
To: Kalle Valo; +Cc: Ahmad Masri, linux-wireless, wil6210, Maya Erez
In-Reply-To: <1560669967-23706-1-git-send-email-merez@codeaurora.org>
From: Ahmad Masri <amasri@codeaurora.org>
This change fixes a rare race condition of handling WMI events after
wmi_call expires.
wmi_recv_cmd immediately handles an event when reply_buf is defined and
a wmi_call is waiting for the event.
However, in case the wmi_call has already timed-out, there will be no
waiting/running wmi_call and the event will be queued in WMI queue and
will be handled later in wmi_event_handle.
Meanwhile, a new similar wmi_call for the same command and event may
be issued. In this case, when handling the queued event we got WARN_ON
printed.
Fixing this case as a valid timeout and drop the unexpected event.
Signed-off-by: Ahmad Masri <amasri@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
---
drivers/net/wireless/ath/wil6210/wmi.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 542ef15..475b1a2 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -3303,7 +3303,18 @@ static void wmi_event_handle(struct wil6210_priv *wil,
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id &&
wil->reply_mid == mid) {
- WARN_ON(wil->reply_buf);
+ if (wil->reply_buf) {
+ /* event received while wmi_call is waiting
+ * with a buffer. Such event should be handled
+ * in wmi_recv_cmd function. Handling the event
+ * here means a previous wmi_call was timeout.
+ * Drop the event and do not handle it.
+ */
+ wil_err(wil,
+ "Old event (%d, %s) while wmi_call is waiting. Drop it and Continue waiting\n",
+ id, eventid2name(id));
+ return;
+ }
wmi_evt_call_handler(vif, id, evt_data,
len - sizeof(*wmi));
--
1.9.1
^ permalink raw reply related
* [PATCH 02/11] wil6210: enlarge Tx status ring size
From: Maya Erez @ 2019-06-16 7:25 UTC (permalink / raw)
To: Kalle Valo; +Cc: Ahmad Masri, linux-wireless, wil6210, Maya Erez
In-Reply-To: <1560669967-23706-1-git-send-email-merez@codeaurora.org>
From: Ahmad Masri <amasri@codeaurora.org>
With multiple clients and in high throughput scenarios, Tx status ring
can get full and become a bottleneck in Tx transmission.
Set the default Tx status ring size order to 13, previous value was 12.
This will double the status ring size from 4K entries to 8K entries.
Signed-off-by: Ahmad Masri <amasri@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
---
drivers/net/wireless/ath/wil6210/txrx_edma.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h
index bb4ff28..e9e6ea9 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.h
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h
@@ -24,7 +24,7 @@
#define WIL_SRING_SIZE_ORDER_MAX (WIL_RING_SIZE_ORDER_MAX)
/* RX sring order should be bigger than RX ring order */
#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (12)
-#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (12)
+#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (14)
#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600)
#define WIL_DEFAULT_RX_STATUS_RING_ID 0
--
1.9.1
^ permalink raw reply related
* [PATCH 00/11] wil6210 patches
From: Maya Erez @ 2019-06-16 7:25 UTC (permalink / raw)
To: Kalle Valo; +Cc: Maya Erez, linux-wireless, wil6210
The following set of patces include multiple wil6210 bug fixes.
Ahmad Masri (4):
wil6210: enlarge Tx status ring size
wil6210: increase the frequency of status ring hw tail update
wil6210: set WIL_WMI_CALL_GENERAL_TO_MS as wmi_call timeout
wil6210: drop old event after wmi_call timeout
Alexei Avshalom Lazar (3):
wil6210: do not reset FW in STA to P2P client interface switch
wil6210: Add support for setting RBUFCAP configuration
wil6210: update cid boundary check of wil_find_cid/_by_idx()
Dedy Lansky (1):
wil6210: fix printout in wil_read_pmccfg
Maya Erez (2):
wil6210: clear FW and ucode log address
wil6210: publish max_msdu_size to FW on BCAST ring
Tzahi Sabo (1):
wil6210: add support for reading multiple RFs temperature via debugfs
drivers/net/wireless/ath/wil6210/cfg80211.c | 22 ++++-
drivers/net/wireless/ath/wil6210/debugfs.c | 88 +++++++++++++++---
drivers/net/wireless/ath/wil6210/main.c | 19 +++-
drivers/net/wireless/ath/wil6210/pcie_bus.c | 1 +
drivers/net/wireless/ath/wil6210/rx_reorder.c | 31 +++----
drivers/net/wireless/ath/wil6210/txrx.c | 9 +-
drivers/net/wireless/ath/wil6210/txrx_edma.c | 16 +++-
drivers/net/wireless/ath/wil6210/txrx_edma.h | 2 +-
drivers/net/wireless/ath/wil6210/wil6210.h | 6 ++
drivers/net/wireless/ath/wil6210/wmi.c | 127 ++++++++++++++++++++++----
drivers/net/wireless/ath/wil6210/wmi.h | 47 ++++++++--
11 files changed, 297 insertions(+), 71 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH 04/11] wil6210: Add support for setting RBUFCAP configuration
From: Maya Erez @ 2019-06-16 7:26 UTC (permalink / raw)
To: Kalle Valo; +Cc: Alexei Avshalom Lazar, linux-wireless, wil6210, Maya Erez
In-Reply-To: <1560669967-23706-1-git-send-email-merez@codeaurora.org>
From: Alexei Avshalom Lazar <ailizaro@codeaurora.org>
RBUFCAP support added in FW.
The RBUFCAP feature is amendment to the block ack mechanism to
prevent overloading of the recipient’s memory space, which may
happen in case the link speed is higher than STA’s capability
to process or consume incoming data.
The block ack policy (ba_policy) is now controlled by FW so driver
should ignore this field.
Add new debugfs "rbufcap" to configure RBUFCAP.
Signed-off-by: Alexei Avshalom Lazar <ailizaro@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
---
drivers/net/wireless/ath/wil6210/debugfs.c | 39 +++++++++++++++++++++++++++
drivers/net/wireless/ath/wil6210/rx_reorder.c | 31 ++++++++-------------
drivers/net/wireless/ath/wil6210/wil6210.h | 1 +
drivers/net/wireless/ath/wil6210/wmi.c | 39 +++++++++++++++++++++++++--
4 files changed, 88 insertions(+), 22 deletions(-)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 7a2c3fd..14778a1c 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -777,6 +777,44 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
.open = simple_open,
};
+static ssize_t wil_write_file_rbufcap(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ int val;
+ int rc;
+
+ rc = kstrtoint_from_user(buf, count, 0, &val);
+ if (rc) {
+ wil_err(wil, "Invalid argument\n");
+ return rc;
+ }
+ /* input value: negative to disable, 0 to use system default,
+ * 1..ring size to set descriptor threshold
+ */
+ wil_info(wil, "%s RBUFCAP, descriptors threshold - %d\n",
+ val < 0 ? "Disabling" : "Enabling", val);
+
+ if (!wil->ring_rx.va || val > wil->ring_rx.size) {
+ wil_err(wil, "Invalid descriptors threshold, %d\n", val);
+ return -EINVAL;
+ }
+
+ rc = wmi_rbufcap_cfg(wil, val < 0 ? 0 : 1, val < 0 ? 0 : val);
+ if (rc) {
+ wil_err(wil, "RBUFCAP config failed: %d\n", rc);
+ return rc;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_rbufcap = {
+ .write = wil_write_file_rbufcap,
+ .open = simple_open,
+};
+
/* block ack control, write:
* - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
* - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
@@ -2364,6 +2402,7 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
{"tx_latency", 0644, &fops_tx_latency},
{"link_stats", 0644, &fops_link_stats},
{"link_stats_global", 0644, &fops_link_stats_global},
+ {"rbufcap", 0244, &fops_rbufcap},
};
static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 1c79664..784239b 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -316,7 +316,7 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
u16 agg_timeout = le16_to_cpu(ba_timeout);
u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl);
struct wil_sta_info *sta;
- u16 agg_wsize = 0;
+ u16 agg_wsize;
/* bit 0: A-MSDU supported
* bit 1: policy (should be 0 for us)
* bits 2..5: TID
@@ -328,7 +328,6 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) &&
wil->amsdu_en && (param_set & BIT(0));
int ba_policy = param_set & BIT(1);
- u16 status = WLAN_STATUS_SUCCESS;
u16 ssn = seq_ctrl >> 4;
struct wil_tid_ampdu_rx *r;
int rc = 0;
@@ -355,27 +354,19 @@ int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn);
/* apply policies */
- if (ba_policy) {
- wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
- status = WLAN_STATUS_INVALID_QOS_PARAM;
- }
- if (status == WLAN_STATUS_SUCCESS) {
- if (req_agg_wsize == 0) {
- wil_dbg_misc(wil, "Suggest BACK wsize %d\n",
- wil->max_agg_wsize);
- agg_wsize = wil->max_agg_wsize;
- } else {
- agg_wsize = min_t(u16,
- wil->max_agg_wsize, req_agg_wsize);
- }
+ if (req_agg_wsize == 0) {
+ wil_dbg_misc(wil, "Suggest BACK wsize %d\n",
+ wil->max_agg_wsize);
+ agg_wsize = wil->max_agg_wsize;
+ } else {
+ agg_wsize = min_t(u16, wil->max_agg_wsize, req_agg_wsize);
}
rc = wil->txrx_ops.wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token,
- status, agg_amsdu, agg_wsize,
- agg_timeout);
- if (rc || (status != WLAN_STATUS_SUCCESS)) {
- wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
- status);
+ WLAN_STATUS_SUCCESS, agg_amsdu,
+ agg_wsize, agg_timeout);
+ if (rc) {
+ wil_err(wil, "do not apply ba, rc(%d)\n", rc);
goto out;
}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 4498403..75abec2 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1406,6 +1406,7 @@ int wmi_start_sched_scan(struct wil6210_priv *wil,
int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len);
int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
u8 channel, u16 duration_ms);
+int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold);
int reverse_memcmp(const void *cs, const void *ct, size_t count);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 0a0818f..298c918 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -484,6 +484,8 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_FT_REASSOC_CMD";
case WMI_UPDATE_FT_IES_CMDID:
return "WMI_UPDATE_FT_IES_CMD";
+ case WMI_RBUFCAP_CFG_CMDID:
+ return "WMI_RBUFCAP_CFG_CMD";
default:
return "Untracked CMD";
}
@@ -628,6 +630,8 @@ static const char *eventid2name(u16 eventid)
return "WMI_FT_AUTH_STATUS_EVENT";
case WMI_FT_REASSOC_STATUS_EVENTID:
return "WMI_FT_REASSOC_STATUS_EVENT";
+ case WMI_RBUFCAP_CFG_EVENTID:
+ return "WMI_RBUFCAP_CFG_EVENT";
default:
return "Untracked EVENT";
}
@@ -2124,6 +2128,37 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
return rc;
}
+int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold)
+{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
+ int rc;
+
+ struct wmi_rbufcap_cfg_cmd cmd = {
+ .enable = enable,
+ .rx_desc_threshold = cpu_to_le16(threshold),
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_rbufcap_cfg_event evt;
+ } __packed reply = {
+ .evt = {.status = WMI_FW_STATUS_FAILURE},
+ };
+
+ rc = wmi_call(wil, WMI_RBUFCAP_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
+ WMI_RBUFCAP_CFG_EVENTID, &reply, sizeof(reply),
+ WIL_WMI_CALL_GENERAL_TO_MS);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "RBUFCAP_CFG failed. status %d\n",
+ reply.evt.status);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
int wmi_pcp_start(struct wil6210_vif *vif,
int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
{
@@ -2715,7 +2750,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil,
.dialog_token = token,
.status_code = cpu_to_le16(status),
/* bit 0: A-MSDU supported
- * bit 1: policy (should be 0 for us)
+ * bit 1: policy (controlled by FW)
* bits 2..5: TID
* bits 6..15: buffer size
*/
@@ -2769,7 +2804,7 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
.dialog_token = token,
.status_code = cpu_to_le16(status),
/* bit 0: A-MSDU supported
- * bit 1: policy (should be 0 for us)
+ * bit 1: policy (controlled by FW)
* bits 2..5: TID
* bits 6..15: buffer size
*/
--
1.9.1
^ permalink raw reply related
* [PATCH 07/11] wil6210: update cid boundary check of wil_find_cid/_by_idx()
From: Maya Erez @ 2019-06-16 7:26 UTC (permalink / raw)
To: Kalle Valo; +Cc: Alexei Avshalom Lazar, linux-wireless, wil6210, Maya Erez
In-Reply-To: <1560669967-23706-1-git-send-email-merez@codeaurora.org>
From: Alexei Avshalom Lazar <ailizaro@codeaurora.org>
The return value of wil_find_cid()/wil_find_cid_by_idx() is
validated with the lower boundary value.
Check the upper boundary value as well.
Signed-off-by: Alexei Avshalom Lazar <ailizaro@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
---
drivers/net/wireless/ath/wil6210/cfg80211.c | 6 +++---
drivers/net/wireless/ath/wil6210/main.c | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 1a4223f..cd41a0b 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -380,8 +380,8 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy,
wil_dbg_misc(wil, "get_station: %pM CID %d MID %d\n", mac, cid,
vif->mid);
- if (cid < 0)
- return cid;
+ if (!wil_cid_valid(wil, cid))
+ return -ENOENT;
rc = wil_cid_fill_sinfo(vif, cid, sinfo);
@@ -417,7 +417,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy,
int rc;
int cid = wil_find_cid_by_idx(wil, vif->mid, idx);
- if (cid < 0)
+ if (!wil_cid_valid(wil, cid))
return -ENOENT;
ether_addr_copy(mac, wil->sta[cid].addr);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index f7b9e6b..173561f 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -340,7 +340,7 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
wil_dbg_misc(wil,
"Disconnect complete %pM, CID=%d, reason=%d\n",
bssid, cid, reason_code);
- if (cid >= 0) /* disconnect 1 peer */
+ if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */
wil_disconnect_cid_complete(vif, cid, reason_code);
} else { /* all */
wil_dbg_misc(wil, "Disconnect complete all\n");
@@ -452,7 +452,7 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
cid = wil_find_cid(wil, vif->mid, bssid);
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
bssid, cid, reason_code);
- if (cid >= 0) /* disconnect 1 peer */
+ if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */
wil_disconnect_cid(vif, cid, reason_code);
} else { /* all */
wil_dbg_misc(wil, "Disconnect all\n");
--
1.9.1
^ permalink raw reply related
* [PATCH 03/11] wil6210: increase the frequency of status ring hw tail update
From: Maya Erez @ 2019-06-16 7:25 UTC (permalink / raw)
To: Kalle Valo; +Cc: Ahmad Masri, linux-wireless, wil6210, Maya Erez
In-Reply-To: <1560669967-23706-1-git-send-email-merez@codeaurora.org>
From: Ahmad Masri <amasri@codeaurora.org>
The driver updates Tx status ring HW tail only after it finishes
processing the whole status ring, while the HW is still transmitting
from other transmit rings. This can cause back-pressure on HW if
no status entries are available.
Update HW tail of Tx status ring without waiting for the end of the
processing to help feeding back the HW with status entries and to allow
additional packet transmission.
Signed-off-by: Ahmad Masri <amasri@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
---
drivers/net/wireless/ath/wil6210/txrx_edma.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index 6140db5..dc040cd 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -26,6 +26,10 @@
#include "txrx.h"
#include "trace.h"
+/* Max number of entries (packets to complete) to update the hwtail of tx
+ * status ring. Should be power of 2
+ */
+#define WIL_EDMA_TX_SRING_UPDATE_HW_TAIL 128
#define WIL_EDMA_MAX_DATA_OFFSET (2)
/* RX buffer size must be aligned to 4 bytes */
#define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048)
@@ -1155,7 +1159,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
struct wil_net_stats *stats;
struct wil_tx_enhanced_desc *_d;
unsigned int ring_id;
- unsigned int num_descs;
+ unsigned int num_descs, num_statuses = 0;
int i;
u8 dr_bit; /* Descriptor Ready bit */
struct wil_ring_tx_status msg;
@@ -1276,6 +1280,11 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
}
again:
+ num_statuses++;
+ if (num_statuses % WIL_EDMA_TX_SRING_UPDATE_HW_TAIL == 0)
+ /* update HW tail to allow HW to push new statuses */
+ wil_w(wil, sring->hwtail, sring->swhead);
+
wil_sring_advance_swhead(sring);
wil_get_next_tx_status_msg(sring, &msg);
@@ -1286,8 +1295,9 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
if (desc_cnt)
wil_update_net_queues(wil, vif, NULL, false);
- /* Update the HW tail ptr (RD ptr) */
- wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size);
+ if (num_statuses % WIL_EDMA_TX_SRING_UPDATE_HW_TAIL != 0)
+ /* Update the HW tail ptr (RD ptr) */
+ wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size);
return desc_cnt;
}
--
1.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox