* [PATCH 1/4] mt76: move mt76x02_insert_hdr_pad in mt76-core module
From: Lorenzo Bianconi @ 2019-03-11 12:35 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, linux-wireless, lorenzo.bianconi
In-Reply-To: <cover.1552306908.git.lorenzo@kernel.org>
Move mt76x02_insert_hdr_pad in m76-core and rename it in
mt76_insert_hdr_pad in order to be used in mt76_dma_tx_queue_skb.
This is a preliminary patch in order to properly support tx dma
mapping for new chipsets (e.g. mt7615)
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 15 +++++++++++++++
drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 -
.../net/wireless/mediatek/mt76/mt76x02_txrx.c | 2 +-
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +-
.../net/wireless/mediatek/mt76/mt76x02_util.c | 16 ----------------
5 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 57136073e1fa..971d968c1b5f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -653,6 +653,21 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
return ((void *) IEEE80211_SKB_CB(skb)->status.status_driver_data);
}
+static inline int mt76_insert_hdr_pad(struct sk_buff *skb)
+{
+ int len = ieee80211_get_hdrlen_from_skb(skb);
+
+ if (len % 4 == 0)
+ return 0;
+
+ skb_push(skb, 2);
+ memmove(skb->data, skb->data + 2, len);
+
+ skb->data[len] = 0;
+ skb->data[len + 1] = 0;
+ return 2;
+}
+
void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 392b96fcb520..53ec8103a268 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -163,7 +163,6 @@ void mt76x02_set_tx_ackto(struct mt76x02_dev *dev);
void mt76x02_set_coverage_class(struct ieee80211_hw *hw,
s16 coverage_class);
int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val);
-int mt76x02_insert_hdr_pad(struct sk_buff *skb);
void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len);
bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update);
void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
index ce9ace11339d..f574866c7e9d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
@@ -165,7 +165,7 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
pid = mt76_tx_status_skb_add(mdev, wcid, skb);
txwi->pktid = pid;
- ret = mt76x02_insert_hdr_pad(skb);
+ ret = mt76_insert_hdr_pad(skb);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 8ab63255ba6f..6c3fc4cea283 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -82,7 +82,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
enum mt76_qsel qsel;
u32 flags;
- mt76x02_insert_hdr_pad(skb);
+ mt76_insert_hdr_pad(skb);
txwi = (struct mt76x02_txwi *)(skb->data - sizeof(struct mt76x02_txwi));
mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index b14a55737829..81d65319d3ea 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -566,22 +566,6 @@ void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update);
-int mt76x02_insert_hdr_pad(struct sk_buff *skb)
-{
- int len = ieee80211_get_hdrlen_from_skb(skb);
-
- if (len % 4 == 0)
- return 0;
-
- skb_push(skb, 2);
- memmove(skb->data, skb->data + 2, len);
-
- skb->data[len] = 0;
- skb->data[len + 1] = 0;
- return 2;
-}
-EXPORT_SYMBOL_GPL(mt76x02_insert_hdr_pad);
-
void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len)
{
int hdrlen;
--
2.20.1
^ permalink raw reply related
* [PATCH 0/4] move skb mapping before configuring txwi
From: Lorenzo Bianconi @ 2019-03-11 12:35 UTC (permalink / raw)
To: nbd; +Cc: ryder.lee, roychl666, linux-wireless, lorenzo.bianconi
Move skb dma mapping before configuring txwi since new chipsets
(e.g. mt7615) will need dma addresses to properly configure txwi.
Introduce temporary tx_aligned4_skbs variable in order to tell mt76 layer
if it is necessary to align the 802.11 header (it will be removed as soon
as mac80211 will take care of it)
Lorenzo Bianconi (4):
mt76: move mt76x02_insert_hdr_pad in mt76-core module
mt76: mmio: move mt76_insert_hdr_pad in mt76_dma_tx_queue_skb
mt76: move skb dma mapping before running tx_prepare_skb
mt76: introduce mt76_tx_info data structure
drivers/net/wireless/mediatek/mt76/dma.c | 55 +++++++++----------
drivers/net/wireless/mediatek/mt76/mt76.h | 25 ++++++++-
.../net/wireless/mediatek/mt76/mt7603/mac.c | 2 +-
.../wireless/mediatek/mt76/mt7603/mt7603.h | 2 +-
.../net/wireless/mediatek/mt76/mt76x0/pci.c | 1 +
drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +-
.../net/wireless/mediatek/mt76/mt76x02_txrx.c | 21 +++----
.../net/wireless/mediatek/mt76/mt76x02_usb.h | 2 +-
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 4 +-
.../net/wireless/mediatek/mt76/mt76x02_util.c | 16 ------
.../net/wireless/mediatek/mt76/mt76x2/pci.c | 1 +
11 files changed, 68 insertions(+), 64 deletions(-)
--
2.20.1
^ permalink raw reply
* Re: [PATCH] mt76: fix schedule while atomic in mt76x02_reset_state
From: Lorenzo Bianconi @ 2019-03-11 10:11 UTC (permalink / raw)
To: Felix Fietkau; +Cc: Lorenzo Bianconi, linux-wireless, sgruszka
In-Reply-To: <09c3c2ec-071f-4fd9-927d-2981b65fe29f@nbd.name>
[-- Attachment #1: Type: text/plain, Size: 3103 bytes --]
> On 2019-03-10 23:47, Lorenzo Bianconi wrote:
> > Fix following schedule while atomic mt76x02_reset_state
> > since synchronize_rcu is run inside a RCU section
> >
> > [44036.944222] mt76x2e 0000:06:00.0: MCU message 31 (seq 3) timed out
> > [44036.944281] BUG: sleeping function called from invalid context at kernel/rcu/tree_exp.h:818
> > [44036.944284] in_atomic(): 1, irqs_disabled(): 0, pid: 28066, name: kworker/u4:1
> > [44036.944287] INFO: lockdep is turned off.
> > [44036.944292] CPU: 1 PID: 28066 Comm: kworker/u4:1 Tainted: G W 5.0.0-rc7-wdn-t1+ #7
> > [44036.944294] Hardware name: Dell Inc. Studio XPS 1340/0K183D, BIOS A11 09/08/2009
> > [44036.944305] Workqueue: phy1 mt76x02_wdt_work [mt76x02_lib]
> > [44036.944308] Call Trace:
> > [44036.944317] dump_stack+0x67/0x90
> > [44036.944322] ___might_sleep.cold.88+0x9f/0xaf
> > [44036.944327] rcu_blocking_is_gp+0x13/0x50
> > [44036.944330] synchronize_rcu+0x17/0x80
> > [44036.944337] mt76_sta_state+0x138/0x1d0 [mt76]
> > [44036.944349] mt76x02_wdt_work+0x1c9/0x610 [mt76x02_lib]
> > [44036.944355] process_one_work+0x2a5/0x620
> > [44036.944361] worker_thread+0x35/0x3e0
> > [44036.944368] kthread+0x11c/0x140
> > [44036.944376] ret_from_fork+0x3a/0x50
> > [44036.944384] BUG: scheduling while atomic: kworker/u4:1/28066/0x00000002
> > [44036.944387] INFO: lockdep is turned off.
> > [44036.944389] Modules linked in: cmac ctr ccm af_packet snd_hda_codec_hdmi
> >
> > Introduce __mt76_sta_remove in order to run sta_remove without holding dev->mutex.
> > Move __mt76_sta_remove outside RCU section in mt76x02_reset_state
> >
> > Fixes: e4ebb8b403d1 ("mt76: mt76x2: implement full device restart on watchdog reset")
> > Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> > index 6a34a6afcfe4..898afcbcdf52 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> > @@ -419,6 +419,7 @@ static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
> > mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key);
> > }
> >
> > +/* need to run with mt76.mutex held */
> > static void mt76x02_reset_state(struct mt76x02_dev *dev)
> You can replace that comment with a call to lockdep_assert_held in the
> function.
>
> > @@ -426,11 +427,11 @@ static void mt76x02_reset_state(struct mt76x02_dev *dev)
> > clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
> >
> > rcu_read_lock();
> > -
> > ieee80211_iter_keys_rcu(dev->mt76.hw, NULL, mt76x02_key_sync, NULL);
> > + rcu_read_unlock();
> >
> > for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) {
> > - struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[i]);
> > + struct mt76_wcid *wcid = dev->mt76.wcid[i];
> This should use rcu_dereference_protected() instead of accessing the
> pointer directly.
>
ack, I will fix them in v2.
Regards,
Lorenzo
> Thanks,
>
> - Felix
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH] mt76: fix schedule while atomic in mt76x02_reset_state
From: Felix Fietkau @ 2019-03-11 10:07 UTC (permalink / raw)
To: Lorenzo Bianconi; +Cc: linux-wireless, sgruszka, lorenzo.bianconi
In-Reply-To: <510d7b670f673a4662ed672b0ce3d9f75512b100.1552251427.git.lorenzo@kernel.org>
On 2019-03-10 23:47, Lorenzo Bianconi wrote:
> Fix following schedule while atomic mt76x02_reset_state
> since synchronize_rcu is run inside a RCU section
>
> [44036.944222] mt76x2e 0000:06:00.0: MCU message 31 (seq 3) timed out
> [44036.944281] BUG: sleeping function called from invalid context at kernel/rcu/tree_exp.h:818
> [44036.944284] in_atomic(): 1, irqs_disabled(): 0, pid: 28066, name: kworker/u4:1
> [44036.944287] INFO: lockdep is turned off.
> [44036.944292] CPU: 1 PID: 28066 Comm: kworker/u4:1 Tainted: G W 5.0.0-rc7-wdn-t1+ #7
> [44036.944294] Hardware name: Dell Inc. Studio XPS 1340/0K183D, BIOS A11 09/08/2009
> [44036.944305] Workqueue: phy1 mt76x02_wdt_work [mt76x02_lib]
> [44036.944308] Call Trace:
> [44036.944317] dump_stack+0x67/0x90
> [44036.944322] ___might_sleep.cold.88+0x9f/0xaf
> [44036.944327] rcu_blocking_is_gp+0x13/0x50
> [44036.944330] synchronize_rcu+0x17/0x80
> [44036.944337] mt76_sta_state+0x138/0x1d0 [mt76]
> [44036.944349] mt76x02_wdt_work+0x1c9/0x610 [mt76x02_lib]
> [44036.944355] process_one_work+0x2a5/0x620
> [44036.944361] worker_thread+0x35/0x3e0
> [44036.944368] kthread+0x11c/0x140
> [44036.944376] ret_from_fork+0x3a/0x50
> [44036.944384] BUG: scheduling while atomic: kworker/u4:1/28066/0x00000002
> [44036.944387] INFO: lockdep is turned off.
> [44036.944389] Modules linked in: cmac ctr ccm af_packet snd_hda_codec_hdmi
>
> Introduce __mt76_sta_remove in order to run sta_remove without holding dev->mutex.
> Move __mt76_sta_remove outside RCU section in mt76x02_reset_state
>
> Fixes: e4ebb8b403d1 ("mt76: mt76x2: implement full device restart on watchdog reset")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> index 6a34a6afcfe4..898afcbcdf52 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> @@ -419,6 +419,7 @@ static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
> mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key);
> }
>
> +/* need to run with mt76.mutex held */
> static void mt76x02_reset_state(struct mt76x02_dev *dev)
You can replace that comment with a call to lockdep_assert_held in the
function.
> @@ -426,11 +427,11 @@ static void mt76x02_reset_state(struct mt76x02_dev *dev)
> clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
>
> rcu_read_lock();
> -
> ieee80211_iter_keys_rcu(dev->mt76.hw, NULL, mt76x02_key_sync, NULL);
> + rcu_read_unlock();
>
> for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) {
> - struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[i]);
> + struct mt76_wcid *wcid = dev->mt76.wcid[i];
This should use rcu_dereference_protected() instead of accessing the
pointer directly.
Thanks,
- Felix
^ permalink raw reply
* Re: [PATCH] net: iwlegacy: fix potential NULL pointer dereferences
From: Stanislaw Gruszka @ 2019-03-11 9:16 UTC (permalink / raw)
To: Kangjie Lu
Cc: pakki001, Kalle Valo, David S. Miller, linux-wireless, netdev,
linux-kernel
In-Reply-To: <20190311073758.31038-1-kjlu@umn.edu>
On Mon, Mar 11, 2019 at 02:37:57AM -0500, Kangjie Lu wrote:
> In case create_singlethread_workqueue fails, the fix immediately
> return to avoid NULL pointer dereferences.
>
> Signed-off-by: Kangjie Lu <kjlu@umn.edu>
> ---
> drivers/net/wireless/intel/iwlegacy/3945-mac.c | 2 ++
> drivers/net/wireless/intel/iwlegacy/4965-mac.c | 2 ++
> 2 files changed, 4 insertions(+)
>
> diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
> index 271977f7fbb0..d23ee2ca0c8e 100644
> --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
> +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
> @@ -3403,6 +3403,8 @@ static void
> il3945_setup_deferred_work(struct il_priv *il)
> {
> il->workqueue = create_singlethread_workqueue(DRV_NAME);
> + if (!il->workqueue)
> + return;
This is not full fix since we will crash later without setup various
structures in il3945_setup_deferred_work. The driver is pretty
much legacy and worked for decade (or maybe more) without NULL
dereference of il->workqueue. I do not see need to fix _potential_
problems as fix can introduce more harm than good.
Stanislaw
^ permalink raw reply
* Re: [PATCH] net: brcm80211: fix potential NULL pointer dereferences
From: Arend Van Spriel @ 2019-03-11 9:11 UTC (permalink / raw)
To: Kangjie Lu
Cc: pakki001, Franky Lin, Hante Meuleman, Chi-Hsien Lin, Wright Feng,
Kalle Valo, David S. Miller, Rafał Miłecki,
Stefan Wahren, Chung-Hsien Hsu, linux-wireless,
brcm80211-dev-list.pdl, brcm80211-dev-list, netdev, linux-kernel
In-Reply-To: <20190311073232.30807-1-kjlu@umn.edu>
On 3/11/2019 8:32 AM, Kangjie Lu wrote:
> In case kmemdup fails, the fix returns -ENOMEM to avoid NULL
> pointer dereferences.
Hi Kangjie Lu,
Are you fixing any reported issue with this? If you looked further you
would see that this function is called in two places and the return
value is not checked there. So your patch is not changing anything.
Please sent a V2 addressing my comments below.
Thanks,
Arend
> Signed-off-by: Kangjie Lu <kjlu@umn.edu>
> ---
> drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> index e92f6351bd22..d903a45e7b68 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> @@ -5464,6 +5464,9 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
> conn_info->req_ie =
> kmemdup(cfg->extra_buf, conn_info->req_ie_len,
> GFP_KERNEL);
> + if (!conn_info->req_ie)
> + return -ENOMEM;
No need to return an error here. Instead set conn_info->req_ie_len to
zero here.
> +
> } else {
> conn_info->req_ie_len = 0;
> conn_info->req_ie = NULL;
> @@ -5480,6 +5483,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
> conn_info->resp_ie =
> kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
> GFP_KERNEL);
> + if (!conn_info->resp_ie)
> + return -ENOMEM;
Same here for conn_info->resp_ie_len.
> } else {
> conn_info->resp_ie_len = 0;
> conn_info->resp_ie = NULL;
>
^ permalink raw reply
* [PATCH] iommu/amd: fix sg->dma_address for sg->offset bigger than PAGE_SIZE
From: Stanislaw Gruszka @ 2019-03-11 9:03 UTC (permalink / raw)
To: Rosen Penev, Joerg Roedel
Cc: Lorenzo Bianconi, linux-wireless, Samuel Sieb, Alexander Duyck,
iommu, linux-kernel, linux-nvme, jan.viktorin
In-Reply-To: <20190311084319.GA3310@redhat.com>
Take into account that sg->offset can be bigger than PAGE_SIZE when
setting segment sg->dma_address. Otherwise sg->dma_address will point
at diffrent page, what makes DMA not possible with erros like this:
xhci_hcd 0000:38:00.3: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0000 address=0x00000000fdaa70c0 flags=0x0020]
xhci_hcd 0000:38:00.3: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0000 address=0x00000000fdaa7040 flags=0x0020]
xhci_hcd 0000:38:00.3: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0000 address=0x00000000fdaa7080 flags=0x0020]
xhci_hcd 0000:38:00.3: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0000 address=0x00000000fdaa7100 flags=0x0020]
xhci_hcd 0000:38:00.3: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x0000 address=0x00000000fdaa7000 flags=0x0020]
Additinally with wrong sg->dma_address unmap_sg will free wrong pages,
what what can cause crashes like this:
Feb 28 19:27:45 kernel: BUG: Bad page state in process cinnamon pfn:39e8b1
Feb 28 19:27:45 kernel: Disabling lock debugging due to kernel taint
Feb 28 19:27:45 kernel: flags: 0x2ffff0000000000()
Feb 28 19:27:45 kernel: raw: 02ffff0000000000 0000000000000000 ffffffff00000301 0000000000000000
Feb 28 19:27:45 kernel: raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000
Feb 28 19:27:45 kernel: page dumped because: nonzero _refcount
Feb 28 19:27:45 kernel: Modules linked in: ccm fuse arc4 nct6775 hwmon_vid amdgpu nls_iso8859_1 nls_cp437 edac_mce_amd vfat fat kvm_amd ccp rng_core kvm mt76x0u mt76x0_common mt76x02_usb irqbypass mt76_usb mt76x02_lib mt76 crct10dif_pclmul crc32_pclmul chash mac80211 amd_iommu_v2 ghash_clmulni_intel gpu_sched i2c_algo_bit ttm wmi_bmof snd_hda_codec_realtek snd_hda_codec_generic drm_kms_helper snd_hda_codec_hdmi snd_hda_intel drm snd_hda_codec aesni_intel snd_hda_core snd_hwdep aes_x86_64 crypto_simd snd_pcm cfg80211 cryptd mousedev snd_timer glue_helper pcspkr r8169 input_leds realtek agpgart libphy rfkill snd syscopyarea sysfillrect sysimgblt fb_sys_fops soundcore sp5100_tco k10temp i2c_piix4 wmi evdev gpio_amdpt pinctrl_amd mac_hid pcc_cpufreq acpi_cpufreq sg ip_tables x_tables ext4(E) crc32c_generic(E) crc16(E) mbcache(E) jbd2(E) fscrypto(E) sd_mod(E) hid_generic(E) usbhid(E) hid(E) dm_mod(E) serio_raw(E) atkbd(E) libps2(E) crc32c_intel(E) ahci(E) libahci(E) libata(E) xhci_pci(E)
xhci_hcd(E)
Feb 28 19:27:45 kernel: scsi_mod(E) i8042(E) serio(E) bcache(E) crc64(E)
Feb 28 19:27:45 kernel: CPU: 2 PID: 896 Comm: cinnamon Tainted: G B W E 4.20.12-arch1-1-custom #1
Feb 28 19:27:45 kernel: Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./B450M Pro4, BIOS P1.20 06/26/2018
Feb 28 19:27:45 kernel: Call Trace:
Feb 28 19:27:45 kernel: dump_stack+0x5c/0x80
Feb 28 19:27:45 kernel: bad_page.cold.29+0x7f/0xb2
Feb 28 19:27:45 kernel: __free_pages_ok+0x2c0/0x2d0
Feb 28 19:27:45 kernel: skb_release_data+0x96/0x180
Feb 28 19:27:45 kernel: __kfree_skb+0xe/0x20
Feb 28 19:27:45 kernel: tcp_recvmsg+0x894/0xc60
Feb 28 19:27:45 kernel: ? reuse_swap_page+0x120/0x340
Feb 28 19:27:45 kernel: ? ptep_set_access_flags+0x23/0x30
Feb 28 19:27:45 kernel: inet_recvmsg+0x5b/0x100
Feb 28 19:27:45 kernel: __sys_recvfrom+0xc3/0x180
Feb 28 19:27:45 kernel: ? handle_mm_fault+0x10a/0x250
Feb 28 19:27:45 kernel: ? syscall_trace_enter+0x1d3/0x2d0
Feb 28 19:27:45 kernel: ? __audit_syscall_exit+0x22a/0x290
Feb 28 19:27:45 kernel: __x64_sys_recvfrom+0x24/0x30
Feb 28 19:27:45 kernel: do_syscall_64+0x5b/0x170
Feb 28 19:27:45 kernel: entry_SYSCALL_64_after_hwframe+0x44/0xa9
Cc: stable@vger.kernel.org
Reported-and-tested-by: jan.viktorin@gmail.com
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/iommu/amd_iommu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 6b0760dafb3e..949621f33624 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2604,7 +2604,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
/* Everything is mapped - write the right values into s->dma_address */
for_each_sg(sglist, s, nelems, i) {
- s->dma_address += address + s->offset;
+ s->dma_address += address + (s->offset & ~PAGE_MASK);
s->dma_length = s->length;
}
--
2.7.5
^ permalink raw reply related
* Re: MT76x2U crashes XHCI driver on AMD Ryzen system
From: Stanislaw Gruszka @ 2019-03-11 8:43 UTC (permalink / raw)
To: Rosen Penev
Cc: Joerg Roedel, Lorenzo Bianconi, linux-wireless, Samuel Sieb,
Alexander Duyck, iommu, linux-kernel, linux-nvme, jan.viktorin
In-Reply-To: <CAKxU2N-k-9DCYBv6W3CohL963dr3AeY3VHyt8FrUuo=BfacDsw@mail.gmail.com>
On Sun, Mar 03, 2019 at 11:20:45PM -0800, Rosen Penev wrote:
> On Sun, Mar 3, 2019 at 11:10 PM Stanislaw Gruszka <sgruszka@redhat.com> wrote:
> >
> > On Thu, Feb 28, 2019 at 02:40:29PM +0100, Joerg Roedel wrote:
> > > On Thu, Feb 28, 2019 at 01:19:48PM +0100, Stanislaw Gruszka wrote:
> > > > Nevermind, the patch is wrong, s->dma_address is initalized in sg_num_pages().
> > >
> > > Yes, it is. In sg_num_pages() the offset into the IOMMU mapping is
> > > stored in s->dma_address, taking also the segment boundary mask into
> > > account. map_sg() later only adds the base-address to that.
> >
> > I have some more info about the issues in
> > https://bugzilla.kernel.org/show_bug.cgi?id=202673
> >
> > We have some bugs in mt76. Apparently we should not use
> > page_frag_alloc() with size bigger than PAGE_SIZE as page_frag_alloc()
> > can fallback to single page allocation. And also we should not make
> > sizes unaligned as pointed in commit:
> > 3bed3cc4156e ("net: Do not allocate page fragments that are not skb aligned"
> As a small and totally unrelated note, page_frag_alloc is only used in
> mt76 and the nvme driver ;)
And there is nvme problem on AMD IOMMU:
https://bugzilla.kernel.org/show_bug.cgi?id=202665
While page_frag_alloc() should be used with cautious, at least care of
size alignment with ARCH_DMA_MINALIGN (not for IOMMU, but standard arch
dma), at this point I think some of those issues are AMD IOMMU problems.
> > However after fixing that mt76usb still did not work. To make things
> > work we had to change rx frag size from 2048 to PAGE_SIZE and change
> > virt_to_head_page() to virt_to_page() when setting SG's.
>
> > I think I understand why first change was needed. If we do 2 separate
> > dma maps of 2 different buffers in single page i.e (PAGE + off=0
> > and PAGE + off=2048) it causes problem. So either map_sg() return
> > error which mt76usb does not handle correctly or there is issue
> > in AMD IOMMU because two dma maps use the same page.
Any comment on that? Is fine or not to do 2 or more dma mappings
within the same single page on AMD IOMMU? If not, is there any
mechanism for drivers to find out about this limitation to prevent
to prepare wrong SG buffers?
> > But I don't understand why the second change was needed. Without
> > it we have issue with incorrect page->_refcount . It is somehow
> > related with AMD IOMMU, because on different platforms we do not
> > have such problems.
I think I found a bug in amd iommu code when setting sg->dma_address
with sg->offset > PAGE_SIZE. Will post fix shortly.
Stanislaw
^ permalink raw reply
* [PATCH] ath10k: avoid leaving .bss_info_changed prematurely
From: Sven Eckelmann @ 2019-03-11 8:31 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Sven Eckelmann, Kalle Valo, Sriram R
From: Sven Eckelmann <seckelmann@datto.com>
ath10k_bss_info_changed() handles various events from the upper layers. It
parses the changed bitfield and then configures the driver/firmware
accordingly. Each detected event is handled in a separate scope which is
independent of each other - but in the same function.
The commit f279294e9ee2 ("ath10k: add support for configuring management
packet rate") changed this behavior by returning from this function
prematurely when some precondition was not fulfilled. All new event
handlers added after the BSS_CHANGED_BASIC_RATES event handler would then
also be skipped.
Signed-off-by: Sven Eckelmann <seckelmann@datto.com>
---
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: Sriram R <srirrama@codeaurora.org>
Only compile tested
---
drivers/net/wireless/ath/ath10k/mac.c | 64 ++++++++++++++++-----------
1 file changed, 38 insertions(+), 26 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b73c23d4ce86..b1d0741c7861 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5578,6 +5578,40 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
mutex_unlock(&ar->conf_mutex);
}
+static void ath10k_recalculate_mgmt_rate(struct ath10k *ar,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ const struct ieee80211_supported_band *sband;
+ struct cfg80211_chan_def def;
+ u8 basic_rate_idx;
+ int hw_rate_code;
+ u32 vdev_param;
+ u16 bitrate;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ sband = ar->hw->wiphy->bands[def.chan->band];
+ basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
+ bitrate = sband->bitrates[basic_rate_idx].bitrate;
+
+ hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate);
+ if (hw_rate_code < 0) {
+ ath10k_warn(ar, "bitrate not supported %d\n", bitrate);
+ return;
+ }
+
+ vdev_param = ar->wmi.vdev_param->mgmt_rate;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+ hw_rate_code);
+ if (ret)
+ ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret);
+}
+
static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@@ -5588,10 +5622,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
struct cfg80211_chan_def def;
u32 vdev_param, pdev_param, slottime, preamble;
u16 bitrate, hw_value;
- u8 rate, basic_rate_idx;
- int rateidx, ret = 0, hw_rate_code;
+ u8 rate;
+ int rateidx, ret = 0;
enum nl80211_band band;
- const struct ieee80211_supported_band *sband;
mutex_lock(&ar->conf_mutex);
@@ -5811,29 +5844,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
}
- if (changed & BSS_CHANGED_BASIC_RATES) {
- if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) {
- mutex_unlock(&ar->conf_mutex);
- return;
- }
-
- sband = ar->hw->wiphy->bands[def.chan->band];
- basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
- bitrate = sband->bitrates[basic_rate_idx].bitrate;
-
- hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate);
- if (hw_rate_code < 0) {
- ath10k_warn(ar, "bitrate not supported %d\n", bitrate);
- mutex_unlock(&ar->conf_mutex);
- return;
- }
-
- vdev_param = ar->wmi.vdev_param->mgmt_rate;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- hw_rate_code);
- if (ret)
- ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret);
- }
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ ath10k_recalculate_mgmt_rate(ar, vif);
mutex_unlock(&ar->conf_mutex);
}
--
2.20.1
^ permalink raw reply related
* [PATCH] net: wireless: fix missing checks for ioremap
From: Kangjie Lu @ 2019-03-11 7:54 UTC (permalink / raw)
To: kjlu
Cc: pakki001, Kalle Valo, David S. Miller, linux-wireless, netdev,
linux-kernel
ioremap could fail and returns NULL. The fix actively checks
its return value and handles potential failures.
Signed-off-by: Kangjie Lu <kjlu@umn.edu>
---
drivers/net/wireless/ray_cs.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 44a943d18b84..cecd18a2f2de 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -394,6 +394,10 @@ static int ray_config(struct pcmcia_device *link)
goto failed;
local->sram = ioremap(link->resource[2]->start,
resource_size(link->resource[2]));
+ if (!local->sram) {
+ ret = -ENOMEM;
+ goto failed;
+ }
/*** Set up 16k window for shared memory (receive buffer) ***************/
link->resource[3]->flags |=
@@ -408,6 +412,10 @@ static int ray_config(struct pcmcia_device *link)
goto failed;
local->rmem = ioremap(link->resource[3]->start,
resource_size(link->resource[3]));
+ if (!local->rmem) {
+ ret = -ENOMEM;
+ goto failed;
+ }
/*** Set up window for attribute memory ***********************************/
link->resource[4]->flags |=
@@ -422,6 +430,10 @@ static int ray_config(struct pcmcia_device *link)
goto failed;
local->amem = ioremap(link->resource[4]->start,
resource_size(link->resource[4]));
+ if (!local->amem) {
+ ret = -ENOMEM;
+ goto failed;
+ }
dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram);
dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem);
--
2.17.1
^ permalink raw reply related
* Re: [PATCH] iwlwifi: mvm: Change an 'else if' into an 'else' in iwl_mvm_send_add_bcast_sta
From: Luca Coelho @ 2019-03-11 7:45 UTC (permalink / raw)
To: Nick Desaulniers, Nathan Chancellor
Cc: Johannes Berg, Emmanuel Grumbach, Intel Linux Wireless,
Kalle Valo, linux-wireless, netdev, LKML, clang-built-linux
In-Reply-To: <CAKwvOdn183kWz=+6robC44m4YWPXBLVJzhxL6f9jftvRi-=sxA@mail.gmail.com>
On Thu, 2019-03-07 at 16:08 -0800, Nick Desaulniers wrote:
> On Thu, Mar 7, 2019 at 4:03 PM Nathan Chancellor
> <natechancellor@gmail.com> wrote:
> > When building with -Wsometimes-uninitialized, Clang warns:
> >
> > drivers/net/wireless/intel/iwlwifi/mvm/sta.c:2114:12: warning:
> > variable
> > 'queue' is used uninitialized whenever 'if' condition is false
> > [-Wsometimes-uninitialized]
> >
> > Clang can't evaluate at this point that WARN(1, ...) always returns
> > true
> > because __ret_warn_on is defined as !!(condition), which isn't
> > immediately evaluated as 1. Change this branch to else so that it's
> > clear to Clang that we intend to bail out here.
> >
> > Link: https://github.com/ClangBuiltLinux/linux/issues/399
> > Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
>
> Thanks for the simple fix.
> Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Thanks for the patch and for the review!
I have applied it in our internal tree and it will reach the mainline
following our normal upstreaming process.
--
Cheers,
Luca.
^ permalink raw reply
* [PATCH] net: mwifiex: fix a NULL pointer dereference
From: Kangjie Lu @ 2019-03-11 7:43 UTC (permalink / raw)
To: kjlu
Cc: pakki001, Amitkumar Karwar, Nishant Sarmukadam, Ganapathi Bhat,
Xinming Hu, Kalle Valo, David S. Miller, linux-wireless, netdev,
linux-kernel
In case dev_alloc_skb fails, the fix returns -ENOMEM to avoid
NULL pointer dereference.
Signed-off-by: Kangjie Lu <kjlu@umn.edu>
---
drivers/net/wireless/marvell/mwifiex/cmdevt.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 60db2b969e20..5565f18039ab 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -341,6 +341,12 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
sleep_cfm_tmp =
dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm)
+ MWIFIEX_TYPE_LEN);
+ if (!sleep_cfm_tmp) {
+ mwifiex_dbg(adapter, ERROR,
+ "SLEEP_CFM: dev_alloc_skb failed\n");
+ return -ENOMEM;
+ }
+
skb_put(sleep_cfm_tmp, sizeof(struct mwifiex_opt_sleep_confirm)
+ MWIFIEX_TYPE_LEN);
put_unaligned_le32(MWIFIEX_USB_TYPE_CMD, sleep_cfm_tmp->data);
--
2.17.1
^ permalink raw reply related
* [PATCH] net: brcm80211: fix potential NULL pointer dereferences
From: Kangjie Lu @ 2019-03-11 7:32 UTC (permalink / raw)
To: kjlu
Cc: pakki001, Arend van Spriel, Franky Lin, Hante Meuleman,
Chi-Hsien Lin, Wright Feng, Kalle Valo, David S. Miller,
Rafał Miłecki, Stefan Wahren, Chung-Hsien Hsu,
linux-wireless, brcm80211-dev-list.pdl, brcm80211-dev-list,
netdev, linux-kernel
In case kmemdup fails, the fix returns -ENOMEM to avoid NULL
pointer dereferences.
Signed-off-by: Kangjie Lu <kjlu@umn.edu>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index e92f6351bd22..d903a45e7b68 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5464,6 +5464,9 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
conn_info->req_ie =
kmemdup(cfg->extra_buf, conn_info->req_ie_len,
GFP_KERNEL);
+ if (!conn_info->req_ie)
+ return -ENOMEM;
+
} else {
conn_info->req_ie_len = 0;
conn_info->req_ie = NULL;
@@ -5480,6 +5483,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
conn_info->resp_ie =
kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
GFP_KERNEL);
+ if (!conn_info->resp_ie)
+ return -ENOMEM;
} else {
conn_info->resp_ie_len = 0;
conn_info->resp_ie = NULL;
--
2.17.1
^ permalink raw reply related
* [PATCH] net: iwlegacy: fix potential NULL pointer dereferences
From: Kangjie Lu @ 2019-03-11 7:37 UTC (permalink / raw)
To: kjlu
Cc: pakki001, Stanislaw Gruszka, Kalle Valo, David S. Miller,
linux-wireless, netdev, linux-kernel
In case create_singlethread_workqueue fails, the fix immediately
return to avoid NULL pointer dereferences.
Signed-off-by: Kangjie Lu <kjlu@umn.edu>
---
drivers/net/wireless/intel/iwlegacy/3945-mac.c | 2 ++
drivers/net/wireless/intel/iwlegacy/4965-mac.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
index 271977f7fbb0..d23ee2ca0c8e 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
@@ -3403,6 +3403,8 @@ static void
il3945_setup_deferred_work(struct il_priv *il)
{
il->workqueue = create_singlethread_workqueue(DRV_NAME);
+ if (!il->workqueue)
+ return;
init_waitqueue_head(&il->wait_command_queue);
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
index 94222ae464ae..2c555c9f1ff4 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -6236,6 +6236,8 @@ static void
il4965_setup_deferred_work(struct il_priv *il)
{
il->workqueue = create_singlethread_workqueue(DRV_NAME);
+ if (!il->workqueue)
+ return;
init_waitqueue_head(&il->wait_command_queue);
--
2.17.1
^ permalink raw reply related
* Re: Nokia N900: wl1251 spi3.0: EOW timed out on
From: Vignesh Raghavendra @ 2019-03-11 7:21 UTC (permalink / raw)
To: Merlijn Wajer, kvalo@codeaurora.org
Cc: linux-omap, linux-wireless@vger.kernel.org, Tony Lindgren,
Sebastian Reichel, Pavel Machek, linux-kernel@vger.kernel.org,
broonie@kernel.org
In-Reply-To: <1b2918b4-1765-5aba-4752-1d04bdfea925@wizzup.org>
On 11/03/19 12:53 AM, Merlijn Wajer wrote:
> Hi,
>
> On 10/03/2019 05:16, Vignesh Raghavendra wrote:
>> Hi.
>>
>> On 10-Mar-19 6:23 AM, Merlijn Wajer wrote:
>>>
>>> Hi,
>>>
>>> On 10/03/2019 00:22, Merlijn Wajer wrote:
>>>> Hi,
>>>>
>>>> I just migrated to Linux 5.0 (from 4.15) on my Nokia N900, and I'm
>>>> getting a lot of messages like this:
>>>>
>>>>> wl1251 spi3.0: EOW timed out
>>
>>
>> Could you try if this patch fixes the issue? This is part of latest mainline tree but not part of 5.0:
>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=baf8b9f8d260c55a86405f70a384c29cda888476
>
> This seems to fix the issue. Would it make sense to queue this for an
> upcoming fixes release for 5.0?
>
Patch carries "Cc: stable@vger.kernel.org" tag. So, will be backported
to stable trees. It will be part of one of 5.0.y stable releases.
> Cheers,
> Merlijn
>
--
Regards
Vignesh
^ permalink raw reply
* Re: [PATCHv3 8/9] ath10k: Add new api to support TID specific configuration
From: Dan Carpenter @ 2019-03-11 7:02 UTC (permalink / raw)
To: kbuild, Tamizh chelvam
Cc: kbuild-all, johannes, ath10k, linux-wireless, Tamizh chelvam
In-Reply-To: <1551895251-22941-9-git-send-email-tamizhr@codeaurora.org>
Hi Tamizh,
url: https://github.com/0day-ci/linux/commits/Tamizh-chelvam/cfg80211-mac80211-Add-support-for-TID-specific-configuration/20190308-195433
base: https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git master
smatch warnings:
drivers/net/wireless/ath/ath10k/mac.c:8438 ath10k_mac_op_set_tid_config() error: uninitialized symbol 'ret'.
# https://github.com/0day-ci/linux/commit/2eab2d81c36efa0cf08b02bfe2df3f83a2e2d756
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout 2eab2d81c36efa0cf08b02bfe2df3f83a2e2d756
vim +/ret +8438 drivers/net/wireless/ath/ath10k/mac.c
6a7f8911 Anilkumar Kolli 2017-12-05 8306
2eab2d81 Tamizh chelvam 2019-03-06 8307 static int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw,
2eab2d81 Tamizh chelvam 2019-03-06 8308 struct ieee80211_vif *vif,
2eab2d81 Tamizh chelvam 2019-03-06 8309 struct ieee80211_sta *sta,
2eab2d81 Tamizh chelvam 2019-03-06 8310 struct ieee80211_tid_config *tid_config)
2eab2d81 Tamizh chelvam 2019-03-06 8311 {
2eab2d81 Tamizh chelvam 2019-03-06 8312 struct ath10k *ar = hw->priv;
2eab2d81 Tamizh chelvam 2019-03-06 8313 struct ath10k_vif *arvif = (void *)vif->drv_priv;
2eab2d81 Tamizh chelvam 2019-03-06 8314 struct ath10k_mac_iter_tid_conf_data data = {};
2eab2d81 Tamizh chelvam 2019-03-06 8315 struct wmi_per_peer_per_tid_cfg_arg arg = {};
2eab2d81 Tamizh chelvam 2019-03-06 8316 int ret, i;
2eab2d81 Tamizh chelvam 2019-03-06 8317 u8 changed;
2eab2d81 Tamizh chelvam 2019-03-06 8318
2eab2d81 Tamizh chelvam 2019-03-06 8319 mutex_lock(&ar->conf_mutex);
2eab2d81 Tamizh chelvam 2019-03-06 8320 arg.vdev_id = arvif->vdev_id;
2eab2d81 Tamizh chelvam 2019-03-06 8321
2eab2d81 Tamizh chelvam 2019-03-06 8322 memset(arvif->tid_conf_changed, 0, sizeof(arvif->tid_conf_changed));
2eab2d81 Tamizh chelvam 2019-03-06 8323
2eab2d81 Tamizh chelvam 2019-03-06 8324 for (i = 0; i < tid_config->n_tid_conf; i++) {
2eab2d81 Tamizh chelvam 2019-03-06 8325 if (tid_config->tid_conf[i].tid >= IEEE80211_TID_MAX)
2eab2d81 Tamizh chelvam 2019-03-06 8326 continue;
^^^^^^^^^
We would have to hit this continue over and over and "sta" would have
to be non-NULL for this to be an issue.
2eab2d81 Tamizh chelvam 2019-03-06 8327
2eab2d81 Tamizh chelvam 2019-03-06 8328 ath10k_mac_parse_tid_config(ar, sta, vif,
2eab2d81 Tamizh chelvam 2019-03-06 8329 &tid_config->tid_conf[i],
2eab2d81 Tamizh chelvam 2019-03-06 8330 &arg);
2eab2d81 Tamizh chelvam 2019-03-06 8331 changed = tid_config->tid_conf[i].tid_conf_mask;
2eab2d81 Tamizh chelvam 2019-03-06 8332 if (sta) {
2eab2d81 Tamizh chelvam 2019-03-06 8333 if (!sta->wme) {
2eab2d81 Tamizh chelvam 2019-03-06 8334 ret = -ENOTSUPP;
2eab2d81 Tamizh chelvam 2019-03-06 8335 goto exit;
2eab2d81 Tamizh chelvam 2019-03-06 8336 }
2eab2d81 Tamizh chelvam 2019-03-06 8337
2eab2d81 Tamizh chelvam 2019-03-06 8338 if (changed & IEEE80211_TID_CONF_RETRY) {
2eab2d81 Tamizh chelvam 2019-03-06 8339 if (sta->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK ||
2eab2d81 Tamizh chelvam 2019-03-06 8340 vif->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK)
2eab2d81 Tamizh chelvam 2019-03-06 8341 arg.retry_count = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8342 }
2eab2d81 Tamizh chelvam 2019-03-06 8343
2eab2d81 Tamizh chelvam 2019-03-06 8344 if (changed & IEEE80211_TID_CONF_AMPDU) {
2eab2d81 Tamizh chelvam 2019-03-06 8345 if (sta->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK ||
2eab2d81 Tamizh chelvam 2019-03-06 8346 vif->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK)
2eab2d81 Tamizh chelvam 2019-03-06 8347 arg.aggr_control = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8348 }
2eab2d81 Tamizh chelvam 2019-03-06 8349
2eab2d81 Tamizh chelvam 2019-03-06 8350 if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
2eab2d81 Tamizh chelvam 2019-03-06 8351 if (sta->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK ||
2eab2d81 Tamizh chelvam 2019-03-06 8352 vif->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK) {
2eab2d81 Tamizh chelvam 2019-03-06 8353 arg.rate_ctrl = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8354 arg.rcode_flags = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8355 }
2eab2d81 Tamizh chelvam 2019-03-06 8356 }
2eab2d81 Tamizh chelvam 2019-03-06 8357
2eab2d81 Tamizh chelvam 2019-03-06 8358 ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
2eab2d81 Tamizh chelvam 2019-03-06 8359 ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg);
2eab2d81 Tamizh chelvam 2019-03-06 8360 if (ret)
2eab2d81 Tamizh chelvam 2019-03-06 8361 goto exit;
2eab2d81 Tamizh chelvam 2019-03-06 8362
2eab2d81 Tamizh chelvam 2019-03-06 8363 /* Store the configured parameters in success case */
2eab2d81 Tamizh chelvam 2019-03-06 8364 if (changed & IEEE80211_TID_CONF_NOACK) {
2eab2d81 Tamizh chelvam 2019-03-06 8365 if (tid_config->tid_conf[i].noack ==
2eab2d81 Tamizh chelvam 2019-03-06 8366 NL80211_TID_CONFIG_DEFAULT) {
2eab2d81 Tamizh chelvam 2019-03-06 8367 sta->noack[arg.tid] = -1;
2eab2d81 Tamizh chelvam 2019-03-06 8368 } else {
2eab2d81 Tamizh chelvam 2019-03-06 8369 sta->noack[arg.tid] = arg.ack_policy;
2eab2d81 Tamizh chelvam 2019-03-06 8370 }
2eab2d81 Tamizh chelvam 2019-03-06 8371
2eab2d81 Tamizh chelvam 2019-03-06 8372 arg.ack_policy = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8373 arg.aggr_control = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8374 arg.rate_ctrl = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8375 arg.rcode_flags = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8376 }
2eab2d81 Tamizh chelvam 2019-03-06 8377
2eab2d81 Tamizh chelvam 2019-03-06 8378 if (changed & IEEE80211_TID_CONF_RETRY) {
2eab2d81 Tamizh chelvam 2019-03-06 8379 if (tid_config->tid_conf[i].retry_long == -1) {
2eab2d81 Tamizh chelvam 2019-03-06 8380 sta->retry_long[arg.tid] = -1;
2eab2d81 Tamizh chelvam 2019-03-06 8381 } else {
2eab2d81 Tamizh chelvam 2019-03-06 8382 sta->retry_long[arg.tid] = arg.retry_count;
2eab2d81 Tamizh chelvam 2019-03-06 8383 }
2eab2d81 Tamizh chelvam 2019-03-06 8384
2eab2d81 Tamizh chelvam 2019-03-06 8385 arg.retry_count = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8386 }
2eab2d81 Tamizh chelvam 2019-03-06 8387
2eab2d81 Tamizh chelvam 2019-03-06 8388 if (changed & IEEE80211_TID_CONF_AMPDU) {
2eab2d81 Tamizh chelvam 2019-03-06 8389 if (tid_config->tid_conf[i].ampdu ==
2eab2d81 Tamizh chelvam 2019-03-06 8390 NL80211_TID_CONFIG_DEFAULT) {
2eab2d81 Tamizh chelvam 2019-03-06 8391 sta->ampdu[arg.tid] = -1;
2eab2d81 Tamizh chelvam 2019-03-06 8392 } else {
2eab2d81 Tamizh chelvam 2019-03-06 8393 sta->ampdu[arg.tid] = arg.aggr_control;
2eab2d81 Tamizh chelvam 2019-03-06 8394 }
2eab2d81 Tamizh chelvam 2019-03-06 8395
2eab2d81 Tamizh chelvam 2019-03-06 8396 arg.aggr_control = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8397 }
2eab2d81 Tamizh chelvam 2019-03-06 8398
2eab2d81 Tamizh chelvam 2019-03-06 8399 if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
2eab2d81 Tamizh chelvam 2019-03-06 8400 sta->rate_ctrl[arg.tid] = arg.rate_ctrl;
2eab2d81 Tamizh chelvam 2019-03-06 8401 arg.rate_ctrl = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8402 arg.rcode_flags = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8403 }
2eab2d81 Tamizh chelvam 2019-03-06 8404 } else {
2eab2d81 Tamizh chelvam 2019-03-06 8405 arvif->tid_conf_changed[arg.tid] |= changed;
2eab2d81 Tamizh chelvam 2019-03-06 8406
2eab2d81 Tamizh chelvam 2019-03-06 8407 if (changed & IEEE80211_TID_CONF_NOACK) {
2eab2d81 Tamizh chelvam 2019-03-06 8408 vif->noack[arg.tid] = arg.ack_policy;
2eab2d81 Tamizh chelvam 2019-03-06 8409 vif->ampdu[arg.tid] = arg.aggr_control;
2eab2d81 Tamizh chelvam 2019-03-06 8410 vif->rate_ctrl[arg.tid] = arg.rate_ctrl;
2eab2d81 Tamizh chelvam 2019-03-06 8411 }
2eab2d81 Tamizh chelvam 2019-03-06 8412
2eab2d81 Tamizh chelvam 2019-03-06 8413 if (changed & IEEE80211_TID_CONF_RETRY)
2eab2d81 Tamizh chelvam 2019-03-06 8414 vif->retry_long[arg.tid] = arg.retry_count;
2eab2d81 Tamizh chelvam 2019-03-06 8415
2eab2d81 Tamizh chelvam 2019-03-06 8416 if (changed & IEEE80211_TID_CONF_AMPDU)
2eab2d81 Tamizh chelvam 2019-03-06 8417 vif->ampdu[arg.tid] = arg.aggr_control;
2eab2d81 Tamizh chelvam 2019-03-06 8418
2eab2d81 Tamizh chelvam 2019-03-06 8419 if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
2eab2d81 Tamizh chelvam 2019-03-06 8420 vif->rate_ctrl[arg.tid] = arg.rate_ctrl;
2eab2d81 Tamizh chelvam 2019-03-06 8421 vif->rate_code[arg.tid] = arg.rcode_flags;
2eab2d81 Tamizh chelvam 2019-03-06 8422 }
2eab2d81 Tamizh chelvam 2019-03-06 8423 }
2eab2d81 Tamizh chelvam 2019-03-06 8424 }
2eab2d81 Tamizh chelvam 2019-03-06 8425
2eab2d81 Tamizh chelvam 2019-03-06 8426 if (sta)
2eab2d81 Tamizh chelvam 2019-03-06 8427 goto exit;
2eab2d81 Tamizh chelvam 2019-03-06 8428
2eab2d81 Tamizh chelvam 2019-03-06 8429 ret = 0;
2eab2d81 Tamizh chelvam 2019-03-06 8430 data.curr_vif = vif;
2eab2d81 Tamizh chelvam 2019-03-06 8431 data.ar = ar;
2eab2d81 Tamizh chelvam 2019-03-06 8432
2eab2d81 Tamizh chelvam 2019-03-06 8433 ieee80211_iterate_stations_atomic(hw, ath10k_mac_vif_stations_tid_conf,
2eab2d81 Tamizh chelvam 2019-03-06 8434 &data);
2eab2d81 Tamizh chelvam 2019-03-06 8435
2eab2d81 Tamizh chelvam 2019-03-06 8436 exit:
2eab2d81 Tamizh chelvam 2019-03-06 8437 mutex_unlock(&ar->conf_mutex);
2eab2d81 Tamizh chelvam 2019-03-06 @8438 return ret;
2eab2d81 Tamizh chelvam 2019-03-06 8439 }
2eab2d81 Tamizh chelvam 2019-03-06 8440
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply
* [PATCHv4 9/9] ath10k: Add extended TID configuration support
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
This patch extend TID configuration support to configure
RTS_CTS control and TX rate limit. Tx rate limit is
similar to auto rate but it will be limited to the user
configured rate mask rather than the station's highest
supported rate mask. Here ext_tid_cfg_bitmap added
to notify the target which extended configuration
parameter has modified(here RTS_CTS).
WMI_10_4_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT service flag
introduced to advertise this support.
Testing:
* Tested HW: QCA9984
* Tested FW: 10.4-3.9.0.2-00021
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
drivers/net/wireless/ath/ath10k/core.c | 4 +++
drivers/net/wireless/ath/ath10k/mac.c | 48 ++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.c | 9 ++++--
drivers/net/wireless/ath/ath10k/wmi.h | 20 +++++++++++++
4 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index ac2cf3f..248709d 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2623,6 +2623,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map))
val |= WMI_10_4_REPORT_AIRTIME;
+ if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,
+ ar->wmi.svc_map))
+ val |= WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT;
+
status = ath10k_mac_ext_resource_config(ar, val);
if (status) {
ath10k_err(ar,
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index e5ae054..5d4611e 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2950,6 +2950,12 @@ static int ath10k_new_peer_tid_config(struct ath10k *ar,
arg.aggr_control = vif->ampdu[i];
arg.rate_ctrl = vif->rate_ctrl[i];
arg.rcode_flags = vif->rate_code[i];
+ if (vif->rtscts[i])
+ arg.ext_tid_cfg_bitmap =
+ WMI_EXT_TID_RTS_CTS_CONFIG;
+ else
+ arg.ext_tid_cfg_bitmap = 0;
+ arg.rtscts_ctrl = vif->rtscts[i];
}
if (vif->noack[i]) {
@@ -6560,6 +6566,10 @@ static int ath10k_mac_validate_rate_mask(struct ath10k *ar,
if (txrate_type == NL80211_TX_RATE_FIXED)
*rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE;
+ else if (txrate_type == NL80211_TX_RATE_LIMITED &&
+ (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,
+ ar->wmi.svc_map)))
+ *rate_ctrl = WMI_PEER_TID_CONFIG_RATE_UPPER_CAP;
else
return -EOPNOTSUPP;
return 0;
@@ -6626,6 +6636,14 @@ static int ath10k_mac_validate_rate_mask(struct ath10k *ar,
arg->rate_ctrl = 0;
}
}
+
+ if (changed & IEEE80211_TID_CONF_RTSCTS) {
+ if (tid_conf->rtscts)
+ arg->rtscts_ctrl = tid_conf->rtscts - 1;
+ else
+ arg->rtscts_ctrl = WMI_TID_CONFIG_RTSCTS_CONTROL_ENABLE;
+ arg->ext_tid_cfg_bitmap = WMI_EXT_TID_RTS_CTS_CONFIG;
+ }
}
static void ath10k_sta_tid_cfg_wk(struct work_struct *wk)
@@ -6706,6 +6724,18 @@ static void ath10k_sta_tid_cfg_wk(struct work_struct *wk)
}
}
+ if (changed & IEEE80211_TID_CONF_RTSCTS) {
+ if (sta->rtscts[i]) {
+ arg.rtscts_ctrl = 0;
+ arg.ext_tid_cfg_bitmap = 0;
+ } else {
+ arg.rtscts_ctrl = vif->rtscts[i] - 1;
+ arg.ext_tid_cfg_bitmap =
+ WMI_EXT_TID_RTS_CTS_CONFIG;
+ config_apply = true;
+ }
+ }
+
arg.tid = i;
if (config_apply) {
@@ -8401,6 +8431,13 @@ static int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw,
arg.rate_ctrl = 0;
arg.rcode_flags = 0;
}
+
+ if (changed & IEEE80211_TID_CONF_RTSCTS) {
+ sta->rtscts[arg.tid] =
+ tid_config->tid_conf[i].rtscts;
+ arg.rtscts_ctrl = 0;
+ arg.ext_tid_cfg_bitmap = 0;
+ }
} else {
arvif->tid_conf_changed[arg.tid] |= changed;
@@ -8420,6 +8457,10 @@ static int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw,
vif->rate_ctrl[arg.tid] = arg.rate_ctrl;
vif->rate_code[arg.tid] = arg.rcode_flags;
}
+
+ if (changed & IEEE80211_TID_CONF_RTSCTS)
+ vif->rtscts[arg.tid] =
+ tid_config->tid_conf[i].rtscts;
}
}
@@ -9166,6 +9207,13 @@ int ath10k_mac_register(struct ath10k *ar)
ar->ops->set_tid_config = NULL;
ar->hw->wiphy->flags &= ~WIPHY_FLAG_HAS_MAX_DATA_RETRY_COUNT;
}
+
+ if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map)) {
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL);
+ }
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 44b66f2..6ae3f8c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -8884,11 +8884,14 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
cmd->rate_control = cpu_to_le32(arg->rate_ctrl);
cmd->retry_count = cpu_to_le32(arg->retry_count);
cmd->rcode_flags = cpu_to_le32(arg->rcode_flags);
+ cmd->ext_tid_cfg_bitmap = cpu_to_le32(arg->ext_tid_cfg_bitmap);
+ cmd->rtscts_ctrl = cpu_to_le32(arg->rtscts_ctrl);
ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi noack tid %d vdev id %d ack_policy %d aggr %u rate_ctrl %u rcflag %u retry_count %d mac_addr %pM\n",
- arg->tid, arg->vdev_id, arg->ack_policy, arg->aggr_control, arg->rate_ctrl,
- arg->rcode_flags, arg->retry_count, arg->peer_macaddr.addr);
+ "wmi noack tid %d vdev id %d ack_policy %d aggr %u rate_ctrl %u rcflag %u retry_count %d rtscts %d ext_tid_cfg_bitmap %d mac_addr %pM\n",
+ arg->tid, arg->vdev_id, arg->ack_policy, arg->aggr_control,
+ arg->rate_ctrl, arg->rcode_flags, arg->retry_count, arg->rtscts_ctrl,
+ arg->ext_tid_cfg_bitmap, arg->peer_macaddr.addr);
return skb;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 187c13e..21a328f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -201,6 +201,7 @@ enum wmi_service {
WMI_SERVICE_PER_PACKET_SW_ENCRYPT,
WMI_SERVICE_REPORT_AIRTIME,
WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+ WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,
/* Remember to add the new value to wmi_service_name()! */
@@ -493,6 +494,7 @@ static inline char *wmi_service_name(enum wmi_service service_id)
SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT);
SVCSTR(WMI_SERVICE_REPORT_AIRTIME);
SVCSTR(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT);
+ SVCSTR(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT);
case WMI_SERVICE_MAX:
return NULL;
@@ -822,6 +824,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_REPORT_AIRTIME, len);
SVCMAP(WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, len);
+ SVCMAP(WMI_10_4_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,
+ WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, len);
}
#undef SVCMAP
@@ -7169,6 +7173,16 @@ enum wmi_tid_rate_ctrl_conf {
WMI_TID_CONFIG_RATE_CONTROL_AUTO,
WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE,
WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE,
+ WMI_PEER_TID_CONFIG_RATE_UPPER_CAP,
+};
+
+enum wmi_tid_rtscts_control_conf {
+ WMI_TID_CONFIG_RTSCTS_CONTROL_ENABLE,
+ WMI_TID_CONFIG_RTSCTS_CONTROL_DISABLE,
+};
+
+enum wmi_ext_tid_config_map {
+ WMI_EXT_TID_RTS_CTS_CONFIG = BIT(0),
};
struct wmi_per_peer_per_tid_cfg_arg {
@@ -7180,6 +7194,8 @@ struct wmi_per_peer_per_tid_cfg_arg {
u8 rate_ctrl;
u32 retry_count;
u32 rcode_flags;
+ u32 ext_tid_cfg_bitmap;
+ u32 rtscts_ctrl;
};
struct wmi_peer_per_tid_cfg_cmd {
@@ -7195,6 +7211,10 @@ struct wmi_peer_per_tid_cfg_cmd {
__le32 rate_control;
__le32 rcode_flags;
__le32 retry_count;
+ /* See enum wmi_ext_tid_config_map */
+ __le32 ext_tid_cfg_bitmap;
+ /* see enum wmi_tid_rtscts_control_conf */
+ __le32 rtscts_ctrl;
} __packed;
enum wmi_txbf_conf {
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 8/9] ath10k: Add new api to support TID specific configuration
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
This patch add ops for set_tid_config to support TID
specific configuration. STA information along with the
TID config change mask to notify driver that which configuration
needs to be applied for this current command.
If the STA info not available in the command then the
configuration will be applied for all connected stations
in the vif. TID specific noack configuration requires
aggregation disabled and rate for the data TID packets
should be basic rates. So, if the TID already configured
with noack policy then driver will ignore the aggregation
or TX rate related configuration for the same data TID.
In TX rate configuration should be applied with highest
preamble configuration(HT rates should not be applied
for the station which supports vht rates).
Vif specific TID configuration will be applied for all
the connected stations except for the station which
already applied with the same configuration for the TID
through station specific command. Newly connecting stations
will be applied with vif TID configuration which will be stored
in ieee80211_vif.
Testing:
* Tested HW: QCA9888
* Tested FW: 10.4-3.5.1-00052
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
drivers/net/wireless/ath/ath10k/core.h | 6 +
drivers/net/wireless/ath/ath10k/mac.c | 631 ++++++++++++++++++++++++++++----
2 files changed, 557 insertions(+), 80 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 27ec555..87234d2 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -82,6 +82,8 @@
/* Default Airtime weight multipler (Tuned for multiclient performance) */
#define ATH10K_AIRTIME_WEIGHT_MULTIPLIER 4
+#define ATH10K_MAX_RETRY_COUNT 30
+
struct ath10k;
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
@@ -504,6 +506,7 @@ struct ath10k_sta {
#endif
/* Protected with ar->data_lock */
u32 peer_ps_state;
+ struct work_struct tid_config_wk;
};
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
@@ -571,6 +574,9 @@ struct ath10k_vif {
struct work_struct ap_csa_work;
struct delayed_work connection_loss_work;
struct cfg80211_bitrate_mask bitrate_mask;
+ u32 tid_conf_changed[IEEE80211_TID_MAX];
+
+ struct ieee80211_tid_config *tid_config;
};
struct ath10k_vif_iter {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b73c23d..e5ae054 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2930,6 +2930,59 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
cancel_delayed_work_sync(&arvif->connection_loss_work);
}
+static int ath10k_new_peer_tid_config(struct ath10k *ar,
+ struct ieee80211_sta *sta,
+ struct ath10k_vif *arvif)
+{
+ struct wmi_per_peer_per_tid_cfg_arg arg = {};
+ struct ieee80211_vif *vif = arvif->vif;
+ bool config_apply;
+ int ret, i;
+
+ for (i = 0; i < IEEE80211_TID_MAX; i++) {
+ config_apply = false;
+ if (vif->retry_long[i] || vif->ampdu[i] ||
+ vif->rate_code[i]) {
+ config_apply = true;
+ arg.tid = i;
+ arg.vdev_id = arvif->vdev_id;
+ arg.retry_count = vif->retry_long[i];
+ arg.aggr_control = vif->ampdu[i];
+ arg.rate_ctrl = vif->rate_ctrl[i];
+ arg.rcode_flags = vif->rate_code[i];
+ }
+
+ if (vif->noack[i]) {
+ arg.ack_policy = vif->noack[i];
+ arg.rate_ctrl =
+ WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE;
+ arg.aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE;
+ config_apply = true;
+ }
+
+ /* Assign default value(-1) to newly connected station.
+ * This is to identify station specific tid configuration not
+ * configured for the station.
+ */
+ sta->retry_long[i] = -1;
+ sta->noack[i] = -1;
+ sta->ampdu[i] = -1;
+
+ if (!config_apply)
+ continue;
+
+ ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
+ ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to set per tid retry/aggr config for sta %pM: %d\n",
+ sta->addr, ret);
+ return ret;
+ }
+ memset(&arg, 0, sizeof(arg));
+ }
+ return 0;
+}
+
static int ath10k_station_assoc(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2995,7 +3048,10 @@ static int ath10k_station_assoc(struct ath10k *ar,
}
}
- return ret;
+ if (!test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map))
+ return ret;
+
+ return ath10k_new_peer_tid_config(ar, sta, arvif);
}
static int ath10k_station_disassoc(struct ath10k *ar,
@@ -6350,6 +6406,338 @@ static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif,
ar->num_stations--;
}
+struct ath10k_mac_iter_tid_conf_data {
+ struct ieee80211_vif *curr_vif;
+ struct ath10k *ar;
+};
+
+static bool
+ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
+ enum nl80211_band band,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ int num_rates = 0;
+ int i;
+
+ num_rates += hweight32(mask->control[band].legacy);
+
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
+ num_rates += hweight8(mask->control[band].ht_mcs[i]);
+
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
+ num_rates += hweight16(mask->control[band].vht_mcs[i]);
+
+ return num_rates == 1;
+}
+
+static int
+ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
+ enum nl80211_band band,
+ const struct cfg80211_bitrate_mask *mask,
+ u8 *rate, u8 *nss)
+{
+ int rate_idx;
+ int i;
+ u16 bitrate;
+ u8 preamble;
+ u8 hw_rate;
+
+ if (hweight32(mask->control[band].legacy) == 1) {
+ rate_idx = ffs(mask->control[band].legacy) - 1;
+
+ if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
+ rate_idx += ATH10K_MAC_FIRST_OFDM_RATE_IDX;
+
+ hw_rate = ath10k_wmi_legacy_rates[rate_idx].hw_value;
+ bitrate = ath10k_wmi_legacy_rates[rate_idx].bitrate;
+
+ if (ath10k_mac_bitrate_is_cck(bitrate))
+ preamble = WMI_RATE_PREAMBLE_CCK;
+ else
+ preamble = WMI_RATE_PREAMBLE_OFDM;
+
+ *nss = 1;
+ *rate = preamble << 6 |
+ (*nss - 1) << 4 |
+ hw_rate << 0;
+
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
+ if (hweight8(mask->control[band].ht_mcs[i]) == 1) {
+ *nss = i + 1;
+ *rate = WMI_RATE_PREAMBLE_HT << 6 |
+ (*nss - 1) << 4 |
+ (ffs(mask->control[band].ht_mcs[i]) - 1);
+
+ return 0;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+ if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
+ *nss = i + 1;
+ *rate = WMI_RATE_PREAMBLE_VHT << 6 |
+ (*nss - 1) << 4 |
+ (ffs(mask->control[band].vht_mcs[i]) - 1);
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int ath10k_mac_validate_rate_mask(struct ath10k *ar,
+ struct ieee80211_sta *sta,
+ u32 rate_ctrl_flag, u8 nss)
+{
+ if (nss > sta->rx_nss) {
+ ath10k_warn(ar, "Invalid nss field, configured %u limit %u\n",
+ nss, sta->rx_nss);
+ return -EINVAL;
+ }
+
+ if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_VHT) {
+ if (!sta->vht_cap.vht_supported) {
+ ath10k_warn(ar, "Invalid VHT rate for sta %pM\n",
+ sta->addr);
+ return -EINVAL;
+ }
+ } else if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_HT) {
+ if (!sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) {
+ ath10k_warn(ar, "Invalid HT rate for sta %pM\n",
+ sta->addr);
+ return -EINVAL;
+ }
+ } else {
+ if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+ath10k_mac_tid_bitrate_config(struct ath10k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ u32 *rate_ctrl_flag, u8 *rate_ctrl,
+ enum nl80211_tx_rate_setting txrate_type,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct cfg80211_chan_def def;
+ enum nl80211_band band;
+ u8 nss, rate;
+ int ret;
+
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return -EINVAL;
+
+ if (txrate_type == NL80211_TX_RATE_AUTOMATIC) {
+ *rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO;
+ *rate_ctrl_flag = 0;
+ return 0;
+ }
+
+ band = def.chan->band;
+
+ if (!ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask))
+ return -EINVAL;
+
+ ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
+ &rate, &nss);
+ if (ret) {
+ ath10k_warn(ar, "failed to get single rate: %d\n",
+ ret);
+ return ret;
+ }
+ *rate_ctrl_flag = rate;
+
+ if (sta && ath10k_mac_validate_rate_mask(ar, sta, *rate_ctrl_flag, nss))
+ return -EINVAL;
+
+ if (txrate_type == NL80211_TX_RATE_FIXED)
+ *rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE;
+ else
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static void
+ath10k_mac_parse_tid_config(struct ath10k *ar,
+ struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif,
+ struct ieee80211_tid_cfg *tid_conf,
+ struct wmi_per_peer_per_tid_cfg_arg *arg)
+{
+ u8 changed = tid_conf->tid_conf_mask;
+ int ret;
+
+ arg->tid = tid_conf->tid;
+
+ if (changed & IEEE80211_TID_CONF_NOACK) {
+ if (tid_conf->noack == NL80211_TID_CONFIG_ENABLE) {
+ arg->ack_policy = WMI_PEER_TID_CONFIG_NOACK;
+ arg->rate_ctrl =
+ WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE;
+ arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE;
+ } else {
+ arg->ack_policy = WMI_PEER_TID_CONFIG_ACK;
+ arg->rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO;
+ arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_ENABLE;
+ }
+ }
+
+ if (changed & IEEE80211_TID_CONF_RETRY) {
+ if (tid_conf->retry_long == -1) {
+ if (vif->retry_long[arg->tid])
+ arg->retry_count = vif->retry_long[arg->tid];
+ else
+ arg->retry_count = ATH10K_MAX_RETRY_COUNT;
+ } else {
+ arg->retry_count = tid_conf->retry_long;
+ }
+ }
+
+ if (changed & IEEE80211_TID_CONF_AMPDU) {
+ if (tid_conf->ampdu) {
+ arg->aggr_control = tid_conf->ampdu;
+ } else {
+ if (vif->ampdu[arg->tid])
+ arg->aggr_control = vif->ampdu[arg->tid];
+ else
+ arg->aggr_control =
+ WMI_TID_CONFIG_AGGR_CONTROL_DISABLE;
+ }
+ }
+
+ if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
+ ret = ath10k_mac_tid_bitrate_config(ar, vif, sta,
+ &arg->rcode_flags,
+ &arg->rate_ctrl,
+ tid_conf->txrate_type,
+ tid_conf->mask);
+ if (ret) {
+ ath10k_warn(ar, "failed to configure bitrate mask %d\n",
+ ret);
+ arg->rcode_flags = 0;
+ arg->rate_ctrl = 0;
+ }
+ }
+}
+
+static void ath10k_sta_tid_cfg_wk(struct work_struct *wk)
+{
+ struct wmi_per_peer_per_tid_cfg_arg arg = {};
+ struct ieee80211_vif *vif;
+ struct ieee80211_sta *sta;
+ struct ath10k_sta *arsta;
+ struct ath10k_vif *arvif;
+ struct ath10k *ar;
+ bool config_apply;
+ int ret, i;
+ u8 changed;
+
+ arsta = container_of(wk, struct ath10k_sta, tid_config_wk);
+ sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+ arvif = arsta->arvif;
+ vif = arvif->vif;
+ ar = arvif->ar;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
+ for (i = 0; i < IEEE80211_TID_MAX; i++) {
+ config_apply = false;
+ changed = arvif->tid_conf_changed[i];
+
+ if (changed & IEEE80211_TID_CONF_NOACK) {
+ if (sta->noack[i] != -1) {
+ arg.ack_policy = 0;
+ } else {
+ config_apply = true;
+ arg.ack_policy = vif->noack[i];
+ arg.aggr_control = vif->ampdu[i];
+ arg.rate_ctrl = vif->rate_ctrl[i];
+ }
+ }
+
+ if (changed & IEEE80211_TID_CONF_RETRY) {
+ if (sta->retry_long[i] != -1 ||
+ sta->noack[i] == WMI_PEER_TID_CONFIG_NOACK ||
+ vif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) {
+ arg.retry_count = 0;
+ } else {
+ arg.retry_count = vif->retry_long[i];
+ config_apply = true;
+ }
+ }
+
+ if (changed & IEEE80211_TID_CONF_AMPDU) {
+ if (sta->ampdu[i] != -1 ||
+ sta->noack[i] == WMI_PEER_TID_CONFIG_NOACK ||
+ vif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) {
+ arg.aggr_control = 0;
+ } else {
+ arg.aggr_control = vif->ampdu[i];
+ config_apply = true;
+ }
+ }
+
+ if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
+ if (ath10k_mac_validate_rate_mask(ar, sta, vif->rate_code[i],
+ ATH10K_HW_NSS(vif->rate_code[i]))) {
+ arg.rate_ctrl = 0;
+ arg.rcode_flags = 0;
+ }
+
+ if (sta->rate_ctrl[i] >
+ WMI_TID_CONFIG_RATE_CONTROL_AUTO ||
+ sta->noack[i] == WMI_PEER_TID_CONFIG_NOACK ||
+ vif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) {
+ arg.rate_ctrl = 0;
+ arg.rcode_flags = 0;
+ } else {
+ arg.rate_ctrl = vif->rate_ctrl[i];
+ arg.rcode_flags = vif->rate_code[i];
+ config_apply = true;
+ }
+ }
+
+ arg.tid = i;
+
+ if (config_apply) {
+ ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg);
+ if (ret)
+ ath10k_warn(ar, "failed to set per tid config for sta %pM: %d\n",
+ sta->addr, ret);
+ }
+
+ arg.ack_policy = 0;
+ arg.retry_count = 0;
+ arg.aggr_control = 0;
+ arg.rate_ctrl = 0;
+ arg.rcode_flags = 0;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static void ath10k_mac_vif_stations_tid_conf(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k_mac_iter_tid_conf_data *iter_data = data;
+ struct ieee80211_vif *sta_vif = arsta->arvif->vif;
+
+ if (sta_vif != iter_data->curr_vif || !sta->wme)
+ return;
+
+ ieee80211_queue_work(iter_data->ar->hw, &arsta->tid_config_wk);
+}
+
static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -6369,6 +6757,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
arsta->arvif = arvif;
arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
+ INIT_WORK(&arsta->tid_config_wk, ath10k_sta_tid_cfg_wk);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
ath10k_mac_txq_init(sta->txq[i]);
@@ -6376,8 +6765,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/* cancel must be done outside the mutex to avoid deadlock */
if ((old_state == IEEE80211_STA_NONE &&
- new_state == IEEE80211_STA_NOTEXIST))
+ new_state == IEEE80211_STA_NOTEXIST)) {
cancel_work_sync(&arsta->update_wk);
+ cancel_work_sync(&arsta->tid_config_wk);
+ }
mutex_lock(&ar->conf_mutex);
@@ -7097,25 +7488,6 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
}
static bool
-ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
- enum nl80211_band band,
- const struct cfg80211_bitrate_mask *mask)
-{
- int num_rates = 0;
- int i;
-
- num_rates += hweight32(mask->control[band].legacy);
-
- for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
- num_rates += hweight8(mask->control[band].ht_mcs[i]);
-
- for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
- num_rates += hweight16(mask->control[band].vht_mcs[i]);
-
- return num_rates == 1;
-}
-
-static bool
ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar,
enum nl80211_band band,
const struct cfg80211_bitrate_mask *mask,
@@ -7164,65 +7536,6 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
return true;
}
-static int
-ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
- enum nl80211_band band,
- const struct cfg80211_bitrate_mask *mask,
- u8 *rate, u8 *nss)
-{
- int rate_idx;
- int i;
- u16 bitrate;
- u8 preamble;
- u8 hw_rate;
-
- if (hweight32(mask->control[band].legacy) == 1) {
- rate_idx = ffs(mask->control[band].legacy) - 1;
-
- if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
- rate_idx += ATH10K_MAC_FIRST_OFDM_RATE_IDX;
-
- hw_rate = ath10k_wmi_legacy_rates[rate_idx].hw_value;
- bitrate = ath10k_wmi_legacy_rates[rate_idx].bitrate;
-
- if (ath10k_mac_bitrate_is_cck(bitrate))
- preamble = WMI_RATE_PREAMBLE_CCK;
- else
- preamble = WMI_RATE_PREAMBLE_OFDM;
-
- *nss = 1;
- *rate = preamble << 6 |
- (*nss - 1) << 4 |
- hw_rate << 0;
-
- return 0;
- }
-
- for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
- if (hweight8(mask->control[band].ht_mcs[i]) == 1) {
- *nss = i + 1;
- *rate = WMI_RATE_PREAMBLE_HT << 6 |
- (*nss - 1) << 4 |
- (ffs(mask->control[band].ht_mcs[i]) - 1);
-
- return 0;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
- if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
- *nss = i + 1;
- *rate = WMI_RATE_PREAMBLE_VHT << 6 |
- (*nss - 1) << 4 |
- (ffs(mask->control[band].vht_mcs[i]) - 1);
-
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
u8 rate, u8 nss, u8 sgi, u8 ldpc)
{
@@ -7991,6 +8304,140 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
+static int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_tid_config *tid_config)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ struct ath10k_mac_iter_tid_conf_data data = {};
+ struct wmi_per_peer_per_tid_cfg_arg arg = {};
+ int ret, i;
+ u8 changed;
+
+ mutex_lock(&ar->conf_mutex);
+ arg.vdev_id = arvif->vdev_id;
+
+ memset(arvif->tid_conf_changed, 0, sizeof(arvif->tid_conf_changed));
+
+ for (i = 0; i < tid_config->n_tid_conf; i++) {
+ if (tid_config->tid_conf[i].tid >= IEEE80211_TID_MAX)
+ continue;
+
+ ath10k_mac_parse_tid_config(ar, sta, vif,
+ &tid_config->tid_conf[i],
+ &arg);
+ changed = tid_config->tid_conf[i].tid_conf_mask;
+ if (sta) {
+ if (!sta->wme) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ if (changed & IEEE80211_TID_CONF_RETRY) {
+ if (sta->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK ||
+ vif->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK)
+ arg.retry_count = 0;
+ }
+
+ if (changed & IEEE80211_TID_CONF_AMPDU) {
+ if (sta->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK ||
+ vif->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK)
+ arg.aggr_control = 0;
+ }
+
+ if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
+ if (sta->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK ||
+ vif->noack[arg.tid] == WMI_PEER_TID_CONFIG_NOACK) {
+ arg.rate_ctrl = 0;
+ arg.rcode_flags = 0;
+ }
+ }
+
+ ether_addr_copy(arg.peer_macaddr.addr, sta->addr);
+ ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg);
+ if (ret)
+ goto exit;
+
+ /* Store the configured parameters in success case */
+ if (changed & IEEE80211_TID_CONF_NOACK) {
+ if (tid_config->tid_conf[i].noack ==
+ NL80211_TID_CONFIG_DEFAULT) {
+ sta->noack[arg.tid] = -1;
+ } else {
+ sta->noack[arg.tid] = arg.ack_policy;
+ }
+
+ arg.ack_policy = 0;
+ arg.aggr_control = 0;
+ arg.rate_ctrl = 0;
+ arg.rcode_flags = 0;
+ }
+
+ if (changed & IEEE80211_TID_CONF_RETRY) {
+ if (tid_config->tid_conf[i].retry_long == -1) {
+ sta->retry_long[arg.tid] = -1;
+ } else {
+ sta->retry_long[arg.tid] = arg.retry_count;
+ }
+
+ arg.retry_count = 0;
+ }
+
+ if (changed & IEEE80211_TID_CONF_AMPDU) {
+ if (tid_config->tid_conf[i].ampdu ==
+ NL80211_TID_CONFIG_DEFAULT) {
+ sta->ampdu[arg.tid] = -1;
+ } else {
+ sta->ampdu[arg.tid] = arg.aggr_control;
+ }
+
+ arg.aggr_control = 0;
+ }
+
+ if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
+ sta->rate_ctrl[arg.tid] = arg.rate_ctrl;
+ arg.rate_ctrl = 0;
+ arg.rcode_flags = 0;
+ }
+ } else {
+ arvif->tid_conf_changed[arg.tid] |= changed;
+
+ if (changed & IEEE80211_TID_CONF_NOACK) {
+ vif->noack[arg.tid] = arg.ack_policy;
+ vif->ampdu[arg.tid] = arg.aggr_control;
+ vif->rate_ctrl[arg.tid] = arg.rate_ctrl;
+ }
+
+ if (changed & IEEE80211_TID_CONF_RETRY)
+ vif->retry_long[arg.tid] = arg.retry_count;
+
+ if (changed & IEEE80211_TID_CONF_AMPDU)
+ vif->ampdu[arg.tid] = arg.aggr_control;
+
+ if (changed & IEEE80211_TID_CONF_TX_BITRATE) {
+ vif->rate_ctrl[arg.tid] = arg.rate_ctrl;
+ vif->rate_code[arg.tid] = arg.rcode_flags;
+ }
+ }
+ }
+
+ if (sta)
+ goto exit;
+
+ ret = 0;
+ data.curr_vif = vif;
+ data.ar = ar;
+
+ ieee80211_iterate_stations_atomic(hw, ath10k_mac_vif_stations_tid_conf,
+ &data);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_mac_op_tx,
.wake_tx_queue = ath10k_mac_op_wake_tx_queue,
@@ -8033,6 +8480,7 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
.switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
.sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove,
.sta_statistics = ath10k_sta_statistics,
+ .set_tid_config = ath10k_mac_op_set_tid_config,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
@@ -8695,6 +9143,29 @@ int ath10k_mac_register(struct ath10k *ar)
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
+ if (test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map)) {
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK);
+ ar->hw->wiphy->max_data_retry_count = ATH10K_MAX_RETRY_COUNT;
+ ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_MAX_DATA_RETRY_COUNT;
+ } else {
+ ar->ops->set_tid_config = NULL;
+ ar->hw->wiphy->flags &= ~WIPHY_FLAG_HAS_MAX_DATA_RETRY_COUNT;
+ }
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 6/9] mac80211: Add api to support configuring TID specific configuration
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
Implement drv_set_tid_config api to allow TID specific
configuration. This per-TID configuration
will be applied for all the connected stations when MAC is NULL.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/mac80211.h | 38 ++++++++++++++++++++++++++++++++++++++
net/mac80211/cfg.c | 28 ++++++++++++++++++++++++++++
net/mac80211/driver-ops.h | 15 +++++++++++++++
3 files changed, 81 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ac2ed8e..ead7605 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1556,6 +1556,8 @@ enum ieee80211_vif_flags {
IEEE80211_VIF_GET_NOA_UPDATE = BIT(3),
};
+#define IEEE80211_TID_MAX 8
+
/**
* struct ieee80211_vif - per-interface data
*
@@ -1593,6 +1595,13 @@ enum ieee80211_vif_flags {
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
* @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
* protected by fq->lock.
+ * @noack: per-TID noack policy.
+ * @retry_short: per-TID retry count.
+ * @retry_long: per-TID count.
+ * @ampdu: per-TID Aggregation-MPDU.
+ * @rate_ctrl: per-TID tx rate control type.
+ * @rate_code: per-TID tx rate code mask.
+ * @rtscts: per-TID RTSCTS policy.
*/
struct ieee80211_vif {
enum nl80211_iftype type;
@@ -1619,6 +1628,14 @@ struct ieee80211_vif {
bool txqs_stopped[IEEE80211_NUM_ACS];
+ int noack[IEEE80211_TID_MAX];
+ int retry_short[IEEE80211_TID_MAX];
+ int retry_long[IEEE80211_TID_MAX];
+ int ampdu[IEEE80211_TID_MAX];
+ u8 rate_ctrl[IEEE80211_TID_MAX];
+ u32 rate_code[IEEE80211_TID_MAX];
+ u8 rtscts[IEEE80211_TID_MAX];
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
@@ -1933,6 +1950,12 @@ struct ieee80211_sta_rates {
* @max_tid_amsdu_len: Maximum A-MSDU size in bytes for this TID
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that
* the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames
+ * @noack: per-TID noack policy.
+ * @retry_short: per-TID retry count.
+ * @retry_long: per-TID count.
+ * @ampdu: per-TID Aggregation-MPDU.
+ * @rate_ctrl: per-TID tx rate control type.
+ * @rtscts: per-TID RTSCTS policy.
*/
struct ieee80211_sta {
u32 supp_rates[NUM_NL80211_BANDS];
@@ -1976,6 +1999,13 @@ struct ieee80211_sta {
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
+ int noack[IEEE80211_TID_MAX];
+ int retry_short[IEEE80211_TID_MAX];
+ int retry_long[IEEE80211_TID_MAX];
+ int ampdu[IEEE80211_TID_MAX];
+ u8 rate_ctrl[IEEE80211_TID_MAX];
+ u8 rtscts[IEEE80211_TID_MAX];
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
@@ -3707,6 +3737,10 @@ enum ieee80211_reconfig_type {
*
* @start_pmsr: start peer measurement (e.g. FTM) (this call can sleep)
* @abort_pmsr: abort peer measurement (this call can sleep)
+ * @set_tid_config: TID specific configurations will be applied for a particular
+ * station when @sta is non-NULL. When @sta is NULL, then the configuration
+ * will be for all the connected clients in the vif.
+ * This callback may sleep.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -4004,6 +4038,10 @@ struct ieee80211_ops {
struct cfg80211_pmsr_request *request);
void (*abort_pmsr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_pmsr_request *request);
+ int (*set_tid_config)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_tid_config *tid_conf);
};
/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 09dd1c2..7d9c44d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3893,6 +3893,33 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
return drv_abort_pmsr(local, sdata, request);
}
+static int ieee80211_set_tid_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_tid_config *tid_conf)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta;
+ int ret;
+
+ if (!sdata->local->ops->set_tid_config)
+ return -EOPNOTSUPP;
+
+ if (!tid_conf->peer)
+ return drv_set_tid_config(sdata->local, sdata, NULL, tid_conf);
+
+ mutex_lock(&sdata->local->sta_mtx);
+
+ sta = sta_info_get_bss(sdata, tid_conf->peer);
+ if (!sta) {
+ mutex_unlock(&sdata->local->sta_mtx);
+ return -ENOENT;
+ }
+
+ ret = drv_set_tid_config(sdata->local, sdata, &sta->sta, tid_conf);
+ mutex_unlock(&sdata->local->sta_mtx);
+ return ret;
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -3990,4 +4017,5 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
.start_pmsr = ieee80211_start_pmsr,
.abort_pmsr = ieee80211_abort_pmsr,
+ .set_tid_config = ieee80211_set_tid_config,
};
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 28d022a..d316b18 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1348,4 +1348,19 @@ static inline void drv_del_nan_func(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline int drv_set_tid_config(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct ieee80211_tid_config *tid_conf)
+{
+ int ret;
+
+ might_sleep();
+ ret = local->ops->set_tid_config(&local->hw, &sdata->vif, sta,
+ tid_conf);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 7/9] ath10k: Add wmi command support for station specific TID config
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
This patch adds WMI interface to configure station specific
TID configuration . Host needs to send station's MAC address
along with TID number and its configuration to target through
WMI_10_4_PER_PEER_PER_TID_CONFIG_CMDID.
WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT flag is added to advertise
this support.
Testing:
* Tested HW: QCA9888
* Tested FW: 10.4-3.5.1-00052
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
drivers/net/wireless/ath/ath10k/wmi-ops.h | 19 +++++++++++
drivers/net/wireless/ath/ath10k/wmi.c | 32 ++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.h | 52 +++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 1491c25..796badf 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -216,6 +216,8 @@ struct wmi_ops {
struct sk_buff *(*gen_bb_timing)
(struct ath10k *ar,
const struct wmi_bb_timing_cfg_arg *arg);
+ struct sk_buff *(*gen_per_peer_per_tid_cfg)(struct ath10k *ar,
+ const struct wmi_per_peer_per_tid_cfg_arg *arg);
};
@@ -1616,4 +1618,21 @@ struct wmi_ops {
return ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->set_bb_timing_cmdid);
}
+
+static inline int
+ath10k_wmi_set_per_peer_per_tid_cfg(struct ath10k *ar,
+ const struct wmi_per_peer_per_tid_cfg_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_per_peer_per_tid_cfg)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_per_peer_per_tid_cfg(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->per_peer_per_tid_config_cmdid);
+}
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 97e5b2e..44b66f2 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -740,6 +740,7 @@
.tdls_peer_update_cmdid = WMI_10_4_TDLS_PEER_UPDATE_CMDID,
.tdls_set_offchan_mode_cmdid = WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID,
.radar_found_cmdid = WMI_10_4_RADAR_FOUND_CMDID,
+ .per_peer_per_tid_config_cmdid = WMI_10_4_PER_PEER_PER_TID_CONFIG_CMDID,
};
/* MAIN WMI VDEV param map */
@@ -8862,6 +8863,36 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
}
static struct sk_buff *
+ath10k_wmi_10_4_gen_per_peer_per_tid_cfg(struct ath10k *ar,
+ const struct wmi_per_peer_per_tid_cfg_arg *arg)
+{
+ struct wmi_peer_per_tid_cfg_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ memset(skb->data, 0, sizeof(*cmd));
+
+ cmd = (struct wmi_peer_per_tid_cfg_cmd *)skb->data;
+ cmd->vdev_id = cpu_to_le32(arg->vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, arg->peer_macaddr.addr);
+ cmd->tid = cpu_to_le32(arg->tid);
+ cmd->ack_policy = cpu_to_le32(arg->ack_policy);
+ cmd->aggr_control = cpu_to_le32(arg->aggr_control);
+ cmd->rate_control = cpu_to_le32(arg->rate_ctrl);
+ cmd->retry_count = cpu_to_le32(arg->retry_count);
+ cmd->rcode_flags = cpu_to_le32(arg->rcode_flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi noack tid %d vdev id %d ack_policy %d aggr %u rate_ctrl %u rcflag %u retry_count %d mac_addr %pM\n",
+ arg->tid, arg->vdev_id, arg->ack_policy, arg->aggr_control, arg->rate_ctrl,
+ arg->rcode_flags, arg->retry_count, arg->peer_macaddr.addr);
+ return skb;
+}
+
+static struct sk_buff *
ath10k_wmi_op_gen_echo(struct ath10k *ar, u32 value)
{
struct wmi_echo_cmd *cmd;
@@ -9270,6 +9301,7 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
.gen_pdev_get_tpc_table_cmdid =
ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid,
.gen_radar_found = ath10k_wmi_10_4_gen_radar_found,
+ .gen_per_peer_per_tid_cfg = ath10k_wmi_10_4_gen_per_peer_per_tid_cfg,
/* shared with 10.2 */
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index d9b646f..187c13e 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -200,6 +200,7 @@ enum wmi_service {
WMI_SERVICE_RTT_RESPONDER_ROLE,
WMI_SERVICE_PER_PACKET_SW_ENCRYPT,
WMI_SERVICE_REPORT_AIRTIME,
+ WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT,
/* Remember to add the new value to wmi_service_name()! */
@@ -491,6 +492,7 @@ static inline char *wmi_service_name(enum wmi_service service_id)
SVCSTR(WMI_SERVICE_RTT_RESPONDER_ROLE);
SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT);
SVCSTR(WMI_SERVICE_REPORT_AIRTIME);
+ SVCSTR(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT);
case WMI_SERVICE_MAX:
return NULL;
@@ -818,6 +820,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_PER_PACKET_SW_ENCRYPT, len);
SVCMAP(WMI_10_4_SERVICE_REPORT_AIRTIME,
WMI_SERVICE_REPORT_AIRTIME, len);
+ SVCMAP(WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+ WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, len);
}
#undef SVCMAP
@@ -1019,6 +1023,7 @@ struct wmi_cmd_map {
u32 tdls_set_offchan_mode_cmdid;
u32 radar_found_cmdid;
u32 set_bb_timing_cmdid;
+ u32 per_peer_per_tid_config_cmdid;
};
/*
@@ -1860,6 +1865,8 @@ enum wmi_10_4_cmd_id {
WMI_10_4_PDEV_SET_BRIDGE_MACADDR_CMDID,
WMI_10_4_ATF_GROUP_WMM_AC_CONFIG_REQUEST_CMDID,
WMI_10_4_RADAR_FOUND_CMDID,
+ WMI_10_4_PEER_CFR_CAPTURE_CMDID,
+ WMI_10_4_PER_PEER_PER_TID_CONFIG_CMDID,
WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1,
};
@@ -7145,6 +7152,51 @@ struct wmi_tdls_peer_event {
__le32 vdev_id;
} __packed;
+enum wmi_tid_aggr_control_conf {
+ WMI_TID_CONFIG_AGGR_CONTROL_IGNORE,
+ WMI_TID_CONFIG_AGGR_CONTROL_ENABLE,
+ WMI_TID_CONFIG_AGGR_CONTROL_DISABLE,
+};
+
+enum wmi_noack_tid_conf {
+ WMI_NOACK_TID_CONFIG_IGNORE_ACK_POLICY,
+ WMI_PEER_TID_CONFIG_ACK,
+ WMI_PEER_TID_CONFIG_NOACK,
+};
+
+enum wmi_tid_rate_ctrl_conf {
+ WMI_TID_CONFIG_RATE_CONTROL_IGNORE,
+ WMI_TID_CONFIG_RATE_CONTROL_AUTO,
+ WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE,
+ WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE,
+};
+
+struct wmi_per_peer_per_tid_cfg_arg {
+ u32 vdev_id;
+ struct wmi_mac_addr peer_macaddr;
+ u32 tid;
+ enum wmi_noack_tid_conf ack_policy;
+ enum wmi_tid_aggr_control_conf aggr_control;
+ u8 rate_ctrl;
+ u32 retry_count;
+ u32 rcode_flags;
+};
+
+struct wmi_peer_per_tid_cfg_cmd {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_macaddr;
+ __le32 tid;
+
+ /* see enum wmi_noack_tid_conf */
+ __le32 ack_policy;
+ /* see enum wmi_tid_aggr_control_conf */
+ __le32 aggr_control;
+ /* see enum wmi_tid_rate_ctrl_conf */
+ __le32 rate_control;
+ __le32 rcode_flags;
+ __le32 retry_count;
+} __packed;
+
enum wmi_txbf_conf {
WMI_TXBF_CONF_UNSUPPORTED,
WMI_TXBF_CONF_BEFORE_ASSOC,
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 5/9] nl80211: Add netlink attribute to configure TID specific tx rate
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
Introduce NL80211_ATTR_TID_CONFIG_TX_RATES in nl80211_attr_tid_config
to accept data TID specific TX bitrate configuration
through NL80211_CMD_SET_TID_CONFIG command. TID for which the
this configuration is to be applied is passed in
NL80211_ATTR_TID_CONFIG_TID attribute. TX bitrate mask values passed
in NL80211_ATTR_TX_RATES attribute and NL80211_ATTR_TID_CONFIG_TX_RATES
attribute will have types of the TX rate should be applied.
When the user-space wants this configuration peer specific
rather than being applied for all the connected stations,
MAC address of the peer can be passed in NL80211_ATTR_MAC attribute.
Driver supporting this feature should advertise
NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK and supporting per-STA data TID
TX bitrate configuration should advertise
NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/cfg80211.h | 5 +++
include/uapi/linux/nl80211.h | 39 ++++++++++++++++++
net/wireless/nl80211.c | 89 ++++++++++++++++++++++++++++++++----------
3 files changed, 113 insertions(+), 20 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 86dee3d..ebf041b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -514,6 +514,7 @@ enum ieee80211_tid_conf_mask {
IEEE80211_TID_CONF_RETRY = BIT(1),
IEEE80211_TID_CONF_AMPDU = BIT(2),
IEEE80211_TID_CONF_RTSCTS = BIT(3),
+ IEEE80211_TID_CONF_TX_BITRATE = BIT(4),
};
/**
@@ -526,6 +527,8 @@ enum ieee80211_tid_conf_mask {
* @retry_short: retry count value
* @ampdu: Enable/Disable aggregation
* @rtscts: Enable/Disable RTS/CTS
+ * @txrate_type: TX bitrate mask type
+ * @mask: bitrate to be applied for the TID
*/
struct ieee80211_tid_cfg {
u8 tid;
@@ -535,6 +538,8 @@ struct ieee80211_tid_cfg {
int retry_short;
u8 ampdu;
u8 rtscts;
+ enum nl80211_tx_rate_setting txrate_type;
+ struct cfg80211_bitrate_mask *mask;
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 996b4d4..c8aa3ba 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4557,6 +4557,18 @@ enum nl80211_tx_power_setting {
NL80211_TX_POWER_FIXED,
};
+/**
+ * enum nl80211_tx_rate_setting - TX rate configuration type
+ * @NL80211_TX_RATE_AUTOMATIC: automatically determine TX rate
+ * @NL80211_TX_RATE_LIMITED: limit the TX rate by the TX rate parameter
+ * @NL80211_TX_RATE_FIXED: fix TX rate to the TX rate parameter
+ */
+enum nl80211_tx_rate_setting {
+ NL80211_TX_RATE_AUTOMATIC,
+ NL80211_TX_RATE_LIMITED,
+ NL80211_TX_RATE_FIXED,
+};
+
enum nl80211_tid_config {
NL80211_TID_CONFIG_DEFAULT,
NL80211_TID_CONFIG_ENABLE,
@@ -4645,6 +4657,25 @@ enum nl80211_tid_config {
* NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL and supporting per station
* RTS_CTS configuration should advertise
* NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL.
+ * @NL80211_ATTR_TID_CONFIG_TX_RATES: Data frame TX rate mask should be applied
+ * with the parameters passed through %NL80211_ATTR_TX_RATES. This
+ * configuration is per TID, TID is specified with
+ * %NL80211_ATTR_TID_CONFIG_TID.
+ * If the peer MAC address is passed in %NL80211_ATTR_MAC, then this
+ * configuration is applied to the data frame for the tid to that connected
+ * station. This attribute will be useful to notfiy the driver that what
+ * type of txrate should be applied(%enum enum nl80211_tx_rate_setting)
+ * for the connected station (%NL80211_ATTR_MAC),
+ * Station specific retry configuration is valid only for STA's
+ * current connection. i.e. the configuration will be reset to default when
+ * the station connects back after disconnection/roaming.
+ * when user-space does not include %NL80211_ATTR_MAC, this configuration
+ * should be treated as per-netdev configuration. This configuration will
+ * be cleared when the interface goes down and on the disconnection from a
+ * BSS. Driver supporting this feature should advertise
+ * NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK and supporting per station
+ * TX bitrate configuration should advertise
+ * NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK.
*/
enum nl80211_attr_tid_config {
__NL80211_ATTR_TID_INVALID,
@@ -4655,6 +4686,8 @@ enum nl80211_attr_tid_config {
NL80211_ATTR_TID_CONFIG_RETRY_LONG,
NL80211_ATTR_TID_CONFIG_AMPDU_CTRL,
NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL,
+ NL80211_ATTR_TID_CONFIG_TX_RATES_TYPE,
+ NL80211_ATTR_TID_CONFIG_TX_RATES,
/* keep last */
__NL80211_ATTR_TID_CONFIG_AFTER_LAST,
@@ -5477,6 +5510,10 @@ enum nl80211_feature_flags {
* RTS_CTS control(enable/disable).
* @NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL: Driver supports STA specific
* RTS_CTS control(enable/disable).
+ * @NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK: Driver supports TID specific
+ * TX bitrate configuration.
+ * @NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK: Driver supports STA specific
+ * TX bitrate configuration.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5527,6 +5564,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL,
NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL,
NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL,
+ NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK,
+ NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 47bfc62..1e46778 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -280,6 +280,15 @@ static int validate_ie_attr(const struct nlattr *attr,
NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
};
+static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
+ [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_RATES },
+ [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_HT_RATES },
+ [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
+ [NL80211_TXRATE_GI] = { .type = NLA_U8 },
+};
+
static const struct nla_policy
nl80211_attr_tid_config_policy[NL80211_ATTR_TID_CONFIG_MAX + 1] = {
[NL80211_ATTR_TID_CONFIG_TID] = { .type = NLA_U8 },
@@ -292,6 +301,10 @@ static int validate_ie_attr(const struct nlattr *attr,
NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
[NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL] =
NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+ [NL80211_ATTR_TID_CONFIG_TX_RATES_TYPE] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TX_RATE_FIXED),
+ [NL80211_ATTR_TID_CONFIG_TX_RATES] =
+ NLA_POLICY_NESTED(nl80211_txattr_policy),
};
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
@@ -397,7 +410,8 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
- [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_TX_RATES] =
+ NLA_POLICY_NESTED(nl80211_txattr_policy),
[NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
@@ -4014,20 +4028,12 @@ static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
return true;
}
-static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
- [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
- .len = NL80211_MAX_SUPP_RATES },
- [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
- .len = NL80211_MAX_SUPP_HT_RATES },
- [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
- [NL80211_TXRATE_GI] = { .type = NLA_U8 },
-};
-
-static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
+static int nl80211_parse_tx_bitrate_mask(struct nlattr *attrs[],
+ struct cfg80211_registered_device *rdev,
+ enum nl80211_attrs attr,
struct cfg80211_bitrate_mask *mask)
{
struct nlattr *tb[NL80211_TXRATE_MAX + 1];
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
int rem, i;
struct nlattr *tx_rates;
struct ieee80211_supported_band *sband;
@@ -4054,14 +4060,14 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
}
/* if no rates are given set it back to the defaults */
- if (!info->attrs[NL80211_ATTR_TX_RATES])
+ if (!attrs[attr])
goto out;
/* The nested attribute uses enum nl80211_band as the index. This maps
* directly to the enum nl80211_band values used in cfg80211.
*/
BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
- nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
+ nla_for_each_nested(tx_rates, attrs[attr], rem) {
enum nl80211_band band = nla_type(tx_rates);
int err;
@@ -4071,7 +4077,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
if (sband == NULL)
return -EINVAL;
err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
- nl80211_txattr_policy, info->extack);
+ NULL, NULL);
if (err)
return err;
if (tb[NL80211_TXRATE_LEGACY]) {
@@ -4504,7 +4510,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
if (info->attrs[NL80211_ATTR_TX_RATES]) {
- err = nl80211_parse_tx_bitrate_mask(info, ¶ms.beacon_rate);
+ err = nl80211_parse_tx_bitrate_mask(info->attrs, rdev,
+ NL80211_ATTR_TX_RATES,
+ ¶ms.beacon_rate);
if (err)
return err;
@@ -10110,7 +10118,8 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
if (!rdev->ops->set_bitrate_mask)
return -EOPNOTSUPP;
- err = nl80211_parse_tx_bitrate_mask(info, &mask);
+ err = nl80211_parse_tx_bitrate_mask(info->attrs, rdev, NL80211_ATTR_TX_RATES,
+ &mask);
if (err)
return err;
@@ -10702,7 +10711,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_TX_RATES]) {
- err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
+ err = nl80211_parse_tx_bitrate_mask(info->attrs, rdev,
+ NL80211_ATTR_TX_RATES,
+ &setup.beacon_rate);
if (err)
return err;
@@ -13278,8 +13289,10 @@ static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
static int parse_tid_conf(struct cfg80211_registered_device *rdev,
struct nlattr *attrs[],
struct ieee80211_tid_cfg *tid_conf,
- const u8 *peer)
+ struct genl_info *info, const u8 *peer)
{
+ int ret;
+
tid_conf->tid = nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_TID]);
if (attrs[NL80211_ATTR_TID_CONFIG_NOACK]) {
if (!wiphy_ext_feature_isset(&rdev->wiphy,
@@ -13354,6 +13367,42 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev,
nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL]);
}
+ if (attrs[NL80211_ATTR_TID_CONFIG_TX_RATES_TYPE]) {
+ int idx;
+ enum nl80211_attrs attr;
+
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_TX_BITRATE_MASK))
+ return -EOPNOTSUPP;
+
+ if (peer &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_TX_BITRATE_MASK))
+ return -EOPNOTSUPP;
+
+ idx = NL80211_ATTR_TID_CONFIG_TX_RATES_TYPE;
+ tid_conf->txrate_type = nla_get_u8(attrs[idx]);
+
+ tid_conf->tid_conf_mask |= IEEE80211_TID_CONF_TX_BITRATE;
+ if (tid_conf->txrate_type != NL80211_TX_RATE_AUTOMATIC) {
+ tid_conf->mask =
+ kzalloc(sizeof(struct cfg80211_bitrate_mask),
+ GFP_KERNEL);
+ if (!tid_conf->mask)
+ return -ENOMEM;
+
+ attr = NL80211_ATTR_TID_CONFIG_TX_RATES;
+ ret = nl80211_parse_tx_bitrate_mask(attrs, rdev, attr,
+ tid_conf->mask);
+ if (ret) {
+ kfree(tid_conf->mask);
+ return ret;
+ }
+ } else {
+ tid_conf->mask = NULL;
+ }
+ }
+
return 0;
}
@@ -13405,7 +13454,7 @@ static int nl80211_set_tid_config(struct sk_buff *skb,
return -EINVAL;
ret = parse_tid_conf(rdev, attrs, &tid_conf->tid_conf[conf_idx],
- tid_conf->peer);
+ info, tid_conf->peer);
if (ret)
goto bad_tid_conf;
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 4/9] nl80211: Add netlink attribute to enable/disable RTS_CTS
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
Introduce NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL in nl80211_attr_tid_config
to accept TID specific RTS_CTS enable/disable configuration
through NL80211_CMD_SET_TID_CONFIG command. TID for which the
RTS_CTS control configuration is to be applied is passed in
NL80211_ATTR_TID_CONFIG_TID attribute. When the user-space wants this
configuration peer specific rather than being applied for all the
connected stations, MAC address of the peer can be passed in
NL80211_ATTR_MAC attribute.
Driver supporting this feature should advertise
NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL and supporting per-STA data TID
RTS_CTS configuration should advertise NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/cfg80211.h | 3 +++
include/uapi/linux/nl80211.h | 22 ++++++++++++++++++++++
net/wireless/nl80211.c | 17 +++++++++++++++++
3 files changed, 42 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index aa0f44c..86dee3d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -513,6 +513,7 @@ enum ieee80211_tid_conf_mask {
IEEE80211_TID_CONF_NOACK = BIT(0),
IEEE80211_TID_CONF_RETRY = BIT(1),
IEEE80211_TID_CONF_AMPDU = BIT(2),
+ IEEE80211_TID_CONF_RTSCTS = BIT(3),
};
/**
@@ -524,6 +525,7 @@ enum ieee80211_tid_conf_mask {
* @retry_long: retry count value
* @retry_short: retry count value
* @ampdu: Enable/Disable aggregation
+ * @rtscts: Enable/Disable RTS/CTS
*/
struct ieee80211_tid_cfg {
u8 tid;
@@ -532,6 +534,7 @@ struct ieee80211_tid_cfg {
int retry_long;
int retry_short;
u8 ampdu;
+ u8 rtscts;
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f94651d..996b4d4 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4630,6 +4630,21 @@ enum nl80211_tid_config {
* NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL and supporting per station
* aggregation configuration should advertise
* NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL.
+ * @NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TID
+ * specified in %%NL80211_ATTR_TID_CONFIG_TID. It is u8 type, if the
+ * peer MAC address is passed in %NL80211_ATTR_MAC, then this
+ * configuration is applied to the data frame for the tid to that
+ * connected station.
+ * Station specific RTS_CTS configuration is valid only for STA's
+ * current connection. i.e. the configuration will be reset to default when
+ * the station connects back after disconnection/roaming.
+ * when user-space does not include %NL80211_ATTR_MAC, this configuration
+ * should be treated as per-netdev configuration. This configuration will
+ * be cleared when the interface goes down and on the disconnection from a
+ * BSS. Driver supporting this feature should advertise
+ * NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL and supporting per station
+ * RTS_CTS configuration should advertise
+ * NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL.
*/
enum nl80211_attr_tid_config {
__NL80211_ATTR_TID_INVALID,
@@ -4639,6 +4654,7 @@ enum nl80211_attr_tid_config {
NL80211_ATTR_TID_CONFIG_RETRY_SHORT,
NL80211_ATTR_TID_CONFIG_RETRY_LONG,
NL80211_ATTR_TID_CONFIG_AMPDU_CTRL,
+ NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL,
/* keep last */
__NL80211_ATTR_TID_CONFIG_AFTER_LAST,
@@ -5457,6 +5473,10 @@ enum nl80211_feature_flags {
* aggregation control(enable/disable).
* @NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL: Driver supports per STA
* specific TID aggregation control(enable/disable).
+ * @NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL: Driver supports TID specific
+ * RTS_CTS control(enable/disable).
+ * @NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL: Driver supports STA specific
+ * RTS_CTS control(enable/disable).
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5505,6 +5525,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG,
NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL,
NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL,
+ NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL,
+ NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a001d0..47bfc62 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -290,6 +290,8 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_TID_CONFIG_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
[NL80211_ATTR_TID_CONFIG_AMPDU_CTRL] =
NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+ [NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
};
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
@@ -13337,6 +13339,21 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev,
tid_conf->ampdu =
nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_AMPDU_CTRL]);
}
+
+ if (attrs[NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL]) {
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_RTSCTS_CTRL))
+ return -ENOTSUPP;
+
+ if (peer && !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_RTSCTS_CTRL))
+ return -ENOTSUPP;
+
+ tid_conf->tid_conf_mask |= IEEE80211_TID_CONF_RTSCTS;
+ tid_conf->rtscts =
+ nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_RTSCTS_CTRL]);
+ }
+
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 3/9] nl80211: Add netlink attribute for AMPDU aggregation enable/disable
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
Introduce NL80211_ATTR_TID_CONFIG_AMPDU_CTRL in nl80211_attr_tid_config
to accept TID specific AMPDU aggregation enable/disable configuration
through NL80211_CMD_SET_TID_CONFIG command. TID for which the
aggregation control configuration is to be applied is passed in
NL80211_ATTR_TID_CONFIG_TID attribute. When the user-space wants this
configuration peer specific rather than being applied for all the
connected stations, MAC address of the peer can be passed in
NL80211_ATTR_MAC attribute.
Driver supporting this feature should advertise
NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL and supporting per-STA data TID
ampdu configuration should advertise NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/cfg80211.h | 3 +++
include/uapi/linux/nl80211.h | 22 ++++++++++++++++++++++
net/wireless/nl80211.c | 15 +++++++++++++++
3 files changed, 40 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 888de00..aa0f44c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -512,6 +512,7 @@ struct cfg80211_chan_def {
enum ieee80211_tid_conf_mask {
IEEE80211_TID_CONF_NOACK = BIT(0),
IEEE80211_TID_CONF_RETRY = BIT(1),
+ IEEE80211_TID_CONF_AMPDU = BIT(2),
};
/**
@@ -522,6 +523,7 @@ enum ieee80211_tid_conf_mask {
* @noack: noack configuration value for the TID
* @retry_long: retry count value
* @retry_short: retry count value
+ * @ampdu: Enable/Disable aggregation
*/
struct ieee80211_tid_cfg {
u8 tid;
@@ -529,6 +531,7 @@ struct ieee80211_tid_cfg {
u8 noack;
int retry_long;
int retry_short;
+ u8 ampdu;
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f2ce845..f94651d 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4615,6 +4615,21 @@ enum nl80211_tid_config {
* the max value should be advertised by the driver through
* max_data_retry_count. when this attribute is not present, the driver
* would use the default configuration.
+ * @NL80211_ATTR_TID_CONFIG_AMPDU_CTRL: Enable/Disable aggregation for the TID
+ * specified in %%NL80211_ATTR_TID_CONFIG_TID. Its type is u8,
+ * if the peer MAC address is passed in %NL80211_ATTR_MAC, the aggregation
+ * configuration is applied
+ * to the data frame for the tid to that connected station.
+ * Station specific aggregation configuration is valid only for STA's
+ * current connection. i.e. the configuration will be reset to default when
+ * the station connects back after disconnection/roaming.
+ * when user-space does not include %NL80211_ATTR_MAC, this configuration
+ * should be treated as per-netdev configuration. This configuration will
+ * be cleared when the interface goes down and on the disconnection from a
+ * BSS. Driver supporting this feature should advertise
+ * NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL and supporting per station
+ * aggregation configuration should advertise
+ * NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL.
*/
enum nl80211_attr_tid_config {
__NL80211_ATTR_TID_INVALID,
@@ -4623,6 +4638,7 @@ enum nl80211_attr_tid_config {
NL80211_ATTR_TID_CONFIG_RETRY,
NL80211_ATTR_TID_CONFIG_RETRY_SHORT,
NL80211_ATTR_TID_CONFIG_RETRY_LONG,
+ NL80211_ATTR_TID_CONFIG_AMPDU_CTRL,
/* keep last */
__NL80211_ATTR_TID_CONFIG_AFTER_LAST,
@@ -5437,6 +5453,10 @@ enum nl80211_feature_flags {
* count functionality.
* @NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG: Driver supports STA specific
* data retry count functionality.
+ * @NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL: Driver supports TID specific
+ * aggregation control(enable/disable).
+ * @NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL: Driver supports per STA
+ * specific TID aggregation control(enable/disable).
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5483,6 +5503,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG,
NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG,
NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG,
+ NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL,
+ NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d53eb40..1a001d0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -288,6 +288,8 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_TID_CONFIG_RETRY] = { .type = NLA_FLAG },
[NL80211_ATTR_TID_CONFIG_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
[NL80211_ATTR_TID_CONFIG_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
+ [NL80211_ATTR_TID_CONFIG_AMPDU_CTRL] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
};
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
@@ -13322,6 +13324,19 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev,
}
}
+ if (attrs[NL80211_ATTR_TID_CONFIG_AMPDU_CTRL]) {
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_AMPDU_CTRL))
+ return -ENOTSUPP;
+
+ if (peer && !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_AMPDU_CTRL))
+ return -ENOTSUPP;
+
+ tid_conf->tid_conf_mask |= IEEE80211_TID_CONF_AMPDU;
+ tid_conf->ampdu =
+ nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_AMPDU_CTRL]);
+ }
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 2/9] nl80211: Add new netlink attribute for TID speicific retry count
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
This patch introduced below NL attributes to add support for
configuring data TID specific retry count
NL80211_ATTR_TID_CONFIG_RETRY
NL80211_ATTR_TID_CONFIG_RETRY_LONG
NL80211_ATTR_TID_CONFIG_RETRY_SHORT
These attributes are added in NL80211_ATTR_TID_CONFIG nested attribute.
This will be useful for the driver which supports data TID specific retry
count configuration rather using phy level retry configuration.
This TID specific retry configuration will have more precedence than
phy level configuration. This configuration can be applied for a
specific peer. To apply this configuration specific to a peer
rather than being applied for all the connected stations,
MAC address of the peer can be passed in NL80211_ATTR_MAC attribute.
Driver should advertise WIPHY_FLAG_HAS_MAX_DATA_RETRY_COUNT and
max_data_retry_count value to notify user space to avoid of passing
greater than the allowed limit.
Driver supporting TID specific retry configuration should advertise
NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG and per STA specific
data TID retry configuration should advertise
NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/cfg80211.h | 11 ++++++++++
include/uapi/linux/nl80211.h | 48 ++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.c | 34 ++++++++++++++++++++++++++++++
3 files changed, 93 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index c606e78..888de00 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -511,6 +511,7 @@ struct cfg80211_chan_def {
enum ieee80211_tid_conf_mask {
IEEE80211_TID_CONF_NOACK = BIT(0),
+ IEEE80211_TID_CONF_RETRY = BIT(1),
};
/**
@@ -519,11 +520,15 @@ enum ieee80211_tid_conf_mask {
* @tid_conf_mask: bitmap indicating which parameter changed
* see %enum ieee80211_tid_conf_mask
* @noack: noack configuration value for the TID
+ * @retry_long: retry count value
+ * @retry_short: retry count value
*/
struct ieee80211_tid_cfg {
u8 tid;
enum ieee80211_tid_conf_mask tid_conf_mask;
u8 noack;
+ int retry_long;
+ int retry_short;
};
/**
@@ -3832,6 +3837,7 @@ struct cfg80211_ops {
* beaconing mode (AP, IBSS, Mesh, ...).
* @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation
* before connection.
+ * @WIPHY_FLAG_HAS_MAX_DATA_RETRY_COUNT: Device supports data retry count call.
*/
enum wiphy_flags {
/* use hole at 0 */
@@ -3858,6 +3864,7 @@ enum wiphy_flags {
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23),
WIPHY_FLAG_HAS_STATIC_WEP = BIT(24),
+ WIPHY_FLAG_HAS_MAX_DATA_RETRY_COUNT = BIT(25),
};
/**
@@ -4365,6 +4372,8 @@ struct cfg80211_pmsr_capabilities {
* @support_mbssid must be set for this to have any effect.
*
* @pmsr_capa: peer measurement capabilities
+ * @max_data_retry_count: Maximum limit can be configured as retry count
+ * for a TID.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -4509,6 +4518,8 @@ struct wiphy {
const struct cfg80211_pmsr_capabilities *pmsr_capa;
+ u8 max_data_retry_count;
+
char priv[0] __aligned(NETDEV_ALIGN);
};
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c901a48..f2ce845 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2316,6 +2316,8 @@ enum nl80211_commands {
*
* @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
* nested attribute with %NL80211_ATTR_TID_* sub-attributes.
+ * @NL80211_ATTR_MAX_RETRY_COUNT: The upper limit for the retry count
+ * configuration that the driver can accept.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2769,6 +2771,7 @@ enum nl80211_attrs {
NL80211_ATTR_AIRTIME_WEIGHT,
NL80211_ATTR_TID_CONFIG,
+ NL80211_ATTR_MAX_RETRY_COUNT,
/* add attributes here, update the policy in nl80211.c */
@@ -4576,11 +4579,50 @@ enum nl80211_tid_config {
* advertise NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG and
* NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG for supporting per sta
* configuration.
+ * @NL80211_ATTR_TID_CONFIG_RETRY: Data TID retry count should be applied
+ * with the value passed through %NL80211_ATTR_TID_CONFIG_RETRY_LONG
+ * and/or %NL80211_ATTR_TID_CONFIG_RETRY_SHORT. This configuration
+ * is per-TID, and the TID is specified with %NL80211_ATTR_TID_CONFIG_TID.
+ * If the peer MAC address is passed in %NL80211_ATTR_MAC, the retry
+ * configuration is applied to the data frame for the tid to that
+ * connected station.
+ * This attribute will be useful to notfiy the driver to apply default
+ * retry values for the connected station (%NL80211_ATTR_MAC), when the
+ * command received without %NL80211_ATTR_RETRY_LONG and/or
+ * %NL80211_ATTR_RETRY_SHORT.
+ * Station specific retry configuration is valid only for STA's
+ * current connection. i.e. the configuration will be reset to default when
+ * the station connects back after disconnection/roaming.
+ * when user-space does not include %NL80211_ATTR_MAC, this configuration
+ * should be treated as per-netdev configuration. This configuration will
+ * be cleared when the interface goes down and on the disconnection from a
+ * BSS. When retry count has never been configured using this command, the
+ * other available radio level retry configuration
+ * (%NL80211_ATTR_WIPHY_RETRY_SHORT and %NL80211_ATTR_WIPHY_RETRY_LONG)
+ * should be used. Driver supporting this feature should advertise
+ * NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG and supporting per station
+ * retry count configuration should advertise
+ * NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG.
+ * @NL80211_ATTR_TID_CONFIG_RETRY_SHORT: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and
+ * the max value should be advertised by the driver through
+ * max_data_retry_count. when this attribute is not present, the driver
+ * would use the default configuration.
+ * @NL80211_ATTR_TID_CONFIG_RETRY_LONG: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
+ * the max value should be advertised by the driver through
+ * max_data_retry_count. when this attribute is not present, the driver
+ * would use the default configuration.
*/
enum nl80211_attr_tid_config {
__NL80211_ATTR_TID_INVALID,
NL80211_ATTR_TID_CONFIG_TID,
NL80211_ATTR_TID_CONFIG_NOACK,
+ NL80211_ATTR_TID_CONFIG_RETRY,
+ NL80211_ATTR_TID_CONFIG_RETRY_SHORT,
+ NL80211_ATTR_TID_CONFIG_RETRY_LONG,
/* keep last */
__NL80211_ATTR_TID_CONFIG_AFTER_LAST,
@@ -5391,6 +5433,10 @@ enum nl80211_feature_flags {
* policy functionality.
* @NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG: Driver supports STA specific NoAck
* policy functionality.
+ * @NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG: Driver supports per TID data retry
+ * count functionality.
+ * @NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG: Driver supports STA specific
+ * data retry count functionality.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5435,6 +5481,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG,
NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG,
+ NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG,
+ NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f0e44ee..d53eb40 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -285,6 +285,9 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_TID_CONFIG_TID] = { .type = NLA_U8 },
[NL80211_ATTR_TID_CONFIG_NOACK] =
NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+ [NL80211_ATTR_TID_CONFIG_RETRY] = { .type = NLA_FLAG },
+ [NL80211_ATTR_TID_CONFIG_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
+ [NL80211_ATTR_TID_CONFIG_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
};
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
@@ -13288,6 +13291,37 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev,
nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_NOACK]);
}
+ if (nla_get_flag(attrs[NL80211_ATTR_TID_CONFIG_RETRY])) {
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_RETRY_CONFIG))
+ return -ENOTSUPP;
+
+ if (peer && !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_RETRY_CONFIG))
+ return -ENOTSUPP;
+
+ tid_conf->tid_conf_mask |= IEEE80211_TID_CONF_RETRY;
+ if (attrs[NL80211_ATTR_TID_CONFIG_RETRY_SHORT]) {
+ tid_conf->retry_short =
+ nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_RETRY_SHORT]);
+ if (tid_conf->retry_short >
+ rdev->wiphy.max_data_retry_count)
+ return -EINVAL;
+ } else {
+ tid_conf->retry_short = -1;
+ }
+
+ if (attrs[NL80211_ATTR_TID_CONFIG_RETRY_LONG]) {
+ tid_conf->retry_long =
+ nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_RETRY_LONG]);
+ if (tid_conf->retry_long >
+ rdev->wiphy.max_data_retry_count)
+ return -EINVAL;
+ } else {
+ tid_conf->retry_long = -1;
+ }
+ }
+
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 1/9] nl80211: New netlink command for TID specific configuration
From: Tamizh chelvam @ 2019-03-11 6:48 UTC (permalink / raw)
To: johannes, ath10k; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1552286901-28285-1-git-send-email-tamizhr@codeaurora.org>
Add a new NL command, NL80211_CMD_SET_TID_CONFIG to support
data TID specific configuration. This per TID configurations
are passed in NL80211_ATTR_TID_CONFIG which is a nested
attribute. This patch adds support to configure per TID
noack policy through NL80211_ATTR_TID_CONFIG_NOACK attribute.
Data TID value for this configuration will be passed through
NL80211_ATTR_TID_CONFIG_TID attribute. When the user-space wants
this configuration peer specific rather than being applied for
all the connected stations, MAC address of the peer can be passed
in NL80211_ATTR_MAC attribute. This patch introduced
enum ieee80211_tid_conf_mask to notify the driver that which
configuration modified.
Driver supporting data TID specific noack policy configuration
should be advertise through NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG
and supporting per STA data TID noack policy configuration
should be advertise through NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/cfg80211.h | 35 +++++++++++++++
include/uapi/linux/nl80211.h | 51 +++++++++++++++++++++
net/wireless/nl80211.c | 102 ++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 11 +++++
net/wireless/trace.h | 18 ++++++++
5 files changed, 217 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bb307a1..c606e78 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -509,6 +509,35 @@ struct cfg80211_chan_def {
u32 center_freq2;
};
+enum ieee80211_tid_conf_mask {
+ IEEE80211_TID_CONF_NOACK = BIT(0),
+};
+
+/**
+ * struct ieee80211_tid_cfg - TID specific configuration
+ * @tid: TID number
+ * @tid_conf_mask: bitmap indicating which parameter changed
+ * see %enum ieee80211_tid_conf_mask
+ * @noack: noack configuration value for the TID
+ */
+struct ieee80211_tid_cfg {
+ u8 tid;
+ enum ieee80211_tid_conf_mask tid_conf_mask;
+ u8 noack;
+};
+
+/**
+ * struct ieee80211_tid_config - TID configuration
+ * @peer: Station's MAC address
+ * @n_tid_conf: Number of TID specific configurations to be applied
+ * @tid_conf: Configuration change info
+ */
+struct ieee80211_tid_config {
+ const u8 *peer;
+ u32 n_tid_conf;
+ struct ieee80211_tid_cfg tid_conf[];
+};
+
/**
* cfg80211_get_chandef_type - return old channel type from chandef
* @chandef: the channel definition
@@ -3436,6 +3465,10 @@ struct cfg80211_pmsr_request {
* Statistics should be cumulative, currently no way to reset is provided.
* @start_pmsr: start peer measurement (e.g. FTM)
* @abort_pmsr: abort peer measurement
+ * @set_tid_config: TID specific configuration. Apply this configuration for
+ * all the connected stations in the BSS if peer is NULL. Otherwise
+ * apply this configuration to the specific station.
+ * This callback may sleep.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3750,6 +3783,8 @@ struct cfg80211_ops {
struct cfg80211_pmsr_request *request);
void (*abort_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_pmsr_request *request);
+ int (*set_tid_config)(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_tid_config *tid_conf);
};
/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index dd4f86e..c901a48 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1065,6 +1065,10 @@
* indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes
* determining the width and type.
*
+ * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
+ * is passed through this command using %NL80211_ATTR_TID_CONFIG
+ * nested attributes.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1285,6 +1289,8 @@ enum nl80211_commands {
NL80211_CMD_NOTIFY_RADAR,
+ NL80211_CMD_SET_TID_CONFIG,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2308,6 +2314,9 @@ enum nl80211_commands {
* @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
* scheduler.
*
+ * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
+ * nested attribute with %NL80211_ATTR_TID_* sub-attributes.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2759,6 +2768,8 @@ enum nl80211_attrs {
NL80211_ATTR_AIRTIME_WEIGHT,
+ NL80211_ATTR_TID_CONFIG,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -4543,6 +4554,39 @@ enum nl80211_tx_power_setting {
NL80211_TX_POWER_FIXED,
};
+enum nl80211_tid_config {
+ NL80211_TID_CONFIG_DEFAULT,
+ NL80211_TID_CONFIG_ENABLE,
+ NL80211_TID_CONFIG_DISABLE,
+};
+
+/* enum nl80211_attr_tid_config - TID specific configuration.
+ * @NL80211_ATTR_TID_CONFIG_TID: a TID value (u8 attribute).
+ * @NL80211_ATTR_TID_CONFIG_NOACK: Configure ack policy for the TID.
+ * specified in %NL80211_ATTR_TID_CONFIG_TID. see %enum nl80211_tid_config.
+ * Its type is u8, if the peer MAC address is passed in %NL80211_ATTR_MAC,
+ * then the noack configuration is applied to the data frame for the tid
+ * to that connected station. This configuration is valid only for STA's
+ * current connection. i.e. the configuration will be reset to default when
+ * the station connects back after disconnection/roaming.
+ * when user-space does not include %NL80211_ATTR_MAC, then this
+ * configuration should be treated as per-netdev configuration.
+ * This configuration will be cleared when the interface goes down and on
+ * the disconnection from a BSS. Driver supporting this feature should
+ * advertise NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG and
+ * NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG for supporting per sta
+ * configuration.
+ */
+enum nl80211_attr_tid_config {
+ __NL80211_ATTR_TID_INVALID,
+ NL80211_ATTR_TID_CONFIG_TID,
+ NL80211_ATTR_TID_CONFIG_NOACK,
+
+ /* keep last */
+ __NL80211_ATTR_TID_CONFIG_AFTER_LAST,
+ NL80211_ATTR_TID_CONFIG_MAX = __NL80211_ATTR_TID_CONFIG_AFTER_LAST - 1
+};
+
/**
* enum nl80211_packet_pattern_attr - packet pattern attribute
* @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
@@ -5343,6 +5387,11 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching
* (set/del PMKSA operations) in AP mode.
*
+ * @NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG: Driver supports per TID NoAck
+ * policy functionality.
+ * @NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG: Driver supports STA specific NoAck
+ * policy functionality.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5384,6 +5433,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
+ NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG,
+ NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 25a9e3b..f0e44ee 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -280,6 +280,13 @@ static int validate_ie_attr(const struct nlattr *attr,
NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
};
+static const struct nla_policy
+nl80211_attr_tid_config_policy[NL80211_ATTR_TID_CONFIG_MAX + 1] = {
+ [NL80211_ATTR_TID_CONFIG_TID] = { .type = NLA_U8 },
+ [NL80211_ATTR_TID_CONFIG_NOACK] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+};
+
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
@@ -541,6 +548,8 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_PEER_MEASUREMENTS] =
NLA_POLICY_NESTED(nl80211_pmsr_attr_policy),
[NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
+ [NL80211_ATTR_TID_CONFIG] =
+ NLA_POLICY_NESTED(nl80211_attr_tid_config_policy),
};
/* policy for the key attributes */
@@ -13259,6 +13268,91 @@ static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
return -ENOBUFS;
}
+static int parse_tid_conf(struct cfg80211_registered_device *rdev,
+ struct nlattr *attrs[],
+ struct ieee80211_tid_cfg *tid_conf,
+ const u8 *peer)
+{
+ tid_conf->tid = nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_TID]);
+ if (attrs[NL80211_ATTR_TID_CONFIG_NOACK]) {
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_TID_NOACK_CONFIG))
+ return -ENOTSUPP;
+
+ if (peer && !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_PER_STA_NOACK_CONFIG))
+ return -ENOTSUPP;
+
+ tid_conf->tid_conf_mask |= IEEE80211_TID_CONF_NOACK;
+ tid_conf->noack =
+ nla_get_u8(attrs[NL80211_ATTR_TID_CONFIG_NOACK]);
+ }
+
+ return 0;
+}
+
+static int nl80211_set_tid_config(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct nlattr *attrs[NL80211_ATTR_TID_CONFIG_MAX + 1];
+ struct net_device *dev = info->user_ptr[1];
+ struct ieee80211_tid_config *tid_conf;
+ struct nlattr *tid;
+ int conf_idx = 0, rem_conf;
+ u32 num_conf = 0, size_of_conf;
+ int ret = -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_TID_CONFIG])
+ return -EINVAL;
+
+ if (!rdev->ops->set_tid_config)
+ return -EOPNOTSUPP;
+
+ nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
+ rem_conf)
+ num_conf++;
+
+ size_of_conf = sizeof(struct ieee80211_tid_config) +
+ num_conf * sizeof(struct ieee80211_tid_cfg);
+
+ tid_conf = kzalloc(size_of_conf, GFP_KERNEL);
+ if (!tid_conf)
+ return -ENOMEM;
+
+ tid_conf->n_tid_conf = num_conf;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ tid_conf->peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ else
+ tid_conf->peer = NULL;
+
+ nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
+ rem_conf) {
+ ret = nla_parse_nested(attrs, NL80211_ATTR_TID_CONFIG_MAX, tid,
+ NULL, NULL);
+
+ if (ret)
+ return ret;
+
+ if (!attrs[NL80211_ATTR_TID_CONFIG_TID])
+ return -EINVAL;
+
+ ret = parse_tid_conf(rdev, attrs, &tid_conf->tid_conf[conf_idx],
+ tid_conf->peer);
+ if (ret)
+ goto bad_tid_conf;
+
+ conf_idx++;
+ }
+
+ ret = rdev_set_tid_config(rdev, dev, tid_conf);
+
+bad_tid_conf:
+ kfree(tid_conf);
+ return ret;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -14193,6 +14287,14 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_TID_CONFIG,
+ .doit = nl80211_set_tid_config,
+ .policy = nl80211_policy,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 5cb48d1..59e1905 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1272,4 +1272,15 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}
+static inline int rdev_set_tid_config(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ieee80211_tid_config *tid_conf)
+{
+ int ret;
+
+ trace_rdev_set_tid_config(&rdev->wiphy, dev, tid_conf);
+ ret = rdev->ops->set_tid_config(&rdev->wiphy, dev, tid_conf);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 44b2ce1..186de1f 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3362,6 +3362,24 @@
WIPHY_PR_ARG, WDEV_PR_ARG,
(unsigned long long)__entry->cookie)
);
+
+TRACE_EVENT(rdev_set_tid_config,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct ieee80211_tid_config *tid_conf),
+ TP_ARGS(wiphy, netdev, tid_conf),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(peer)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(peer, tid_conf->peer);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
1.7.9.5
^ 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