Commit 92072e5f authored by Saravanan Shanmugham's avatar Saravanan Shanmugham Committed by Kalle Valo

brcmfmac: map 802.1d priority to precedence level based on AP WMM params

In WLAN, priority among various access categories of traffic is
always set by the AP using WMM parameters and this may not always
follow the standard 802.1d priority.

In this change, priority is adjusted based on the AP WMM params
received as part of the Assoc Response and the same is later used
to map the priority of all incoming traffic.

In a specific scenario where EDCA parameters are configured to be same
for all ACs, use the default FW priority definition to avoid queuing
packets of all ACs to the same priority queue.

This change fixes the following 802.11 certification tests:
* 11n - 5.2.31 ACM Bit Conformance test
* 11n - 5.2.32 AC Parameter Modification test
* 11ac - 5.2.33 TXOP Limit test
Signed-off-by: default avatarSaravanan Shanmugham <saravanan.shanmugham@cypress.com>
Signed-off-by: default avatarJustin Li <justin.li@cypress.com>
Signed-off-by: default avatarMadhan Mohan R <madhanmohan.r@cypress.com>
Signed-off-by: default avatarChi-hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1588661487-21884-2-git-send-email-chi-hsien.lin@cypress.com
parent 790709f2
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "p2p.h" #include "p2p.h"
#include "btcoex.h" #include "btcoex.h"
#include "pno.h" #include "pno.h"
#include "fwsignal.h"
#include "cfg80211.h" #include "cfg80211.h"
#include "feature.h" #include "feature.h"
#include "fwil.h" #include "fwil.h"
...@@ -5586,12 +5587,151 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) ...@@ -5586,12 +5587,151 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
conn_info->resp_ie_len = 0; conn_info->resp_ie_len = 0;
} }
u8 brcmf_map_prio_to_prec(void *config, u8 prio)
{
struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config;
if (!cfg)
return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
(prio ^ 2) : prio;
/* For those AC(s) with ACM flag set to 1, convert its 4-level priority
* to an 8-level precedence which is the same as BE's
*/
if (prio > PRIO_8021D_EE &&
cfg->ac_priority[prio] == cfg->ac_priority[PRIO_8021D_BE])
return cfg->ac_priority[prio] * 2;
/* Conversion of 4-level priority to 8-level precedence */
if (prio == PRIO_8021D_BE || prio == PRIO_8021D_BK ||
prio == PRIO_8021D_CL || prio == PRIO_8021D_VO)
return cfg->ac_priority[prio] * 2;
else
return cfg->ac_priority[prio] * 2 + 1;
}
u8 brcmf_map_prio_to_aci(void *config, u8 prio)
{
/* Prio here refers to the 802.1d priority in range of 0 to 7.
* ACI here refers to the WLAN AC Index in range of 0 to 3.
* This function will return ACI corresponding to input prio.
*/
struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config;
if (cfg)
return cfg->ac_priority[prio];
return prio;
}
static void brcmf_init_wmm_prio(u8 *priority)
{
/* Initialize AC priority array to default
* 802.1d priority as per following table:
* 802.1d prio 0,3 maps to BE
* 802.1d prio 1,2 maps to BK
* 802.1d prio 4,5 maps to VI
* 802.1d prio 6,7 maps to VO
*/
priority[0] = BRCMF_FWS_FIFO_AC_BE;
priority[3] = BRCMF_FWS_FIFO_AC_BE;
priority[1] = BRCMF_FWS_FIFO_AC_BK;
priority[2] = BRCMF_FWS_FIFO_AC_BK;
priority[4] = BRCMF_FWS_FIFO_AC_VI;
priority[5] = BRCMF_FWS_FIFO_AC_VI;
priority[6] = BRCMF_FWS_FIFO_AC_VO;
priority[7] = BRCMF_FWS_FIFO_AC_VO;
}
static void brcmf_wifi_prioritize_acparams(const
struct brcmf_cfg80211_edcf_acparam *acp, u8 *priority)
{
u8 aci;
u8 aifsn;
u8 ecwmin;
u8 ecwmax;
u8 acm;
u8 ranking_basis[EDCF_AC_COUNT];
u8 aci_prio[EDCF_AC_COUNT]; /* AC_BE, AC_BK, AC_VI, AC_VO */
u8 index;
for (aci = 0; aci < EDCF_AC_COUNT; aci++, acp++) {
aifsn = acp->ACI & EDCF_AIFSN_MASK;
acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0;
ecwmin = acp->ECW & EDCF_ECWMIN_MASK;
ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT;
brcmf_dbg(CONN, "ACI %d aifsn %d acm %d ecwmin %d ecwmax %d\n",
aci, aifsn, acm, ecwmin, ecwmax);
/* Default AC_VO will be the lowest ranking value */
ranking_basis[aci] = aifsn + ecwmin + ecwmax;
/* Initialise priority starting at 0 (AC_BE) */
aci_prio[aci] = 0;
/* If ACM is set, STA can't use this AC as per 802.11.
* Change the ranking to BE
*/
if (aci != AC_BE && aci != AC_BK && acm == 1)
ranking_basis[aci] = ranking_basis[AC_BE];
}
/* Ranking method which works for AC priority
* swapping when values for cwmin, cwmax and aifsn are varied
* Compare each aci_prio against each other aci_prio
*/
for (aci = 0; aci < EDCF_AC_COUNT; aci++) {
for (index = 0; index < EDCF_AC_COUNT; index++) {
if (index != aci) {
/* Smaller ranking value has higher priority,
* so increment priority for each ACI which has
* a higher ranking value
*/
if (ranking_basis[aci] < ranking_basis[index])
aci_prio[aci]++;
}
}
}
/* By now, aci_prio[] will be in range of 0 to 3.
* Use ACI prio to get the new priority value for
* each 802.1d traffic type, in this range.
*/
if (!(aci_prio[AC_BE] == aci_prio[AC_BK] &&
aci_prio[AC_BK] == aci_prio[AC_VI] &&
aci_prio[AC_VI] == aci_prio[AC_VO])) {
/* 802.1d 0,3 maps to BE */
priority[0] = aci_prio[AC_BE];
priority[3] = aci_prio[AC_BE];
/* 802.1d 1,2 maps to BK */
priority[1] = aci_prio[AC_BK];
priority[2] = aci_prio[AC_BK];
/* 802.1d 4,5 maps to VO */
priority[4] = aci_prio[AC_VI];
priority[5] = aci_prio[AC_VI];
/* 802.1d 6,7 maps to VO */
priority[6] = aci_prio[AC_VO];
priority[7] = aci_prio[AC_VO];
} else {
/* Initialize to default priority */
brcmf_init_wmm_prio(priority);
}
brcmf_dbg(CONN, "Adj prio BE 0->%d, BK 1->%d, BK 2->%d, BE 3->%d\n",
priority[0], priority[1], priority[2], priority[3]);
brcmf_dbg(CONN, "Adj prio VI 4->%d, VI 5->%d, VO 6->%d, VO 7->%d\n",
priority[4], priority[5], priority[6], priority[7]);
}
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp) struct brcmf_if *ifp)
{ {
struct brcmf_pub *drvr = cfg->pub; struct brcmf_pub *drvr = cfg->pub;
struct brcmf_cfg80211_assoc_ielen_le *assoc_info; struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT];
u32 req_len; u32 req_len;
u32 resp_len; u32 resp_len;
s32 err = 0; s32 err = 0;
...@@ -5640,6 +5780,17 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, ...@@ -5640,6 +5780,17 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
GFP_KERNEL); GFP_KERNEL);
if (!conn_info->resp_ie) if (!conn_info->resp_ie)
conn_info->resp_ie_len = 0; conn_info->resp_ie_len = 0;
err = brcmf_fil_iovar_data_get(ifp, "wme_ac_sta",
edcf_acparam_info,
sizeof(edcf_acparam_info));
if (err) {
brcmf_err("could not get wme_ac_sta (%d)\n", err);
return err;
}
brcmf_wifi_prioritize_acparams(edcf_acparam_info,
cfg->ac_priority);
} else { } else {
conn_info->resp_ie_len = 0; conn_info->resp_ie_len = 0;
conn_info->resp_ie = NULL; conn_info->resp_ie = NULL;
...@@ -6056,6 +6207,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) ...@@ -6056,6 +6207,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
mutex_init(&cfg->usr_sync); mutex_init(&cfg->usr_sync);
brcmf_init_escan(cfg); brcmf_init_escan(cfg);
brcmf_init_conf(cfg->conf); brcmf_init_conf(cfg->conf);
brcmf_init_wmm_prio(cfg->ac_priority);
init_completion(&cfg->vif_disabled); init_completion(&cfg->vif_disabled);
return err; return err;
} }
......
...@@ -23,6 +23,23 @@ ...@@ -23,6 +23,23 @@
#define WL_ROAM_TRIGGER_LEVEL -75 #define WL_ROAM_TRIGGER_LEVEL -75
#define WL_ROAM_DELTA 20 #define WL_ROAM_DELTA 20
/* WME Access Category Indices (ACIs) */
#define AC_BE 0 /* Best Effort */
#define AC_BK 1 /* Background */
#define AC_VI 2 /* Video */
#define AC_VO 3 /* Voice */
#define EDCF_AC_COUNT 4
#define MAX_8021D_PRIO 8
#define EDCF_ACI_MASK 0x60
#define EDCF_ACI_SHIFT 5
#define EDCF_ACM_MASK 0x10
#define EDCF_ECWMIN_MASK 0x0f
#define EDCF_ECWMAX_SHIFT 4
#define EDCF_AIFSN_MASK 0x0f
#define EDCF_AIFSN_MAX 15
#define EDCF_ECWMAX_MASK 0xf0
/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be /* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be
* problematic on some systems and should be avoided. * problematic on some systems and should be avoided.
*/ */
...@@ -209,6 +226,12 @@ struct brcmf_cfg80211_assoc_ielen_le { ...@@ -209,6 +226,12 @@ struct brcmf_cfg80211_assoc_ielen_le {
__le32 resp_len; __le32 resp_len;
}; };
struct brcmf_cfg80211_edcf_acparam {
u8 ACI;
u8 ECW;
u16 TXOP; /* stored in network order (ls octet first) */
};
/* dongle escan state */ /* dongle escan state */
enum wl_escan_state { enum wl_escan_state {
WL_ESCAN_STATE_IDLE, WL_ESCAN_STATE_IDLE,
...@@ -327,6 +350,7 @@ struct brcmf_cfg80211_info { ...@@ -327,6 +350,7 @@ struct brcmf_cfg80211_info {
struct brcmf_assoclist_le assoclist; struct brcmf_assoclist_le assoclist;
struct brcmf_cfg80211_wowl wowl; struct brcmf_cfg80211_wowl wowl;
struct brcmf_pno_info *pno; struct brcmf_pno_info *pno;
u8 ac_priority[MAX_8021D_PRIO];
}; };
/** /**
......
...@@ -72,4 +72,8 @@ static inline void ...@@ -72,4 +72,8 @@ static inline void
brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {} brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {}
#endif #endif
u8 brcmf_map_prio_to_prec(void *cfg, u8 prio);
u8 brcmf_map_prio_to_aci(void *cfg, u8 prio);
#endif /* BRCMFMAC_COMMON_H */ #endif /* BRCMFMAC_COMMON_H */
...@@ -311,28 +311,6 @@ struct brcmf_skbuff_cb { ...@@ -311,28 +311,6 @@ struct brcmf_skbuff_cb {
/* How long to defer borrowing in jiffies */ /* How long to defer borrowing in jiffies */
#define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10) #define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10)
/**
* enum brcmf_fws_fifo - fifo indices used by dongle firmware.
*
* @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background.
* @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
* @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
* @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
* @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
* @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
* @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
* @BRCMF_FWS_FIFO_COUNT: number of fifos.
*/
enum brcmf_fws_fifo {
BRCMF_FWS_FIFO_FIRST,
BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
BRCMF_FWS_FIFO_AC_BE,
BRCMF_FWS_FIFO_AC_VI,
BRCMF_FWS_FIFO_AC_VO,
BRCMF_FWS_FIFO_BCMC,
BRCMF_FWS_FIFO_ATIM,
BRCMF_FWS_FIFO_COUNT
};
/** /**
* enum brcmf_fws_txstatus - txstatus flag values. * enum brcmf_fws_txstatus - txstatus flag values.
...@@ -2130,8 +2108,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) ...@@ -2130,8 +2108,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
skcb->if_flags = 0; skcb->if_flags = 0;
skcb->state = BRCMF_FWS_SKBSTATE_NEW; skcb->state = BRCMF_FWS_SKBSTATE_NEW;
brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx); brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
/* mapping from 802.1d priority to firmware fifo index */
if (!multicast) if (!multicast)
fifo = brcmf_fws_prio2fifo[skb->priority]; fifo = brcmf_map_prio_to_aci(drvr->config, skb->priority);
brcmf_fws_lock(fws); brcmf_fws_lock(fws);
if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC) if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
......
...@@ -6,6 +6,29 @@ ...@@ -6,6 +6,29 @@
#ifndef FWSIGNAL_H_ #ifndef FWSIGNAL_H_
#define FWSIGNAL_H_ #define FWSIGNAL_H_
/**
* enum brcmf_fws_fifo - fifo indices used by dongle firmware.
*
* @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background.
* @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
* @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
* @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
* @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
* @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
* @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
* @BRCMF_FWS_FIFO_COUNT: number of fifos.
*/
enum brcmf_fws_fifo {
BRCMF_FWS_FIFO_FIRST,
BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
BRCMF_FWS_FIFO_AC_BE,
BRCMF_FWS_FIFO_AC_VI,
BRCMF_FWS_FIFO_AC_VO,
BRCMF_FWS_FIFO_BCMC,
BRCMF_FWS_FIFO_ATIM,
BRCMF_FWS_FIFO_COUNT
};
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr); struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
void brcmf_fws_detach(struct brcmf_fws_info *fws); void brcmf_fws_detach(struct brcmf_fws_info *fws);
void brcmf_fws_debugfs_create(struct brcmf_pub *drvr); void brcmf_fws_debugfs_create(struct brcmf_pub *drvr);
......
...@@ -315,15 +315,6 @@ struct rte_console { ...@@ -315,15 +315,6 @@ struct rte_console {
#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5 #define BRCMF_SDIO_MAX_ACCESS_ERRORS 5
/*
* Conversion of 802.1D priority to precedence level
*/
static uint prio2prec(u32 prio)
{
return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
(prio^2) : prio;
}
#ifdef DEBUG #ifdef DEBUG
/* Device console log buffer state */ /* Device console log buffer state */
struct brcmf_console { struct brcmf_console {
...@@ -2774,7 +2765,13 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) ...@@ -2774,7 +2765,13 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
skb_push(pkt, bus->tx_hdrlen); skb_push(pkt, bus->tx_hdrlen);
/* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
prec = prio2prec((pkt->priority & PRIOMASK)); /* In WLAN, priority is always set by the AP using WMM parameters
* and this need not always follow the standard 802.1d priority.
* Based on AP WMM config, map from 802.1d priority to corresponding
* precedence level.
*/
prec = brcmf_map_prio_to_prec(bus_if->drvr->config,
(pkt->priority & PRIOMASK));
/* Check for existing queue, current flow-control, /* Check for existing queue, current flow-control,
pending event, or pending clock */ pending event, or pending clock */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment