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