#include "p2p.h"
 #include "btcoex.h"
 #include "pno.h"
+#include "fwsignal.h"
 #include "cfg80211.h"
 #include "feature.h"
 #include "fwil.h"
        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,
                               struct brcmf_if *ifp)
 {
        struct brcmf_pub *drvr = cfg->pub;
        struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
        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 resp_len;
        s32 err = 0;
                            GFP_KERNEL);
                if (!conn_info->resp_ie)
                        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 {
                conn_info->resp_ie_len = 0;
                conn_info->resp_ie = NULL;
        mutex_init(&cfg->usr_sync);
        brcmf_init_escan(cfg);
        brcmf_init_conf(cfg->conf);
+       brcmf_init_wmm_prio(cfg->ac_priority);
        init_completion(&cfg->vif_disabled);
        return err;
 }