linux/drivers/staging/rtl8192e/rtl819x_TSProc.c
<<
>>
Prefs
   1/******************************************************************************
   2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
   3 *
   4 * This program is distributed in the hope that it will be useful, but WITHOUT
   5 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   6 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   7 * more details.
   8 *
   9 * The full GNU General Public License is included in this distribution in the
  10 * file called LICENSE.
  11 *
  12 * Contact Information:
  13 * wlanfae <wlanfae@realtek.com>
  14******************************************************************************/
  15#include "rtllib.h"
  16#include <linux/etherdevice.h>
  17#include "rtl819x_TS.h"
  18
  19static void TsSetupTimeOut(unsigned long data)
  20{
  21}
  22
  23static void TsInactTimeout(unsigned long data)
  24{
  25}
  26
  27static void RxPktPendingTimeout(unsigned long data)
  28{
  29        struct rx_ts_record *pRxTs = (struct rx_ts_record *)data;
  30        struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device,
  31                                                  RxTsRecord[pRxTs->num]);
  32
  33        struct rx_reorder_entry *pReorderEntry = NULL;
  34
  35        unsigned long flags = 0;
  36        u8 index = 0;
  37        bool bPktInBuf = false;
  38
  39        spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
  40        if (pRxTs->RxTimeoutIndicateSeq != 0xffff) {
  41                while (!list_empty(&pRxTs->RxPendingPktList)) {
  42                        pReorderEntry = (struct rx_reorder_entry *)
  43                                        list_entry(pRxTs->RxPendingPktList.prev,
  44                                        struct rx_reorder_entry, List);
  45                        if (index == 0)
  46                                pRxTs->RxIndicateSeq = pReorderEntry->SeqNum;
  47
  48                        if (SN_LESS(pReorderEntry->SeqNum,
  49                                    pRxTs->RxIndicateSeq) ||
  50                            SN_EQUAL(pReorderEntry->SeqNum,
  51                                     pRxTs->RxIndicateSeq)) {
  52                                list_del_init(&pReorderEntry->List);
  53
  54                                if (SN_EQUAL(pReorderEntry->SeqNum,
  55                                    pRxTs->RxIndicateSeq))
  56                                        pRxTs->RxIndicateSeq =
  57                                              (pRxTs->RxIndicateSeq + 1) % 4096;
  58
  59                                netdev_dbg(ieee->dev,
  60                                           "%s(): Indicate SeqNum: %d\n",
  61                                           __func__, pReorderEntry->SeqNum);
  62                                ieee->stats_IndicateArray[index] =
  63                                                         pReorderEntry->prxb;
  64                                index++;
  65
  66                                list_add_tail(&pReorderEntry->List,
  67                                              &ieee->RxReorder_Unused_List);
  68                        } else {
  69                                bPktInBuf = true;
  70                                break;
  71                        }
  72                }
  73        }
  74
  75        if (index > 0) {
  76                pRxTs->RxTimeoutIndicateSeq = 0xffff;
  77
  78                if (index > REORDER_WIN_SIZE) {
  79                        netdev_warn(ieee->dev,
  80                                    "%s(): Rx Reorder struct buffer full\n",
  81                                    __func__);
  82                        spin_unlock_irqrestore(&(ieee->reorder_spinlock),
  83                                               flags);
  84                        return;
  85                }
  86                rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index);
  87                bPktInBuf = false;
  88        }
  89
  90        if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) {
  91                pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq;
  92                mod_timer(&pRxTs->RxPktPendingTimer,  jiffies +
  93                          msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime)
  94                          );
  95        }
  96        spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
  97}
  98
  99static void TsAddBaProcess(unsigned long data)
 100{
 101        struct tx_ts_record *pTxTs = (struct tx_ts_record *)data;
 102        u8 num = pTxTs->num;
 103        struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
 104                                     TxTsRecord[num]);
 105
 106        TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
 107        netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
 108}
 109
 110static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
 111{
 112        eth_zero_addr(pTsCommonInfo->Addr);
 113        memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body));
 114        memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM);
 115        pTsCommonInfo->TClasProc = 0;
 116        pTsCommonInfo->TClasNum = 0;
 117}
 118
 119static void ResetTxTsEntry(struct tx_ts_record *pTS)
 120{
 121        ResetTsCommonInfo(&pTS->TsCommonInfo);
 122        pTS->TxCurSeq = 0;
 123        pTS->bAddBaReqInProgress = false;
 124        pTS->bAddBaReqDelayed = false;
 125        pTS->bUsingBa = false;
 126        pTS->bDisable_AddBa = false;
 127        ResetBaEntry(&pTS->TxAdmittedBARecord);
 128        ResetBaEntry(&pTS->TxPendingBARecord);
 129}
 130
 131static void ResetRxTsEntry(struct rx_ts_record *pTS)
 132{
 133        ResetTsCommonInfo(&pTS->TsCommonInfo);
 134        pTS->RxIndicateSeq = 0xffff;
 135        pTS->RxTimeoutIndicateSeq = 0xffff;
 136        ResetBaEntry(&pTS->RxAdmittedBARecord);
 137}
 138
 139void TSInitialize(struct rtllib_device *ieee)
 140{
 141        struct tx_ts_record *pTxTS  = ieee->TxTsRecord;
 142        struct rx_ts_record *pRxTS  = ieee->RxTsRecord;
 143        struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry;
 144        u8                              count = 0;
 145
 146        netdev_vdbg(ieee->dev, "%s()\n", __func__);
 147        INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List);
 148        INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List);
 149        INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List);
 150
 151        for (count = 0; count < TOTAL_TS_NUM; count++) {
 152                pTxTS->num = count;
 153                setup_timer(&pTxTS->TsCommonInfo.SetupTimer,
 154                            TsSetupTimeOut,
 155                            (unsigned long) pTxTS);
 156
 157                setup_timer(&pTxTS->TsCommonInfo.InactTimer,
 158                            TsInactTimeout,
 159                            (unsigned long) pTxTS);
 160
 161                setup_timer(&pTxTS->TsAddBaTimer,
 162                            TsAddBaProcess,
 163                            (unsigned long) pTxTS);
 164
 165                setup_timer(&pTxTS->TxPendingBARecord.Timer,
 166                            BaSetupTimeOut,
 167                            (unsigned long) pTxTS);
 168                setup_timer(&pTxTS->TxAdmittedBARecord.Timer,
 169                            TxBaInactTimeout,
 170                            (unsigned long) pTxTS);
 171
 172                ResetTxTsEntry(pTxTS);
 173                list_add_tail(&pTxTS->TsCommonInfo.List,
 174                                &ieee->Tx_TS_Unused_List);
 175                pTxTS++;
 176        }
 177
 178        INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
 179        INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
 180        INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
 181        for (count = 0; count < TOTAL_TS_NUM; count++) {
 182                pRxTS->num = count;
 183                INIT_LIST_HEAD(&pRxTS->RxPendingPktList);
 184
 185                setup_timer(&pRxTS->TsCommonInfo.SetupTimer,
 186                            TsSetupTimeOut,
 187                            (unsigned long) pRxTS);
 188
 189                setup_timer(&pRxTS->TsCommonInfo.InactTimer,
 190                            TsInactTimeout,
 191                            (unsigned long) pRxTS);
 192
 193                setup_timer(&pRxTS->RxAdmittedBARecord.Timer,
 194                            RxBaInactTimeout,
 195                            (unsigned long) pRxTS);
 196
 197                setup_timer(&pRxTS->RxPktPendingTimer,
 198                            RxPktPendingTimeout,
 199                            (unsigned long) pRxTS);
 200
 201                ResetRxTsEntry(pRxTS);
 202                list_add_tail(&pRxTS->TsCommonInfo.List,
 203                              &ieee->Rx_TS_Unused_List);
 204                pRxTS++;
 205        }
 206        INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
 207        for (count = 0; count < REORDER_ENTRY_NUM; count++) {
 208                list_add_tail(&pRxReorderEntry->List,
 209                              &ieee->RxReorder_Unused_List);
 210                if (count == (REORDER_ENTRY_NUM-1))
 211                        break;
 212                pRxReorderEntry = &ieee->RxReorderEntry[count+1];
 213        }
 214
 215}
 216
 217static void AdmitTS(struct rtllib_device *ieee,
 218                    struct ts_common_info *pTsCommonInfo, u32 InactTime)
 219{
 220        del_timer_sync(&pTsCommonInfo->SetupTimer);
 221        del_timer_sync(&pTsCommonInfo->InactTimer);
 222
 223        if (InactTime != 0)
 224                mod_timer(&pTsCommonInfo->InactTimer, jiffies +
 225                          msecs_to_jiffies(InactTime));
 226}
 227
 228static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
 229                                                  u8 *Addr, u8 TID,
 230                                                  enum tr_select TxRxSelect)
 231{
 232        u8      dir;
 233        bool    search_dir[4] = {0};
 234        struct list_head *psearch_list;
 235        struct ts_common_info *pRet = NULL;
 236
 237        if (ieee->iw_mode == IW_MODE_MASTER) {
 238                if (TxRxSelect == TX_DIR) {
 239                        search_dir[DIR_DOWN] = true;
 240                        search_dir[DIR_BI_DIR] = true;
 241                } else {
 242                        search_dir[DIR_UP] = true;
 243                        search_dir[DIR_BI_DIR] = true;
 244                }
 245        } else if (ieee->iw_mode == IW_MODE_ADHOC) {
 246                if (TxRxSelect == TX_DIR)
 247                        search_dir[DIR_UP] = true;
 248                else
 249                        search_dir[DIR_DOWN] = true;
 250        } else {
 251                if (TxRxSelect == TX_DIR) {
 252                        search_dir[DIR_UP] = true;
 253                        search_dir[DIR_BI_DIR] = true;
 254                        search_dir[DIR_DIRECT] = true;
 255                } else {
 256                        search_dir[DIR_DOWN] = true;
 257                        search_dir[DIR_BI_DIR] = true;
 258                        search_dir[DIR_DIRECT] = true;
 259                }
 260        }
 261
 262        if (TxRxSelect == TX_DIR)
 263                psearch_list = &ieee->Tx_TS_Admit_List;
 264        else
 265                psearch_list = &ieee->Rx_TS_Admit_List;
 266
 267        for (dir = 0; dir <= DIR_BI_DIR; dir++) {
 268                if (!search_dir[dir])
 269                        continue;
 270                list_for_each_entry(pRet, psearch_list, List) {
 271                        if (memcmp(pRet->Addr, Addr, 6) == 0 &&
 272                            pRet->TSpec.f.TSInfo.field.ucTSID == TID &&
 273                            pRet->TSpec.f.TSInfo.field.ucDirection == dir)
 274                                break;
 275
 276                }
 277                if (&pRet->List  != psearch_list)
 278                        break;
 279        }
 280
 281        if (pRet && &pRet->List  != psearch_list)
 282                return pRet;
 283        return NULL;
 284}
 285
 286static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr,
 287                        union tspec_body *pTSPEC, union qos_tclas *pTCLAS,
 288                        u8 TCLAS_Num, u8 TCLAS_Proc)
 289{
 290        u8      count;
 291
 292        if (pTsCommonInfo == NULL)
 293                return;
 294
 295        memcpy(pTsCommonInfo->Addr, Addr, 6);
 296
 297        if (pTSPEC != NULL)
 298                memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC,
 299                        sizeof(union tspec_body));
 300
 301        for (count = 0; count < TCLAS_Num; count++)
 302                memcpy((u8 *)(&(pTsCommonInfo->TClass[count])),
 303                       (u8 *)pTCLAS, sizeof(union qos_tclas));
 304
 305        pTsCommonInfo->TClasProc = TCLAS_Proc;
 306        pTsCommonInfo->TClasNum = TCLAS_Num;
 307}
 308
 309bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS,
 310           u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
 311{
 312        u8      UP = 0;
 313        union tspec_body TSpec;
 314        union qos_tsinfo *pTSInfo = &TSpec.f.TSInfo;
 315        struct list_head *pUnusedList;
 316        struct list_head *pAddmitList;
 317        enum direction_value Dir;
 318
 319        if (is_multicast_ether_addr(Addr)) {
 320                netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n");
 321                return false;
 322        }
 323        if (ieee->current_network.qos_data.supported == 0) {
 324                UP = 0;
 325        } else {
 326                if (!IsACValid(TID)) {
 327                        netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n",
 328                                    __func__, TID);
 329                        return false;
 330                }
 331
 332                switch (TID) {
 333                case 0:
 334                case 3:
 335                        UP = 0;
 336                        break;
 337                case 1:
 338                case 2:
 339                        UP = 2;
 340                        break;
 341                case 4:
 342                case 5:
 343                        UP = 5;
 344                        break;
 345                case 6:
 346                case 7:
 347                        UP = 7;
 348                        break;
 349                }
 350        }
 351
 352        *ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect);
 353        if (*ppTS != NULL)
 354                return true;
 355
 356        if (!bAddNewTs) {
 357                netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP);
 358                return false;
 359        }
 360
 361        pUnusedList = (TxRxSelect == TX_DIR) ?
 362                                (&ieee->Tx_TS_Unused_List) :
 363                                (&ieee->Rx_TS_Unused_List);
 364
 365        pAddmitList = (TxRxSelect == TX_DIR) ?
 366                                (&ieee->Tx_TS_Admit_List) :
 367                                (&ieee->Rx_TS_Admit_List);
 368
 369        Dir = (ieee->iw_mode == IW_MODE_MASTER) ?
 370                                ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) :
 371                                ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
 372
 373        if (!list_empty(pUnusedList)) {
 374                (*ppTS) = list_entry(pUnusedList->next,
 375                          struct ts_common_info, List);
 376                list_del_init(&(*ppTS)->List);
 377                if (TxRxSelect == TX_DIR) {
 378                        struct tx_ts_record *tmp =
 379                                container_of(*ppTS,
 380                                struct tx_ts_record,
 381                                TsCommonInfo);
 382                        ResetTxTsEntry(tmp);
 383                } else {
 384                        struct rx_ts_record *tmp =
 385                                 container_of(*ppTS,
 386                                 struct rx_ts_record,
 387                                 TsCommonInfo);
 388                        ResetRxTsEntry(tmp);
 389                }
 390
 391                netdev_dbg(ieee->dev,
 392                           "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n",
 393                           UP, Dir, Addr, *ppTS);
 394                pTSInfo->field.ucTrafficType = 0;
 395                pTSInfo->field.ucTSID = UP;
 396                pTSInfo->field.ucDirection = Dir;
 397                pTSInfo->field.ucAccessPolicy = 1;
 398                pTSInfo->field.ucAggregation = 0;
 399                pTSInfo->field.ucPSB = 0;
 400                pTSInfo->field.ucUP = UP;
 401                pTSInfo->field.ucTSInfoAckPolicy = 0;
 402                pTSInfo->field.ucSchedule = 0;
 403
 404                MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
 405                AdmitTS(ieee, *ppTS, 0);
 406                list_add_tail(&((*ppTS)->List), pAddmitList);
 407
 408                return true;
 409        }
 410
 411        netdev_warn(ieee->dev,
 412                    "There is not enough dir=%d(0=up down=1) TS record to be used!",
 413                    Dir);
 414        return false;
 415}
 416
 417static void RemoveTsEntry(struct rtllib_device *ieee,
 418                          struct ts_common_info *pTs, enum tr_select TxRxSelect)
 419{
 420        del_timer_sync(&pTs->SetupTimer);
 421        del_timer_sync(&pTs->InactTimer);
 422        TsInitDelBA(ieee, pTs, TxRxSelect);
 423
 424        if (TxRxSelect == RX_DIR) {
 425                struct rx_reorder_entry *pRxReorderEntry;
 426                struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs;
 427
 428                if (timer_pending(&pRxTS->RxPktPendingTimer))
 429                        del_timer_sync(&pRxTS->RxPktPendingTimer);
 430
 431                while (!list_empty(&pRxTS->RxPendingPktList)) {
 432                        pRxReorderEntry = (struct rx_reorder_entry *)
 433                                        list_entry(pRxTS->RxPendingPktList.prev,
 434                                        struct rx_reorder_entry, List);
 435                        netdev_dbg(ieee->dev,  "%s(): Delete SeqNum %d!\n",
 436                                   __func__, pRxReorderEntry->SeqNum);
 437                        list_del_init(&pRxReorderEntry->List);
 438                        {
 439                                int i = 0;
 440                                struct rtllib_rxb *prxb = pRxReorderEntry->prxb;
 441
 442                                if (unlikely(!prxb))
 443                                        return;
 444                                for (i = 0; i < prxb->nr_subframes; i++)
 445                                        dev_kfree_skb(prxb->subframes[i]);
 446                                kfree(prxb);
 447                                prxb = NULL;
 448                        }
 449                        list_add_tail(&pRxReorderEntry->List,
 450                                      &ieee->RxReorder_Unused_List);
 451                }
 452        } else {
 453                struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
 454
 455                del_timer_sync(&pTxTS->TsAddBaTimer);
 456        }
 457}
 458
 459void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr)
 460{
 461        struct ts_common_info *pTS, *pTmpTS;
 462
 463        netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr);
 464
 465        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
 466                if (memcmp(pTS->Addr, Addr, 6) == 0) {
 467                        RemoveTsEntry(ieee, pTS, TX_DIR);
 468                        list_del_init(&pTS->List);
 469                        list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 470                }
 471        }
 472
 473        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
 474                if (memcmp(pTS->Addr, Addr, 6) == 0) {
 475                        netdev_info(ieee->dev,
 476                                    "====>remove Tx_TS_admin_list\n");
 477                        RemoveTsEntry(ieee, pTS, TX_DIR);
 478                        list_del_init(&pTS->List);
 479                        list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 480                }
 481        }
 482
 483        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
 484                if (memcmp(pTS->Addr, Addr, 6) == 0) {
 485                        RemoveTsEntry(ieee, pTS, RX_DIR);
 486                        list_del_init(&pTS->List);
 487                        list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 488                }
 489        }
 490
 491        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
 492                if (memcmp(pTS->Addr, Addr, 6) == 0) {
 493                        RemoveTsEntry(ieee, pTS, RX_DIR);
 494                        list_del_init(&pTS->List);
 495                        list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 496                }
 497        }
 498}
 499EXPORT_SYMBOL(RemovePeerTS);
 500
 501void RemoveAllTS(struct rtllib_device *ieee)
 502{
 503        struct ts_common_info *pTS, *pTmpTS;
 504
 505        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
 506                RemoveTsEntry(ieee, pTS, TX_DIR);
 507                list_del_init(&pTS->List);
 508                list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 509        }
 510
 511        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
 512                RemoveTsEntry(ieee, pTS, TX_DIR);
 513                list_del_init(&pTS->List);
 514                list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
 515        }
 516
 517        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
 518                RemoveTsEntry(ieee, pTS, RX_DIR);
 519                list_del_init(&pTS->List);
 520                list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 521        }
 522
 523        list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
 524                RemoveTsEntry(ieee, pTS, RX_DIR);
 525                list_del_init(&pTS->List);
 526                list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
 527        }
 528}
 529
 530void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
 531{
 532        if (pTxTS->bAddBaReqInProgress == false) {
 533                pTxTS->bAddBaReqInProgress = true;
 534
 535                if (pTxTS->bAddBaReqDelayed) {
 536                        netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
 537                        mod_timer(&pTxTS->TsAddBaTimer, jiffies +
 538                                  msecs_to_jiffies(TS_ADDBA_DELAY));
 539                } else {
 540                        netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
 541                        mod_timer(&pTxTS->TsAddBaTimer, jiffies+10);
 542                }
 543        } else
 544                netdev_dbg(ieee->dev, "BA timer is already added\n");
 545}
 546