PageRenderTime 149ms CodeModel.GetById 24ms app.highlight 117ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/net/wireless/sd8797/mlan/mlan_wmm.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 2521 lines | 1609 code | 319 blank | 593 comment | 217 complexity | 023668abc83217137f2911e85c46548b MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

   1/** @file mlan_wmm.c
   2 *
   3 *  @brief This file contains functions for WMM.
   4 *
   5 *  Copyright (C) 2008-2011, Marvell International Ltd. 
   6 *
   7 *  This software file (the "File") is distributed by Marvell International
   8 *  Ltd. under the terms of the GNU General Public License Version 2, June 1991
   9 *  (the "License").  You may use, redistribute and/or modify this File in
  10 *  accordance with the terms and conditions of the License, a copy of which
  11 *  is available by writing to the Free Software Foundation, Inc.,
  12 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  13 *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  14 *
  15 *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  16 *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  17 *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  18 *  this warranty disclaimer.
  19 */
  20
  21/********************************************************
  22Change log:
  23    10/24/2008: initial version
  24********************************************************/
  25
  26#include "mlan.h"
  27#ifdef STA_SUPPORT
  28#include "mlan_join.h"
  29#endif
  30#include "mlan_util.h"
  31#include "mlan_fw.h"
  32#include "mlan_main.h"
  33#include "mlan_wmm.h"
  34#include "mlan_11n.h"
  35#include "mlan_sdio.h"
  36
  37/********************************************************
  38    Local Variables
  39********************************************************/
  40
  41/** Maximum value FW can accept for driver delay in packet transmission */
  42#define DRV_PKT_DELAY_TO_FW_MAX   512
  43
  44/*
  45 * Upper and Lower threshold for packet queuing in the driver
  46
  47 *    - When the number of packets queued reaches the upper limit,
  48 *      the driver will stop the net queue in the app/kernel space.
  49
  50 *    - When the number of packets drops beneath the lower limit after
  51 *      having reached the upper limit, the driver will restart the net
  52 *      queue.
  53 */
  54
  55/** Lower threshold for packet queuing in the driver.
  56  * When the number of packets drops beneath the lower limit after having
  57  * reached the upper limit, the driver will restart the net queue.
  58  */
  59#define WMM_QUEUED_PACKET_LOWER_LIMIT   180
  60
  61/** Upper threshold for packet queuing in the driver.
  62  * When the number of packets queued reaches the upper limit, the driver
  63  * will stop the net queue in the app/kernel space.
  64  */
  65#define WMM_QUEUED_PACKET_UPPER_LIMIT   200
  66
  67/** Offset for TOS field in the IP header */
  68#define IPTOS_OFFSET 5
  69
  70/** WMM information IE */
  71static const t_u8 wmm_info_ie[] = { WMM_IE, 0x07,
  72    0x00, 0x50, 0xf2, 0x02,
  73    0x00, 0x01, 0x00
  74};
  75
  76/**
  77 * AC Priorities go from AC_BK to AC_VO.  The ACI enumeration for AC_BK (1)
  78 *   is higher than the enumeration for AC_BE (0); hence the needed
  79 *   mapping conversion for wmm AC to priority Queue Index
  80 */
  81static const t_u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
  82    WMM_AC_BK,
  83    WMM_AC_VI,
  84    WMM_AC_VO
  85};
  86
  87/**
  88 * This table will be used to store the tid values based on ACs.
  89 * It is initialized to default values per TID.
  90 */
  91t_u8 tos_to_tid[] = {
  92    /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
  93    0x01,                       /* 0 1 0 AC_BK */
  94    0x02,                       /* 0 0 0 AC_BK */
  95    0x00,                       /* 0 0 1 AC_BE */
  96    0x03,                       /* 0 1 1 AC_BE */
  97    0x04,                       /* 1 0 0 AC_VI */
  98    0x05,                       /* 1 0 1 AC_VI */
  99    0x06,                       /* 1 1 0 AC_VO */
 100    0x07                        /* 1 1 1 AC_VO */
 101};
 102
 103/**
 104 * This table inverses the tos_to_tid operation to get a priority
 105 * which is in sequential order, and can be compared.
 106 * Use this to compare the priority of two different TIDs.
 107 */
 108t_u8 tos_to_tid_inv[] = { 0x02, /* from tos_to_tid[2] = 0 */
 109    0x00,                       /* from tos_to_tid[0] = 1 */
 110    0x01,                       /* from tos_to_tid[1] = 2 */
 111    0x03,
 112    0x04,
 113    0x05,
 114    0x06,
 115    0x07
 116};
 117
 118/**
 119 * This table will provide the tid value for given ac. This table does not
 120 * change and will be used to copy back the default values to tos_to_tid in
 121 * case of disconnect.
 122 */
 123const t_u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
 124
 125/* Map of TOS UP values to WMM AC */
 126static const mlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
 127    WMM_AC_BK,
 128    WMM_AC_BK,
 129    WMM_AC_BE,
 130    WMM_AC_VI,
 131    WMM_AC_VI,
 132    WMM_AC_VO,
 133    WMM_AC_VO
 134};
 135
 136raListTbl *wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid,
 137                                    t_u8 * ra_addr);
 138
 139/********************************************************
 140    Local Functions
 141********************************************************/
 142#ifdef DEBUG_LEVEL2
 143/**
 144 *  @brief Debug print function to display the priority parameters for a WMM AC
 145 *
 146 *  @param pac_param	Pointer to the AC parameters to display
 147 *
 148 *  @return		N/A
 149 */
 150static void
 151wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pac_param)
 152{
 153    const char *ac_str[] = { "BK", "BE", "VI", "VO" };
 154
 155    ENTER();
 156
 157    PRINTM(MINFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
 158           "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
 159           ac_str[wmm_aci_to_qidx_map[pac_param->aci_aifsn.aci]],
 160           pac_param->aci_aifsn.aci, pac_param->aci_aifsn.acm,
 161           pac_param->aci_aifsn.aifsn, pac_param->ecw.ecw_min,
 162           pac_param->ecw.ecw_max, wlan_le16_to_cpu(pac_param->tx_op_limit));
 163
 164    LEAVE();
 165}
 166
 167/** Print the WMM AC for debug purpose */
 168#define PRINTM_AC(pac_param) wlan_wmm_ac_debug_print(pac_param)
 169#else
 170/** Print the WMM AC for debug purpose */
 171#define PRINTM_AC(pac_param)
 172#endif
 173
 174/**
 175 *  @brief Allocate route address
 176 *
 177 *  @param pmadapter       Pointer to the mlan_adapter structure
 178 *  @param ra              Pointer to the route address
 179 *
 180 *  @return         ra_list
 181 */
 182static raListTbl *
 183wlan_wmm_allocate_ralist_node(pmlan_adapter pmadapter, t_u8 * ra)
 184{
 185    raListTbl *ra_list = MNULL;
 186
 187    ENTER();
 188
 189    if (pmadapter->callbacks.
 190        moal_malloc(pmadapter->pmoal_handle, sizeof(raListTbl), MLAN_MEM_DEF,
 191                    (t_u8 **) & ra_list)) {
 192        PRINTM(MERROR, "Fail to allocate ra_list\n");
 193        goto done;
 194    }
 195    util_init_list((pmlan_linked_list) ra_list);
 196    util_init_list_head((t_void *) pmadapter->pmoal_handle,
 197                        &ra_list->buf_head, MFALSE,
 198                        pmadapter->callbacks.moal_init_lock);
 199
 200    memcpy(pmadapter, ra_list->ra, ra, MLAN_MAC_ADDR_LENGTH);
 201
 202    ra_list->total_pkts = 0;
 203    ra_list->tx_pause = 0;
 204    PRINTM(MINFO, "RAList: Allocating buffers for TID %p\n", ra_list);
 205  done:
 206    LEAVE();
 207    return ra_list;
 208}
 209
 210/**
 211 * @brief Map ACs to TID
 212 *
 213 * @param priv             Pointer to the mlan_private driver data struct
 214 * @param queue_priority   Queue_priority structure
 215 *
 216 * @return 	   N/A
 217 */
 218static void
 219wlan_wmm_queue_priorities_tid(pmlan_private priv, t_u8 queue_priority[])
 220{
 221    int i;
 222
 223    ENTER();
 224
 225    for (i = 0; i < 4; ++i) {
 226        tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
 227        tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
 228    }
 229
 230    for (i = 0; i < MAX_NUM_TID; i++) {
 231        tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
 232    }
 233
 234    /* in case priorities have changed, force highest priority so next packet
 235       will check from top to re-establish the highest */
 236    util_scalar_write(priv->adapter->pmoal_handle,
 237                      &priv->wmm.highest_queued_prio,
 238                      HIGH_PRIO_TID,
 239                      priv->adapter->callbacks.moal_spin_lock,
 240                      priv->adapter->callbacks.moal_spin_unlock);
 241
 242    LEAVE();
 243}
 244
 245/**
 246 *  @brief Evaluate whether or not an AC is to be downgraded
 247 *
 248 *  @param priv     Pointer to the mlan_private driver data struct
 249 *  @param eval_ac  AC to evaluate for downgrading
 250 *
 251 *  @return WMM AC  The eval_ac traffic is to be sent on.
 252 */
 253static mlan_wmm_ac_e
 254wlan_wmm_eval_downgrade_ac(pmlan_private priv, mlan_wmm_ac_e eval_ac)
 255{
 256    int down_ac;
 257    mlan_wmm_ac_e ret_ac;
 258    WmmAcStatus_t *pac_status;
 259
 260    ENTER();
 261
 262    pac_status = &priv->wmm.ac_status[eval_ac];
 263
 264    if (pac_status->disabled == MFALSE) {
 265        LEAVE();
 266        /* Okay to use this AC, its enabled */
 267        return eval_ac;
 268    }
 269
 270    /* Setup a default return value of the lowest priority */
 271    ret_ac = WMM_AC_BK;
 272
 273    /*
 274     *  Find the highest AC that is enabled and does not require admission
 275     *    control.  The spec disallows downgrading to an AC, which is enabled
 276     *    due to a completed admission control.  Unadmitted traffic is not
 277     *    to be sent on an AC with admitted traffic.
 278     */
 279    for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
 280        pac_status = &priv->wmm.ac_status[down_ac];
 281
 282        if ((pac_status->disabled == MFALSE)
 283            && (pac_status->flow_required == MFALSE))
 284            /* AC is enabled and does not require admission control */
 285            ret_ac = (mlan_wmm_ac_e) down_ac;
 286    }
 287
 288    LEAVE();
 289    return ret_ac;
 290}
 291
 292/**
 293 *  @brief Convert the IP TOS field to an WMM AC Queue assignment
 294 *
 295 *  @param pmadapter A pointer to mlan_adapter structure
 296 *  @param tos       IP TOS field
 297 *
 298 *  @return     WMM AC Queue mapping of the IP TOS field
 299 */
 300static mlan_wmm_ac_e INLINE
 301wlan_wmm_convert_tos_to_ac(pmlan_adapter pmadapter, t_u32 tos)
 302{
 303    ENTER();
 304
 305    if (tos >= NELEMENTS(tos_to_ac)) {
 306        LEAVE();
 307        return WMM_AC_BE;
 308    }
 309
 310    LEAVE();
 311    return tos_to_ac[tos];
 312}
 313
 314/**
 315 *  @brief  Evaluate a given TID and downgrade it to a lower TID if the
 316 *          WMM Parameter IE received from the AP indicates that the AP
 317 *          is disabled (due to call admission control (ACM bit). Mapping
 318 * 			of TID to AC is taken care internally
 319 *
 320 *  @param priv		Pointer to the mlan_private data struct
 321 *  @param tid  	tid to evaluate for downgrading
 322 *
 323 *  @return       Same tid as input if downgrading not required or
 324 *                the tid the traffic for the given tid should be downgraded to
 325 */
 326static t_u8 INLINE
 327wlan_wmm_downgrade_tid(pmlan_private priv, t_u32 tid)
 328{
 329    mlan_wmm_ac_e ac_down;
 330    pmlan_adapter pmadapter = priv->adapter;
 331
 332    ENTER();
 333
 334    ac_down =
 335        priv->wmm.ac_down_graded_vals[wlan_wmm_convert_tos_to_ac(pmadapter,
 336                                                                 tid)];
 337    LEAVE();
 338    /*
 339     * Send the index to tid array, picking from the array will be
 340     * taken care by dequeuing function
 341     */
 342    if (tid == 1 || tid == 2)
 343        return ac_to_tid[ac_down][(tid + 1) % 2];
 344    else if (tid >= MAX_NUM_TID)
 345        return ac_to_tid[ac_down][0];
 346    else
 347        return ac_to_tid[ac_down][tid % 2];
 348}
 349
 350/**
 351 *  @brief Delete packets in RA node
 352 *
 353 *  @param priv			Pointer to the mlan_private driver data struct
 354 *  @param ra_list	    	Pointer to raListTbl
 355 *
 356 *  @return		N/A
 357 */
 358static INLINE void
 359wlan_wmm_del_pkts_in_ralist_node(pmlan_private priv, raListTbl * ra_list)
 360{
 361    pmlan_buffer pmbuf;
 362    pmlan_adapter pmadapter = priv->adapter;
 363
 364    ENTER();
 365    while ((pmbuf =
 366            (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
 367                                          &ra_list->buf_head, MNULL, MNULL))) {
 368        util_unlink_list(pmadapter->pmoal_handle, &ra_list->buf_head,
 369                         (pmlan_linked_list) pmbuf, MNULL, MNULL);
 370        wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
 371    }
 372    util_free_list_head((t_void *) pmadapter->pmoal_handle, &ra_list->buf_head,
 373                        pmadapter->callbacks.moal_free_lock);
 374
 375    LEAVE();
 376}
 377
 378/**
 379 *  @brief Delete packets in RA list
 380 *
 381 *  @param priv			Pointer to the mlan_private driver data struct
 382 *  @param ra_list_head	ra list header
 383 *
 384 *  @return		N/A
 385 */
 386static INLINE void
 387wlan_wmm_del_pkts_in_ralist(pmlan_private priv, mlan_list_head * ra_list_head)
 388{
 389    raListTbl *ra_list;
 390
 391    ENTER();
 392
 393    ra_list =
 394        (raListTbl *) util_peek_list(priv->adapter->pmoal_handle, ra_list_head,
 395                                     MNULL, MNULL);
 396
 397    while (ra_list && ra_list != (raListTbl *) ra_list_head) {
 398        wlan_wmm_del_pkts_in_ralist_node(priv, ra_list);
 399
 400        ra_list = ra_list->pnext;
 401    }
 402
 403    LEAVE();
 404}
 405
 406/**
 407 *  @brief Clean up the wmm queue
 408 *
 409 *  @param priv  Pointer to the mlan_private driver data struct
 410 *
 411 *  @return      N/A
 412 */
 413static void
 414wlan_wmm_cleanup_queues(pmlan_private priv)
 415{
 416    int i;
 417
 418    ENTER();
 419
 420    for (i = 0; i < MAX_NUM_TID; i++) {
 421        wlan_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].ra_list);
 422        priv->wmm.pkts_queued[i] = 0;
 423    }
 424    util_scalar_write(priv->adapter->pmoal_handle, &priv->wmm.tx_pkts_queued, 0,
 425                      MNULL, MNULL);
 426    util_scalar_write(priv->adapter->pmoal_handle,
 427                      &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
 428                      MNULL);
 429
 430    LEAVE();
 431}
 432
 433/**
 434 *  @brief Delete all route address from RA list
 435 *
 436 *  @param priv     Pointer to the mlan_private driver data struct
 437 *
 438 *  @return         N/A
 439 */
 440static void
 441wlan_wmm_delete_all_ralist(pmlan_private priv)
 442{
 443    raListTbl *ra_list;
 444    int i;
 445    pmlan_adapter pmadapter = priv->adapter;
 446
 447    ENTER();
 448
 449    for (i = 0; i < MAX_NUM_TID; ++i) {
 450        PRINTM(MINFO, "RAList: Freeing buffers for TID %d\n", i);
 451        while ((ra_list = (raListTbl *) util_peek_list(pmadapter->pmoal_handle,
 452                                                       &priv->wmm.
 453                                                       tid_tbl_ptr[i].ra_list,
 454                                                       MNULL, MNULL))) {
 455            util_unlink_list(pmadapter->pmoal_handle,
 456                             &priv->wmm.tid_tbl_ptr[i].ra_list,
 457                             (pmlan_linked_list) ra_list, MNULL, MNULL);
 458
 459            pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
 460                                            (t_u8 *) ra_list);
 461        }
 462
 463        util_init_list((pmlan_linked_list)
 464                       & priv->wmm.tid_tbl_ptr[i].ra_list);
 465        priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
 466    }
 467
 468    LEAVE();
 469}
 470
 471/**
 472 *   @brief Get queue RA pointer
 473 *
 474 *   @param priv     Pointer to the mlan_private driver data struct
 475 *   @param tid      TID
 476 *   @param ra_addr  Pointer to the route address
 477 *
 478 *   @return         ra_list
 479 */
 480static raListTbl *
 481wlan_wmm_get_queue_raptr(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
 482{
 483    raListTbl *ra_list;
 484#if defined(UAP_SUPPORT)
 485    t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 486#endif
 487
 488    ENTER();
 489    ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
 490    if (ra_list) {
 491        LEAVE();
 492        return ra_list;
 493    }
 494#if defined(UAP_SUPPORT)
 495    if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
 496        (0 != memcmp(priv->adapter, ra_addr, bcast_addr, sizeof(bcast_addr)))) {
 497        if (MNULL == wlan_get_station_entry(priv, ra_addr)) {
 498            PRINTM(MDATA, "Drop packets to unknown station\n");
 499            LEAVE();
 500            return MNULL;
 501        }
 502    }
 503#endif
 504    wlan_ralist_add(priv, ra_addr);
 505
 506    ra_list = wlan_wmm_get_ralist_node(priv, tid, ra_addr);
 507    LEAVE();
 508    return ra_list;
 509}
 510
 511#ifdef STA_SUPPORT
 512/**
 513 * 	@brief Sends wmmac host event
 514 *
 515 *  @param priv		Pointer to the mlan_private driver data struct
 516 *  @param typeStr	Type of host event
 517 *  @param srcAddr	Pointer to the source Address
 518 *  @param tid    	TID
 519 *  @param up		User priority
 520 *  @param status	Status code or Reason code
 521 *
 522 *  @return		N/A
 523 */
 524static void
 525wlan_send_wmmac_host_event(pmlan_private priv,
 526                           char *typeStr,
 527                           t_u8 * srcAddr, t_u8 tid, t_u8 up, t_u8 status)
 528{
 529    t_u8 event_buf[100];
 530    mlan_event *pevent;
 531    t_u8 *pOutBuf;
 532
 533    ENTER();
 534
 535    /* Format one of the following two output strings: ** -
 536       TSPEC:ADDTS_RSP:[<status code>]:TID=X:UP=Y ** - TSPEC:DELTS_RX:[<reason
 537       code>]:TID=X:UP=Y */
 538    pevent = (mlan_event *) event_buf;
 539    pOutBuf = pevent->event_buf;
 540
 541    memcpy(priv->adapter, pOutBuf, (t_u8 *) "TSPEC:", 6);
 542    pOutBuf += 6;
 543
 544    memcpy(priv->adapter, pOutBuf, (t_u8 *) typeStr, wlan_strlen(typeStr));
 545    pOutBuf += wlan_strlen(typeStr);
 546
 547    *pOutBuf++ = ':';
 548    *pOutBuf++ = '[';
 549
 550    if (status >= 100) {
 551        *pOutBuf++ = (status / 100) + '0';
 552        status = (status % 100);
 553    }
 554
 555    if (status >= 10) {
 556        *pOutBuf++ = (status / 10) + '0';
 557        status = (status % 10);
 558    }
 559
 560    *pOutBuf++ = status + '0';
 561
 562    memcpy(priv->adapter, pOutBuf, (t_u8 *) "]:TID", 5);
 563    pOutBuf += 5;
 564    *pOutBuf++ = tid + '0';
 565
 566    memcpy(priv->adapter, pOutBuf, (t_u8 *) ":UP", 3);
 567    pOutBuf += 3;
 568    *pOutBuf++ = up + '0';
 569
 570    *pOutBuf = '\0';
 571
 572    pevent->bss_index = priv->bss_index;
 573    pevent->event_id = MLAN_EVENT_ID_DRV_REPORT_STRING;
 574    pevent->event_len = wlan_strlen((const t_s8 *) (pevent->event_buf));
 575
 576    wlan_recv_event(priv, MLAN_EVENT_ID_DRV_REPORT_STRING, pevent);
 577    LEAVE();
 578}
 579#endif /* STA_SUPPORT */
 580
 581/**
 582 *  @brief This function gets the highest priority list pointer
 583 *
 584 *  @param pmadapter      A pointer to mlan_adapter
 585 *  @param priv           A pointer to mlan_private
 586 *  @param tid            A pointer to return tid
 587 *
 588 *  @return             raListTbl
 589 */
 590static raListTbl *
 591wlan_wmm_get_highest_priolist_ptr(pmlan_adapter pmadapter,
 592                                  pmlan_private * priv, int *tid)
 593{
 594    pmlan_private priv_tmp;
 595    raListTbl *ptr, *head;
 596    mlan_bssprio_node *bssprio_node, *bssprio_head;
 597    tid_tbl_t *tid_ptr;
 598    int i, j;
 599    int next_prio = 0;
 600    int next_tid = 0;
 601    ENTER();
 602
 603    PRINTM(MDAT_D, "POP\n");
 604    for (j = pmadapter->priv_num - 1; j >= 0; --j) {
 605        if (!(util_peek_list(pmadapter->pmoal_handle,
 606                             &pmadapter->bssprio_tbl[j].bssprio_head,
 607                             pmadapter->callbacks.moal_spin_lock,
 608                             pmadapter->callbacks.moal_spin_unlock)))
 609            continue;
 610
 611        if (pmadapter->bssprio_tbl[j].bssprio_cur == (mlan_bssprio_node *)
 612            & pmadapter->bssprio_tbl[j].bssprio_head) {
 613            pmadapter->bssprio_tbl[j].bssprio_cur =
 614                pmadapter->bssprio_tbl[j].bssprio_cur->pnext;
 615        }
 616
 617        bssprio_head = bssprio_node = pmadapter->bssprio_tbl[j].bssprio_cur;
 618
 619        do {
 620            priv_tmp = bssprio_node->priv;
 621
 622            if ((priv_tmp->port_ctrl_mode == MTRUE)
 623                && (priv_tmp->port_open == MFALSE)) {
 624                PRINTM(MINFO, "get_highest_prio_ptr(): "
 625                       "PORT_CLOSED Ignore pkts from BSS%d\n",
 626                       priv_tmp->bss_index);
 627                /* Ignore data pkts from a BSS if port is closed */
 628                goto next_intf;
 629            }
 630
 631            pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
 632                                                priv_tmp->wmm.ra_list_spinlock);
 633
 634            for (i = util_scalar_read(pmadapter->pmoal_handle,
 635                                      &priv_tmp->wmm.highest_queued_prio,
 636                                      MNULL, MNULL); i >= LOW_PRIO_TID; --i) {
 637
 638                tid_ptr = &(priv_tmp)->wmm.tid_tbl_ptr[tos_to_tid[i]];
 639                if (!util_peek_list
 640                    (pmadapter->pmoal_handle, &tid_ptr->ra_list, MNULL, MNULL))
 641                    continue;
 642
 643                /*
 644                 * Always choose the next ra we transmitted
 645                 * last time, this way we pick the ra's in
 646                 * round robin fashion.
 647                 */
 648                head = ptr = tid_ptr->ra_list_curr->pnext;
 649                if (ptr == (raListTbl *) & tid_ptr->ra_list)
 650                    head = ptr = ptr->pnext;
 651
 652                do {
 653                    if (!ptr->tx_pause &&
 654                        util_peek_list(pmadapter->pmoal_handle, &ptr->buf_head,
 655                                       MNULL, MNULL)) {
 656
 657                        /* Because WMM only support BK/BE/VI/VO, we have 8 tid
 658                           We should balance the traffic of the same AC */
 659                        if (i % 2)
 660                            next_prio = i - 1;
 661                        else
 662                            next_prio = i + 1;
 663                        next_tid = tos_to_tid[next_prio];
 664                        if (priv_tmp->wmm.pkts_queued[next_tid])
 665                            util_scalar_write(pmadapter->pmoal_handle,
 666                                              &priv_tmp->wmm.
 667                                              highest_queued_prio, next_prio,
 668                                              MNULL, MNULL);
 669                        else
 670                            /* if highest_queued_prio > i, set it to i */
 671                            util_scalar_conditional_write(pmadapter->
 672                                                          pmoal_handle,
 673                                                          &priv_tmp->wmm.
 674                                                          highest_queued_prio,
 675                                                          MLAN_SCALAR_COND_GREATER_THAN,
 676                                                          i, i, MNULL, MNULL);
 677                        *priv = priv_tmp;
 678                        *tid = tos_to_tid[i];
 679                        /* hold priv->ra_list_spinlock to maintain ptr */
 680                        PRINTM(MDAT_D, "get highest prio ptr %p, tid %d\n",
 681                               ptr, *tid);
 682                        LEAVE();
 683                        return ptr;
 684                    }
 685
 686                    if ((ptr = ptr->pnext) == (raListTbl *) & tid_ptr->ra_list)
 687                        ptr = ptr->pnext;
 688                } while (ptr != head);
 689            }
 690
 691            /* No packet at any TID for this priv.  Mark as such to skip
 692               checking TIDs for this priv (until pkt is added). */
 693            util_scalar_write(pmadapter->pmoal_handle,
 694                              &priv_tmp->wmm.highest_queued_prio,
 695                              NO_PKT_PRIO_TID, MNULL, MNULL);
 696
 697            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 698                                                  priv_tmp->wmm.
 699                                                  ra_list_spinlock);
 700
 701          next_intf:
 702            if ((bssprio_node = bssprio_node->pnext) == (mlan_bssprio_node *)
 703                & pmadapter->bssprio_tbl[j].bssprio_head)
 704                bssprio_node = bssprio_node->pnext;
 705        } while (bssprio_node != bssprio_head);
 706    }
 707
 708    LEAVE();
 709    return MNULL;
 710}
 711
 712/**
 713 *  @brief This function gets the number of packets in the Tx queue
 714 *
 715 *  @param priv         A pointer to mlan_private
 716 *  @param ptr          A pointer to RA list table
 717 *  @param maxBufSize   Maximum buffer size
 718 *
 719 *  @return             Packet count
 720 */
 721static int
 722wlan_num_pkts_in_txq(mlan_private * priv, raListTbl * ptr, int maxBufSize)
 723{
 724    int count = 0, total_size = 0;
 725    pmlan_buffer pmbuf;
 726
 727    ENTER();
 728
 729    for (pmbuf = (pmlan_buffer) ptr->buf_head.pnext;
 730         pmbuf != (pmlan_buffer) (&ptr->buf_head); pmbuf = pmbuf->pnext) {
 731
 732        total_size += pmbuf->data_len;
 733        if (total_size < maxBufSize)
 734            ++count;
 735        else
 736            break;
 737    }
 738
 739    LEAVE();
 740    return count;
 741}
 742
 743/**
 744 *  @brief This function sends a single packet
 745 *
 746 *  @param priv         A pointer to mlan_private
 747 *  @param ptr          A pointer to RA list table
 748 *  @param ptrindex     ptr's TID index
 749 *
 750 *  @return             N/A
 751 */
 752static void INLINE
 753wlan_send_single_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
 754{
 755    pmlan_buffer pmbuf;
 756    pmlan_buffer pmbuf_next;
 757    mlan_tx_param tx_param;
 758    pmlan_adapter pmadapter = priv->adapter;
 759    mlan_status status = MLAN_STATUS_SUCCESS;
 760
 761    ENTER();
 762
 763    if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
 764                                                  &ptr->buf_head,
 765                                                  MNULL, MNULL))) {
 766        PRINTM(MINFO, "Dequeuing the packet %p %p\n", ptr, pmbuf);
 767        priv->wmm.pkts_queued[ptrindex]--;
 768        util_scalar_decrement(pmadapter->pmoal_handle,
 769                              &priv->wmm.tx_pkts_queued, MNULL, MNULL);
 770        ptr->total_pkts--;
 771        pmbuf_next = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
 772                                                   &ptr->buf_head,
 773                                                   MNULL, MNULL);
 774        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 775                                              priv->wmm.ra_list_spinlock);
 776
 777        tx_param.next_pkt_len = ((pmbuf_next)
 778                                 ? pmbuf_next->data_len + sizeof(TxPD) : 0);
 779        status = wlan_process_tx(priv, pmbuf, &tx_param);
 780
 781        if (status == MLAN_STATUS_RESOURCE) {
 782            /** Queue the packet back at the head */
 783            PRINTM(MDAT_D, "Queuing pkt back to raList %p %p\n", ptr, pmbuf);
 784            pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
 785                                                priv->wmm.ra_list_spinlock);
 786
 787            if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
 788                pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 789                                                      priv->wmm.
 790                                                      ra_list_spinlock);
 791                wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
 792                LEAVE();
 793                return;
 794            }
 795            priv->wmm.pkts_queued[ptrindex]++;
 796            util_scalar_increment(pmadapter->pmoal_handle,
 797                                  &priv->wmm.tx_pkts_queued, MNULL, MNULL);
 798            util_enqueue_list_head(pmadapter->pmoal_handle, &ptr->buf_head,
 799                                   (pmlan_linked_list) pmbuf, MNULL, MNULL);
 800
 801            ptr->total_pkts++;
 802            pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
 803            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 804                                                  priv->wmm.ra_list_spinlock);
 805        } else {
 806            pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
 807                                                priv->wmm.ra_list_spinlock);
 808            if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
 809                priv->wmm.packets_out[ptrindex]++;
 810                priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
 811            }
 812            pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
 813                pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
 814            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 815                                                  priv->wmm.ra_list_spinlock);
 816        }
 817    } else {
 818        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 819                                              priv->wmm.ra_list_spinlock);
 820        PRINTM(MINFO, "Nothing to send\n");
 821    }
 822
 823    LEAVE();
 824}
 825
 826/**
 827 *  @brief This function checks if this mlan_buffer is already processed.
 828 *
 829 *  @param priv     A pointer to mlan_private
 830 *  @param ptr      A pointer to RA list table
 831 *
 832 *  @return 	    MTRUE or MFALSE
 833 */
 834static int INLINE
 835wlan_is_ptr_processed(mlan_private * priv, raListTbl * ptr)
 836{
 837    pmlan_buffer pmbuf;
 838
 839    if ((pmbuf = (pmlan_buffer) util_peek_list(priv->adapter->pmoal_handle,
 840                                               &ptr->buf_head, MNULL, MNULL))
 841        && (pmbuf->flags & MLAN_BUF_FLAG_REQUEUED_PKT))
 842        return MTRUE;
 843
 844    return MFALSE;
 845}
 846
 847/**
 848 *  @brief This function sends a single packet that has been processed
 849 *
 850 *  @param priv         A pointer to mlan_private
 851 *  @param ptr          A pointer to RA list table
 852 *  @param ptrindex     ptr's TID index
 853 *
 854 *  @return             N/A
 855 */
 856static void INLINE
 857wlan_send_processed_packet(pmlan_private priv, raListTbl * ptr, int ptrindex)
 858{
 859    pmlan_buffer pmbuf_next;
 860    mlan_tx_param tx_param;
 861    pmlan_buffer pmbuf;
 862    pmlan_adapter pmadapter = priv->adapter;
 863    mlan_status ret = MLAN_STATUS_FAILURE;
 864
 865    if ((pmbuf = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle,
 866                                                  &ptr->buf_head,
 867                                                  MNULL, MNULL))) {
 868        pmbuf_next =
 869            (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle,
 870                                          &ptr->buf_head, MNULL, MNULL);
 871        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 872                                              priv->wmm.ra_list_spinlock);
 873        tx_param.next_pkt_len =
 874            ((pmbuf_next) ? pmbuf_next->data_len + sizeof(TxPD) : 0);
 875        ret =
 876            wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, &tx_param);
 877        switch (ret) {
 878        case MLAN_STATUS_RESOURCE:
 879            PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
 880            pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
 881                                                priv->wmm.ra_list_spinlock);
 882
 883            if (!wlan_is_ralist_valid(priv, ptr, ptrindex)) {
 884                pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 885                                                      priv->wmm.
 886                                                      ra_list_spinlock);
 887                wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
 888                LEAVE();
 889                return;
 890            }
 891            util_enqueue_list_head(pmadapter->pmoal_handle,
 892                                   &ptr->buf_head,
 893                                   (pmlan_linked_list) pmbuf, MNULL, MNULL);
 894
 895            pmbuf->flags |= MLAN_BUF_FLAG_REQUEUED_PKT;
 896            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 897                                                  priv->wmm.ra_list_spinlock);
 898            break;
 899        case MLAN_STATUS_FAILURE:
 900            pmadapter->data_sent = MFALSE;
 901            PRINTM(MERROR, "Error: Failed to write data\n");
 902            pmadapter->dbg.num_tx_host_to_card_failure++;
 903            pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
 904            wlan_write_data_complete(pmadapter, pmbuf, ret);
 905            break;
 906        case MLAN_STATUS_PENDING:
 907            pmadapter->data_sent = MFALSE;
 908        default:
 909            break;
 910        }
 911        if (ret != MLAN_STATUS_RESOURCE) {
 912            pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
 913                                                priv->wmm.ra_list_spinlock);
 914            if (wlan_is_ralist_valid(priv, ptr, ptrindex)) {
 915                priv->wmm.packets_out[ptrindex]++;
 916                priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = ptr;
 917                ptr->total_pkts--;
 918            }
 919            pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur =
 920                pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext;
 921            priv->wmm.pkts_queued[ptrindex]--;
 922            util_scalar_decrement(pmadapter->pmoal_handle,
 923                                  &priv->wmm.tx_pkts_queued, MNULL, MNULL);
 924            pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 925                                                  priv->wmm.ra_list_spinlock);
 926        }
 927    } else {
 928        pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
 929                                              priv->wmm.ra_list_spinlock);
 930    }
 931}
 932
 933/**
 934 *  @brief This function dequeues a packet
 935 *
 936 *  @param pmadapter  A pointer to mlan_adapter
 937 *
 938 *  @return 	    MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 939 */
 940static int
 941wlan_dequeue_tx_packet(pmlan_adapter pmadapter)
 942{
 943    raListTbl *ptr;
 944    pmlan_private priv = MNULL;
 945    int ptrindex = 0;
 946    t_u8 ra[MLAN_MAC_ADDR_LENGTH];
 947    int tid_del = 0;
 948    int tid = 0;
 949
 950    ENTER();
 951
 952    if (!(ptr = wlan_wmm_get_highest_priolist_ptr(pmadapter, &priv, &ptrindex))) {
 953        LEAVE();
 954        return MLAN_STATUS_FAILURE;
 955    }
 956
 957    /* Note:- Spinlock is locked in wlan_wmm_get_highest_priolist_ptr when it
 958       returns a pointer (for the priv it returns), and is unlocked in
 959       wlan_send_processed_packet, wlan_send_single_packet or
 960       wlan_11n_aggregate_pkt.  The spinlock would be required for some parts
 961       of both of function.  But, the the bulk of these function will execute
 962       w/o spinlock.  Unlocking the spinlock inside these function will help
 963       us avoid taking the spinlock again, check to see if the ptr is still
 964       valid and then proceed. This is done purely to increase execution time.
 965     */
 966
 967    /* Note:- Also, anybody adding code which does not get into
 968       wlan_send_processed_packet, wlan_send_single_packet, or
 969       wlan_11n_aggregate_pkt should make sure ra_list_spinlock is freed.
 970       Otherwise there would be a lock up. */
 971
 972    tid = wlan_get_tid(priv->adapter, ptr);
 973    if (tid >= MAX_NUM_TID)
 974        tid = wlan_wmm_downgrade_tid(priv, tid);
 975
 976    if (wlan_is_ptr_processed(priv, ptr)) {
 977        wlan_send_processed_packet(priv, ptr, ptrindex);
 978        LEAVE();
 979        return MLAN_STATUS_SUCCESS;
 980    }
 981
 982    if (!ptr->is_11n_enabled || wlan_is_bastream_setup(priv, ptr, tid)
 983#ifdef STA_SUPPORT
 984        || ((priv->sec_info.ewpa_enabled == MFALSE) &&
 985            ((priv->sec_info.wpa_enabled
 986              || priv->sec_info.wpa2_enabled) &&
 987             priv->wpa_is_gtk_set == MFALSE))
 988        || priv->wps.session_enable
 989#endif /* STA_SUPPORT */
 990        ) {
 991        if (ptr->is_11n_enabled && wlan_is_bastream_setup(priv, ptr, tid)
 992            && wlan_is_amsdu_in_ampdu_allowed(priv, ptr, tid)
 993            && wlan_is_amsdu_allowed(priv, ptr, tid)
 994            && (wlan_num_pkts_in_txq(priv, ptr, pmadapter->tx_buf_size) >=
 995                MIN_NUM_AMSDU)) {
 996            wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
 997        } else
 998            wlan_send_single_packet(priv, ptr, ptrindex);
 999    } else {
1000        if (wlan_is_ampdu_allowed(priv, ptr, tid) &&
1001            (ptr->packet_count > ptr->ba_packet_threshold)) {
1002            if (wlan_is_bastream_avail(priv)) {
1003                PRINTM(MINFO, "BA setup threshold %d reached. tid=%d\n",
1004                       ptr->packet_count, tid);
1005                wlan_11n_create_txbastream_tbl(priv,
1006                                               ptr->ra, tid,
1007                                               BA_STREAM_SETUP_INPROGRESS);
1008                wlan_send_addba(priv, tid, ptr->ra);
1009            } else if (wlan_find_stream_to_delete(priv, ptr, tid, &tid_del, ra)) {
1010                PRINTM(MDAT_D, "tid_del=%d tid=%d\n", tid_del, tid);
1011                wlan_11n_create_txbastream_tbl(priv,
1012                                               ptr->ra, tid,
1013                                               BA_STREAM_SETUP_INPROGRESS);
1014                wlan_send_delba(priv, tid_del, ra, 1);
1015            }
1016        }
1017        if (wlan_is_amsdu_allowed(priv, ptr, tid) &&
1018            (wlan_num_pkts_in_txq(priv, ptr,
1019                                  pmadapter->tx_buf_size) >= MIN_NUM_AMSDU)) {
1020            wlan_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptrindex);
1021        } else {
1022            wlan_send_single_packet(priv, ptr, ptrindex);
1023        }
1024    }
1025
1026    LEAVE();
1027    return MLAN_STATUS_SUCCESS;
1028}
1029
1030/**
1031 *  @brief update tx_pause flag in ra_list
1032 *
1033 *  @param priv		  A pointer to mlan_private
1034 *  @param mac        peer mac address
1035 *  @param tx_pause   tx_pause flag (0/1)
1036 *
1037 *  @return           N/A
1038 */
1039t_void
1040wlan_updata_ralist_tx_pause(pmlan_private priv, t_u8 * mac, t_u8 tx_pause)
1041{
1042    raListTbl *ra_list;
1043    int i;
1044    pmlan_adapter pmadapter = priv->adapter;
1045    t_u32 pkt_cnt = 0;
1046    t_u32 tx_pkts_queued = 0;
1047    ENTER();
1048
1049    pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
1050                                        priv->wmm.ra_list_spinlock);
1051    for (i = 0; i < MAX_NUM_TID; ++i) {
1052        ra_list = wlan_wmm_get_ralist_node(priv, i, mac);
1053        if (ra_list) {
1054            pkt_cnt += ra_list->total_pkts;
1055            ra_list->tx_pause = tx_pause;
1056        }
1057    }
1058    if (pkt_cnt) {
1059        tx_pkts_queued = util_scalar_read(pmadapter->pmoal_handle,
1060                                          &priv->wmm.tx_pkts_queued, MNULL,
1061                                          MNULL);
1062        if (tx_pause)
1063            tx_pkts_queued -= pkt_cnt;
1064        else
1065            tx_pkts_queued += pkt_cnt;
1066        util_scalar_write(priv->adapter->pmoal_handle,
1067                          &priv->wmm.tx_pkts_queued, tx_pkts_queued, MNULL,
1068                          MNULL);
1069        util_scalar_write(priv->adapter->pmoal_handle,
1070                          &priv->wmm.highest_queued_prio, HIGH_PRIO_TID, MNULL,
1071                          MNULL);
1072    }
1073    pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1074                                          priv->wmm.ra_list_spinlock);
1075    LEAVE();
1076}
1077
1078#ifdef STA_SUPPORT
1079#endif /* STA_SUPPORT */
1080/********************************************************
1081    Global Functions
1082********************************************************/
1083
1084/**
1085 *  @brief Get the threshold value for BA setup using system time.
1086 *
1087 *  @param pmadapter       Pointer to the mlan_adapter structure
1088 *
1089 *  @return         threshold value.
1090 */
1091t_u8
1092wlan_get_random_ba_threshold(pmlan_adapter pmadapter)
1093{
1094    t_u32 sec, usec;
1095    t_u8 ba_threshold = 0;
1096
1097    ENTER();
1098
1099    /* setup ba_packet_threshold here random number between
1100       [BA_SETUP_PACKET_OFFSET,
1101       BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1] */
1102
1103#define BA_SETUP_MAX_PACKET_THRESHOLD   16
1104#define BA_SETUP_PACKET_OFFSET          16
1105
1106    pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
1107                                              &usec);
1108    sec = (sec & 0xFFFF) + (sec >> 16);
1109    usec = (usec & 0xFFFF) + (usec >> 16);
1110
1111    ba_threshold =
1112        (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD) +
1113        BA_SETUP_PACKET_OFFSET;
1114    PRINTM(MINFO, "setup BA after %d packets\n", ba_threshold);
1115
1116    LEAVE();
1117    return ba_threshold;
1118}
1119
1120/**
1121 *  @brief  This function cleans Tx/Rx queues
1122 *
1123 *  @param priv		A pointer to mlan_private
1124 *
1125 *  @return		N/A
1126 */
1127t_void
1128wlan_clean_txrx(pmlan_private priv)
1129{
1130    mlan_adapter *pmadapter = priv->adapter;
1131    t_u8 i = 0;
1132
1133    ENTER();
1134
1135    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1136        wlan_cleanup_bypass_txq(pmadapter);
1137    }
1138
1139    wlan_11n_cleanup_reorder_tbl(priv);
1140
1141    pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
1142                                        priv->wmm.ra_list_spinlock);
1143
1144    wlan_wmm_cleanup_queues(priv);
1145    wlan_11n_deleteall_txbastream_tbl(priv);
1146#ifdef SDIO_MULTI_PORT_TX_AGGR
1147    MP_TX_AGGR_BUF_RESET(priv->adapter);
1148#endif
1149#ifdef SDIO_MULTI_PORT_RX_AGGR
1150    MP_RX_AGGR_BUF_RESET(priv->adapter);
1151#endif
1152    wlan_wmm_delete_all_ralist(priv);
1153    memcpy(pmadapter, tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
1154    for (i = 0; i < MAX_NUM_TID; i++) {
1155        tos_to_tid_inv[tos_to_tid[i]] = (t_u8) i;
1156    }
1157#if defined(UAP_SUPPORT)
1158    priv->num_drop_pkts = 0;
1159#endif
1160    pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
1161                                          priv->wmm.ra_list_spinlock);
1162
1163    LEAVE();
1164}
1165
1166/**
1167 *  @brief Set the WMM queue priorities to their default values
1168 *
1169 *  @param priv     Pointer to the mlan_private driver data struct
1170 *
1171 *  @return         N/A
1172 */
1173void
1174wlan_wmm_default_queue_priorities(pmlan_private priv)
1175{
1176    ENTER();
1177
1178    /* Default queue priorities: VO->VI->BE->BK */
1179    priv->wmm.queue_priority[0] = WMM_AC_VO;
1180    priv->wmm.queue_priority[1] = WMM_AC_VI;
1181    priv->wmm.queue_priority[2] = WMM_AC_BE;
1182    priv->wmm.queue_priority[3] = WMM_AC_BK;
1183
1184    LEAVE();
1185}
1186
1187/**
1188 *  @brief Initialize WMM priority queues
1189 *
1190 *  @param priv     Pointer to the mlan_private driver data struct
1191 *  @param pwmm_ie  Pointer to the IEEEtypes_WmmParameter_t data struct
1192 *
1193 *  @return         N/A
1194 */
1195void
1196wlan_wmm_setup_queue_priorities(pmlan_private priv,
1197                                IEEEtypes_WmmParameter_t * pwmm_ie)
1198{
1199    t_u16 cw_min, avg_back_off, tmp[4];
1200    t_u32 i, j, num_ac;
1201    t_u8 ac_idx;
1202
1203    ENTER();
1204
1205    if (!pwmm_ie || priv->wmm_enabled == MFALSE) {
1206        /* WMM is not enabled, just set the defaults and return */
1207        wlan_wmm_default_queue_priorities(priv);
1208        LEAVE();
1209        return;
1210    }
1211
1212    HEXDUMP("WMM: setup_queue_priorities: param IE",
1213            (t_u8 *) pwmm_ie, sizeof(IEEEtypes_WmmParameter_t));
1214
1215    PRINTM(MINFO, "WMM Parameter IE: version=%d, "
1216           "qos_info Parameter Set Count=%d, Reserved=%#x\n",
1217           pwmm_ie->vend_hdr.version, pwmm_ie->qos_info.para_set_count,
1218           pwmm_ie->reserved);
1219
1220    for (num_ac = 0; num_ac < NELEMENTS(pwmm_ie->ac_params); num_ac++) {
1221        cw_min = (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_min) - 1;
1222        avg_back_off
1223            = (cw_min >> 1) + pwmm_ie->ac_params[num_ac].aci_aifsn.aifsn;
1224
1225        ac_idx = wmm_aci_to_qidx_map[pwmm_ie->ac_params[num_ac].aci_aifsn.aci];
1226        priv->wmm.queue_priority[ac_idx] = ac_idx;
1227        tmp[ac_idx] = avg_back_off;
1228
1229        PRINTM(MCMND, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
1230               (1 << pwmm_ie->ac_params[num_ac].ecw.ecw_max) - 1,
1231               cw_min, avg_back_off);
1232        PRINTM_AC(&pwmm_ie->ac_params[num_ac]);
1233    }
1234
1235    HEXDUMP("WMM: avg_back_off", (t_u8 *) tmp, sizeof(tmp));
1236    HEXDUMP("WMM: queue_priority", priv->wmm.queue_priority,
1237            sizeof(priv->wmm.queue_priority));
1238
1239    /* Bubble sort */
1240    for (i = 0; i < num_ac; i++) {
1241        for (j = 1; j < num_ac - i; j++) {
1242            if (tmp[j - 1] > tmp[j]) {
1243                SWAP_U16(tmp[j - 1], tmp[j]);
1244                SWAP_U8(priv->wmm.queue_priority[j - 1],
1245                        priv->wmm.queue_priority[j]);
1246            } else if (tmp[j - 1] == tmp[j]) {
1247                if (priv->wmm.queue_priority[j - 1]
1248                    < priv->wmm.queue_priority[j]) {
1249                    SWAP_U8(priv->wmm.queue_priority[j - 1],
1250                            priv->wmm.queue_priority[j]);
1251                }
1252            }
1253        }
1254    }
1255
1256    wlan_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority);
1257
1258    HEXDUMP("WMM: avg_back_off, sort", (t_u8 *) tmp, sizeof(tmp));
1259    DBG_HEXDUMP(MCMD_D, "WMM: queue_priority, sort", priv->wmm.queue_priority,
1260                sizeof(priv->wmm.queue_priority));
1261    LEAVE();
1262}
1263
1264/**
1265 *  @brief Downgrade WMM priority queue
1266 *
1267 *  @param priv     Pointer to the mlan_private driver data struct
1268 *
1269 *  @return         N/A
1270 */
1271void
1272wlan_wmm_setup_ac_downgrade(pmlan_private priv)
1273{
1274    int ac_val;
1275
1276    ENTER();
1277
1278    PRINTM(MINFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
1279
1280    if (priv->wmm_enabled == MFALSE) {
1281        /* WMM is not enabled, default priorities */
1282        for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
1283            priv->wmm.ac_down_graded_vals[ac_val] = (mlan_wmm_ac_e) ac_val;
1284        }
1285    } else {
1286        for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
1287            priv->wmm.ac_down_graded_vals[ac_val]
1288                = wlan_wmm_eval_downgrade_ac(priv, (mlan_wmm_ac_e) ac_val);
1289            PRINTM(MINFO, "WMM: AC PRIO %d maps to %d\n",
1290                   ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
1291        }
1292    }
1293
1294    LEAVE();
1295}
1296
1297/**
1298 *  @brief  Allocate and add a RA list for all TIDs with the given RA
1299 *
1300 *  @param priv  Pointer to the mlan_private driver data struct
1301 *  @param ra	 Address of the receiver STA (AP in case of infra)
1302 *
1303 *  @return      N/A
1304 */
1305void
1306wlan_ralist_add(mlan_private * priv, t_u8 * ra)
1307{
1308    int i;
1309    raListTbl *ra_list;
1310    pmlan_adapter pmadapter = priv->adapter;
1311
1312    ENTER();
1313
1314    for (i = 0; i < MAX_NUM_TID; ++i) {
1315        ra_list = wlan_wmm_allocate_ralist_node(pmadapter, ra);
1316        PRINTM(MINFO, "Creating RA List %p for tid %d\n", ra_list, i);
1317        if (!ra_list)
1318            break;
1319        ra_list->max_amsdu = 0;
1320        if (queuing_ra_based(priv)) {
1321            ra_list->is_11n_enabled = wlan_is_11n_enabled(priv, ra);
1322            if (ra_list->is_11n_enabled)
1323                ra_list->max_amsdu = get_station_max_amsdu_size(priv, ra);
1324            ra_list->tx_pause = wlan_is_tx_pause(priv, ra);
1325        } else {
1326            ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
1327            if (ra_list->is_11n_enabled)
1328                ra_list->max_amsdu = priv->max_amsdu;
1329        }
1330
1331        PRINTM(MDATA, "ralist %p: is_11n_enabled=%d max_amsdu=%d\n",
1332               ra_list, ra_list->is_11n_enabled, ra_list->max_amsdu);
1333
1334        if (ra_list->is_11n_enabled) {
1335            ra_list->packet_count = 0;
1336            ra_list->ba_packet_threshold =
1337                wlan_get_random_ba_threshold(pmadapter);
1338        }
1339
1340        util_enqueue_list_tail(pmadapter->pmoal_handle,
1341                               &priv->wmm.tid_tbl_ptr[i].ra_list,
1342                               (pmlan_linked_list) ra_list, MNULL, MNULL);
1343
1344        if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
1345            priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
1346    }
1347
1348    LEAVE();
1349}
1350
1351/**
1352 *  @brief Initialize the WMM state information and the WMM data path queues.
1353 *
1354 *  @param pmadapter  Pointer to the mlan_adapter data structure
1355 *
1356 *  @return         N/A
1357 */
1358t_void
1359wlan_wmm_init(pmlan_adapter pmadapter)
1360{
1361    int i, j;
1362    pmlan_private priv;
1363
1364    ENTER();
1365
1366    for (j = 0; j < pmadapter->priv_num; ++j) {
1367        if ((priv = pmadapter->priv[j])) {
1368            for (i = 0; i < MAX_NUM_TID; ++i) {
1369                priv->aggr_prio_tbl[i].amsdu = BA_STREAM_NOT_ALLOWED;
1370#ifdef WIFI_DIRECT_SUPPORT
1371                if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
1372                    priv->aggr_prio_tbl[i].ampdu_ap =
1373                        priv->aggr_prio_tbl[i].ampdu_user =
1374                        BA_STREAM_NOT_ALLOWED;
1375                else
1376#endif
1377                    priv->aggr_prio_tbl[i].ampdu_ap =
1378                        priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
1379                priv->wmm.pkts_queued[i] = 0;
1380                priv->wmm.tid_tbl_ptr[i].ra_list_curr = MNULL;
1381            }
1382
1383            priv->aggr_prio_tbl[6].ampdu_ap
1384                = priv->aggr_prio_tbl[6].ampdu_user = BA_STREAM_NOT_ALLOWED;
1385
1386            priv->aggr_prio_tbl[7].ampdu_ap
1387                = priv->aggr_prio_tbl[7].ampdu_user = BA_STREAM_NOT_ALLOWED;
1388
1389            priv->add_ba_param.timeout = MLAN_DEFAULT_BLOCK_ACK_TIMEOUT;
1390#ifdef STA_SUPPORT
1391            if (priv->bss_type == MLAN_BSS_TYPE_STA) {
1392                priv->add_ba_param.tx_win_size = MLAN_STA_AMPDU_DEF_TXWINSIZE;
1393                priv->add_ba_param.rx_win_size = MLAN_STA_AMPDU_DEF_RXWINSIZE;
1394            }
1395#endif
1396#ifdef UAP_SUPPORT
1397            if (priv->bss_type == MLAN_BSS_TYPE_UAP
1398#ifdef WIFI_DIRECT_SUPPORT
1399                || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
1400#endif
1401                ) {
1402                priv->add_ba_param.tx_win_size = MLAN_UAP_AMPDU_DEF_TXWINSIZE;
1403                priv->add_ba_param.rx_win_size = MLAN_UAP_AMPDU_DEF_RXWINSIZE;
1404            }
1405#endif
1406            priv->add_ba_param.tx_amsdu = MTRUE;
1407            priv->add_ba_param.rx_amsdu = MTRUE;
1408            memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
1409            wlan_wmm_default_queue_priorities(priv);
1410        }
1411    }
1412
1413    LEAVE();
1414}
1415
1416/**
1417 *  @brief Setup the queue priorities and downgrade any queues as required
1418 *         by the WMM info.  Setups default values if WMM is not active
1419 *         for this association.
1420 *
1421 *  @param priv     Pointer to the mlan_private driver data struct
1422 *
1423 *  @return         N/A
1424 */
1425void
1426wlan_wmm_setup_queues(pmlan_private priv)
1427{
1428    ENTER();
1429    wlan_wmm_setup_queue_priorities(priv, MNULL);
1430    wlan_wmm_setup_ac_downgrade(priv);
1431    LEAVE();
1432}
1433
1434#ifdef STA_SUPPORT
1435/**
1436 *  @brief  Send a command to firmware to retrieve the current WMM status
1437 *
1438 *  @param priv     Pointer to the mlan_private driver data struct
1439 *
1440 *  @return         MLAN_STATUS_SUCCESS; MLAN_STATUS_FAILURE
1441 */
1442mlan_status
1443wlan_cmd_wmm_status_change(pmlan_private priv)
1444{
1445    mlan_status ret = MLAN_STATUS_SUCCESS;
1446
1447    ENTER();
1448
1449    ret = wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0, MNULL);
1450    LEAVE();
1451    return ret;
1452}
1453#endif
1454
1455/**
1456 *  @brief Check if wmm TX queue is empty
1457 *
1458 *  @param pmadapter  Pointer to the mlan_adapter driver data struct
1459 *
1460 *  @return         MFALSE if not empty; MTRUE if empty
1461 */
1462int
1463wlan_wmm_lists_empty(pmlan_adapter pmadapter)
1464{
1465    int j;
1466    pmlan_private priv;
1467
1468    ENTER();
1469
1470    for (j = 0; j < pmadapter->priv_num; ++j) {
1471        if ((priv = pmadapter->priv[j])) {
1472            if ((priv->port_ctrl_mode == MTRUE) && (priv->port_open == MFALSE)) {
1473                PRINTM(MINFO,
1474                       "wmm_lists_empty: PORT_CLOSED Ignore pkts from BSS%d\n",
1475                       j);
1476                continue;
1477            }
1478
1479            if (util_scalar_read(pmadapter->pmoal_handle,
1480                                 &priv->wmm.tx_pkts_queued,
1481                                 pmadapter->callbacks.moal_spin_lock,
1482                                 pmadapter->callbacks.moal_spin_unlock)) {
1483                LEAVE();
1484                return MFALSE;
1485            }
1486        }
1487    }
1488
1489    LEAVE();
1490    return MTRUE;
1491}
1492
1493/**
1494 *   @brief Get ralist node
1495 *
1496 *   @param priv     Pointer to the mlan_private driver data struct
1497 *   @param tid      TID
1498 *   @param ra_addr  Pointer to the route address
1499 *
1500 *   @return         ra_list or MNULL
1501 */
1502raListTbl *
1503wlan_wmm_get_ralist_node(pmlan_private priv, t_u8 tid, t_u8 * ra_addr)
1504{
1505    raListTbl *ra_list;
1506    ENTER();
1507    ra_list =
1508        (raListTbl *) util_peek_list(priv->adapter->pmoal_handle,
1509                                     &priv->wmm.tid_tbl_ptr[tid].ra_list, MNULL,
1510                                     MNULL);
1511    while (ra_list && (ra_list != (raListTbl *)
1512                       & priv->wmm.tid_tbl_ptr[tid].ra_list)) {
1513        if (!memcmp(priv->adapter, ra_list->ra, ra_addr, MLAN_MAC_ADDR_LENGTH)) {
1514            LEAVE();
1515            return ra_lis

Large files files are truncated, but you can click here to view the full file