13aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* 23aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Marvell Wireless LAN device driver: 802.11n RX Re-ordering 33aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 43aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Copyright (C) 2011, Marvell International Ltd. 53aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 6bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller * This software file (the "File") is distributed by Marvell International 7bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller * Ltd. under the terms of the GNU General Public License Version 2, June 1991 84fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller * (the "License"). You may use, redistribute and/or modify this File in 9e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller * accordance with the terms and conditions of the License, a copy of which 10bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller * is available by writing to the Free Software Foundation, Inc., 113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * this warranty disclaimer. 183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "decl.h" 213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "ioctl.h" 223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "util.h" 233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "fw.h" 243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "main.h" 253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "wmm.h" 263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "11n.h" 273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "11n_rxreorder.h" 283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* 307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton * This function dispatches all packets in the Rx reorder table. 316e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora * 323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * There could be holes in the buffer, which are skipped by the function. 333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Since the buffer is linear, the function uses rotation to simulate 343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * circular buffer. 353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void 373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, 383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab struct mwifiex_rx_reorder_tbl 393aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab *rx_reor_tbl_ptr, int start_win) 403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{ 413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab int no_pkt_to_send, i; 423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab void *rx_tmp_ptr; 433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab unsigned long flags; 443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? 463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab min((start_win - rx_reor_tbl_ptr->start_win), 473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size; 483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton for (i = 0; i < no_pkt_to_send; ++i) { 503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_lock_irqsave(&priv->rx_pkt_lock, flags); 513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_tmp_ptr = NULL; 523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) { 533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; 543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; 553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (rx_tmp_ptr) 583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); 593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_lock_irqsave(&priv->rx_pkt_lock, flags); 623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton /* 633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * We don't have a circular buffer, hence use rotation to simulate 643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * circular buffer 653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) { 673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[i] = 683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; 693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; 703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab } 713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab rx_reor_tbl_ptr->start_win = start_win; 733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function dispatches all packets in the Rx reorder table until 783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * a hole is found. 793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The start window is adjusted automatically when a hole is located. 813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Since the buffer is linear, the function uses rotation to simulate 823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * circular buffer. 833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void 853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonmwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, 863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) 873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton int i, j, xchg; 893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton void *rx_tmp_ptr; 903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton unsigned long flags; 913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { 933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_lock_irqsave(&priv->rx_pkt_lock, flags); 943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) { 953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton break; 973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; 993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; 1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 1013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); 1026ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf } 1036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf 1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_lock_irqsave(&priv->rx_pkt_lock, flags); 1053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton /* 1063aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * We don't have a circular buffer, hence use rotation to simulate 1073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * circular buffer 1083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 1093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (i > 0) { 1103aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab xchg = rx_reor_tbl_ptr->win_size - i; 1113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton for (j = 0; j < xchg; ++j) { 1123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[j] = 1133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab rx_reor_tbl_ptr->rx_reorder_ptr[i + j]; 1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL; 1153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 1163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) 1183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton &(MAX_TID_VALUE - 1); 1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); 1203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 1213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function deletes the Rx reorder table and frees the memory. 1243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 1253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The function stops the associated timer and dispatches all the 1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * pending packets in the Rx reorder table before deletion. 1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 1283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void 1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonmwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv, 1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct mwifiex_rx_reorder_tbl 1313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *rx_reor_tbl_ptr) 1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton unsigned long flags; 1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (!rx_reor_tbl_ptr) 1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return; 1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, 1393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (rx_reor_tbl_ptr->start_win + 1406ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf rx_reor_tbl_ptr->win_size) 1416ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf &(MAX_TID_VALUE - 1)); 142c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab 1433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton del_timer(&rx_reor_tbl_ptr->timer_context.timer); 144d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller 1453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 1463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton list_del(&rx_reor_tbl_ptr->list); 147c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 148c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab 149c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab kfree(rx_reor_tbl_ptr->rx_reorder_ptr); 1503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton kfree(rx_reor_tbl_ptr); 151d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller} 152d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller 1533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 154d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller * This function returns the pointer to an entry in Rx reordering 155c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab * table which matches the given TA/TID pair. 1563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 1573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic struct mwifiex_rx_reorder_tbl * 1586ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafmwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) 1596ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{ 1603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 1613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton unsigned long flags; 1623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 163c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 1642fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { 165c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN)) 1663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab && (rx_reor_tbl_ptr->tid == tid)) { 1673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, 1683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab flags); 1693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return rx_reor_tbl_ptr; 1703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 1713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 1723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 1733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return NULL; 1753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 1763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 1783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function finds the last sequence number used in the packets 1793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * buffered in Rx reordering table. 1803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 1813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int 1823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonmwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) 1833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 1846ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf int i; 1856ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf 1863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) 1873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) 1883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return i; 1893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return -1; 1913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 1923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 1933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 1943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function flushes all the packets in Rx reordering table. 1953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 1963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The function checks if any packets are currently buffered in the 1973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * table or not. In case there are packets available, it dispatches 1983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * them and then dumps the Rx reordering table. 1993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 2006ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic void 2016ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafmwifiex_flush_data(unsigned long context) 2023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 2036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf struct reorder_tmr_cnxt *reorder_cnxt = 2043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (struct reorder_tmr_cnxt *) context; 2053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton int start_win; 2063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 2073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr); 2083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (start_win >= 0) { 209e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab dev_dbg(reorder_cnxt->priv->adapter->dev, 210e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab "info: flush data %d\n", start_win); 211e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv, 212e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab reorder_cnxt->ptr, 213e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab ((reorder_cnxt->ptr->start_win + 214e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab start_win + 1) & (MAX_TID_VALUE - 1))); 215e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab } 216e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab} 217e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab 2182fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab/* 219e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab * This function creates an entry in Rx reordering table for the 220e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab * given TA/TID. 2213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 2223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * The function also initializes the entry with sequence number, window 223227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * size as well as initializes the timer. 224227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * 225227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * If the received TA/TID pair is already present, all the packets are 226227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab * dispatched and the window size is moved until the SSN. 2273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 2287e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonstatic void 2297e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonmwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, 2307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton int tid, int win_size, int seq_num) 2317e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton{ 2327e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton int i; 2337e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node; 2347e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton u16 last_seq = 0; 2356e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora unsigned long flags; 2366e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora 2376e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora /* 2386e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora * If we get a TID, ta pair which is already present dispatch all the 2396e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora * the packets and move the window size until the ssn 2406e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora */ 2416e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); 2426e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora if (rx_reor_tbl_ptr) { 2436e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, 24417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller seq_num); 24517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller return; 24617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller } 24717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller /* if !rx_reor_tbl_ptr then create one */ 24817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); 24917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller if (!new_node) { 25017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", 2513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab __func__); 2523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab return; 2533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab } 2543aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 2553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab INIT_LIST_HEAD(&new_node->list); 2563ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab new_node->tid = tid; 2573ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab memcpy(new_node->ta, ta, ETH_ALEN); 2586ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf new_node->start_win = seq_num; 2593ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab if (mwifiex_queuing_ra_based(priv)) 2603ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab /* TODO for adhoc */ 2613ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab dev_dbg(priv->adapter->dev, 2623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton "info: ADHOC:last_seq=%d start_win=%d\n", 2633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab last_seq, new_node->start_win); 2643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab else 2653aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab last_seq = priv->rx_seq[tid]; 2663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 2673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab if (last_seq >= new_node->start_win) 2683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab new_node->start_win = last_seq + 1; 2693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 2703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab new_node->win_size = win_size; 2713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 2723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, 2733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton GFP_KERNEL); 2743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (!new_node->rx_reorder_ptr) { 2753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab kfree((u8 *) new_node); 2763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab dev_err(priv->adapter->dev, 2773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab "%s: failed to alloc reorder_ptr\n", __func__); 2783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab return; 2793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab } 2803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 2813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab new_node->timer_context.ptr = new_node; 2823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab new_node->timer_context.priv = priv; 2833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 2843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton init_timer(&new_node->timer_context.timer); 285d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuil new_node->timer_context.timer.function = mwifiex_flush_data; 2863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton new_node->timer_context.timer.data = 2873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (unsigned long) &new_node->timer_context; 2883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 2893aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab for (i = 0; i < win_size; ++i) 2903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton new_node->rx_reorder_ptr[i] = NULL; 2913aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 2923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 2933aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); 2943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 2953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 2963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 2973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 2983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function prepares command for adding a BA request. 2993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 3003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Preparation includes - 3013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Setting command ID and proper size 302e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab * - Setting add BA request buffer 303e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab * - Ensuring correct endian-ness 304e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab */ 305e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehabint mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) 3063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 3073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct host_cmd_ds_11n_addba_req *add_ba_req = 3083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (struct host_cmd_ds_11n_addba_req *) 3093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton &cmd->params.add_ba_req; 3103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); 3123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); 3133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); 3143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return 0; 3163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 3173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 3193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function prepares command for adding a BA response. 3203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 3213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Preparation includes - 3223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Setting command ID and proper size 3233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Setting add BA response buffer 3243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Ensuring correct endian-ness 325e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab */ 3263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, 3273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct host_cmd_ds_command *cmd, 3283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct host_cmd_ds_11n_addba_req 3293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton *cmd_addba_req) 3303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 3313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = 3323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (struct host_cmd_ds_11n_addba_rsp *) 3333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton &cmd->params.add_ba_rsp; 3343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton u8 tid; 3353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton int win_size; 3363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton uint16_t block_ack_param_set; 3373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); 3393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); 3403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, 34252284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab ETH_ALEN); 3433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; 3443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; 3453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton add_ba_rsp->ssn = cmd_addba_req->ssn; 3463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); 3483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) 3493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton >> BLOCKACKPARAM_TID_POS; 3503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); 3513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; 3523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton /* We donot support AMSDU inside AMPDU, hence reset the bit */ 3533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; 3543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton block_ack_param_set |= (priv->add_ba_param.rx_win_size << 3553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton BLOCKACKPARAM_WINSIZE_POS); 3563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); 3573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) 3583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) 3593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton >> BLOCKACKPARAM_WINSIZE_POS; 3603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); 3613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, 3633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton tid, win_size, le16_to_cpu(cmd_addba_req->ssn)); 3643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return 0; 3653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 3663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 3683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function prepares command for deleting a BA request. 3693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 3703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * Preparation includes - 3713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Setting command ID and proper size 3723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Setting del BA request buffer 3733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * - Ensuring correct endian-ness 3743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 3753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf) 3763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 3773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) 3783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton &cmd->params.del_ba; 3793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); 3813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); 3823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton memcpy(del_ba, data_buf, sizeof(*del_ba)); 3833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return 0; 3853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton} 3863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 3873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 3883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function identifies if Rx reordering is needed for a received packet. 3893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 3903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * In case reordering is required, the function will do the reordering 3913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * before sending it to kernel. 3923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 3933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * The Rx reorder table is checked first with the received TID/TA pair. If 3943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * not found, the received packet is dispatched immediately. But if found, 3953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * the packet is reordered and all the packets in the updated Rx reordering 3963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * table is dispatched until a hole is found. 3973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * 3983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * For sequence number less than the starting window, the packet is dropped. 3993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 4003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, 4013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton u16 seq_num, u16 tid, 4023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton u8 *ta, u8 pkt_type, void *payload) 4033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 4043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 405505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab int start_win, end_win, win_size; 406df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller u16 pkt_index; 407df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller 408df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller rx_reor_tbl_ptr = 409df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, 4103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton tid, ta); 4116ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf if (!rx_reor_tbl_ptr) { 4126ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf if (pkt_type != PKT_TYPE_BAR) 4136ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf mwifiex_process_rx_packet(priv->adapter, payload); 4143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return 0; 4153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } 4163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton start_win = rx_reor_tbl_ptr->start_win; 4173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab win_size = rx_reor_tbl_ptr->win_size; 418c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); 4193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab del_timer(&rx_reor_tbl_ptr->timer_context.timer); 4203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies 421f89bc32974a4376e8393001484af28d8c3350ab4Douglas Schilling Landgraf + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); 42210ac6603613d46a43a4544fbbe9581e50879bd45Mauro Carvalho Chehab 4234fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller /* 424e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller * If seq_num is less then starting win then ignore and drop the 4253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * packet 4263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 4273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ 4283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1)) 4293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton && (seq_num < start_win)) 4303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton return -1; 4313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } else if ((seq_num < start_win) 432227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab || (seq_num > (start_win + (TWOPOW11)))) { 4337e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton return -1; 43446510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE } 43546510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE 436e5db5d44432abc82b1250dd05bd0a4b011392d9dDouglas Schilling Landgraf /* 4373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * If this packet is a BAR we adjust seq_num as 4383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * WinStart = seq_num 4393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton */ 4403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (pkt_type == PKT_TYPE_BAR) 4413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); 4423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 4433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (((end_win < start_win) 4447e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) 4456e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora && (seq_num > end_win)) || ((end_win > start_win) 4466e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora && ((seq_num > end_win) || (seq_num < start_win)))) { 4476e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora end_win = seq_num; 4486e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora if (((seq_num - win_size) + 1) >= 0) 4496e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora start_win = (end_win - win_size) + 1; 4506e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora else 4516e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; 4526e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora mwifiex_11n_dispatch_pkt_until_start_win(priv, 4536e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora rx_reor_tbl_ptr, start_win); 45417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller } 45517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller 45617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller if (pkt_type != PKT_TYPE_BAR) { 45717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller if (seq_num >= start_win) 45817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller pkt_index = seq_num - start_win; 45917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller else 46017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller pkt_index = (seq_num+MAX_TID_VALUE) - start_win; 46117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller 46217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index]) 46317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller return -1; 46417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller 46517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload; 46617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller } 4673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 4683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab /* 4693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Dispatch all packets sequentially from start_win until a 4703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * hole is found and adjust the start_win appropriately 4713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 4723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); 4733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 4743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab return 0; 4753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} 4763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 4773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* 4783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton * This function deletes an entry for a given TID/TA pair. 4793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 480d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky * The TID/TA are taken from del BA event body. 481d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky */ 4823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabvoid 4833aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid, 4843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton u8 *peer_mac, u8 type, int initiator) 4853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{ 4866ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 4873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton struct mwifiex_tx_ba_stream_tbl *ptx_tbl; 4883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton u8 cleanup_rx_reorder_tbl; 4892fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab unsigned long flags; 490102a0b0879a01a413ed5f667f7db9c2085ca8474Mauro Carvalho Chehab 4913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (type == TYPE_DELBA_RECEIVE) 4923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton cleanup_rx_reorder_tbl = (initiator) ? true : false; 4933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton else 4942fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab cleanup_rx_reorder_tbl = (initiator) ? false : true; 4953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton 4963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, " 4973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton "initiator=%d\n", peer_mac, tid, initiator); 4983aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 4993aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab if (cleanup_rx_reorder_tbl) { 5003aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, 5013aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab peer_mac); 502505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab if (!rx_reor_tbl_ptr) { 503df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller dev_dbg(priv->adapter->dev, 504df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller "event: TID, TA not found in table\n"); 505df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller return; 506df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller } 5073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr); 5083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton } else { 5093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac); 5103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton if (!ptx_tbl) { 5113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab dev_dbg(priv->adapter->dev, 5123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab "event: TID, RA not found in table\n"); 5133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab return; 5143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab } 5153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 5163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); 5173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); 5183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); 5193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab } 5203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} 5213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab 5223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* 5233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * This function handles the command response of an add BA response. 5243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * 5253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * Handling includes changing the header fields into CPU format and 5263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab * creating the stream, provided the add BA is accepted. 5273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */ 5283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabint mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, 5293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab struct host_cmd_ds_command *resp) 5303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{ 5313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = 5323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab (struct host_cmd_ds_11n_addba_rsp *) 5333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab &resp->params.add_ba_rsp; 534 int tid, win_size; 535 struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; 536 uint16_t block_ack_param_set; 537 538 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); 539 540 tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) 541 >> BLOCKACKPARAM_TID_POS; 542 /* 543 * Check if we had rejected the ADDBA, if yes then do not create 544 * the stream 545 */ 546 if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { 547 win_size = (block_ack_param_set & 548 IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) 549 >> BLOCKACKPARAM_WINSIZE_POS; 550 551 dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM" 552 " tid=%d ssn=%d win_size=%d\n", 553 add_ba_rsp->peer_mac_addr, 554 tid, add_ba_rsp->ssn, win_size); 555 } else { 556 dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", 557 add_ba_rsp->peer_mac_addr, tid); 558 559 rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, 560 tid, add_ba_rsp->peer_mac_addr); 561 if (rx_reor_tbl_ptr) 562 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, 563 rx_reor_tbl_ptr); 564 } 565 566 return 0; 567} 568 569/* 570 * This function handles BA stream timeout event by preparing and sending 571 * a command to the firmware. 572 */ 573void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, 574 struct host_cmd_ds_11n_batimeout *event) 575{ 576 struct host_cmd_ds_11n_delba delba; 577 578 memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); 579 memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); 580 581 delba.del_ba_param_set |= 582 cpu_to_le16((u16) event->tid << DELBA_TID_POS); 583 delba.del_ba_param_set |= cpu_to_le16( 584 (u16) event->origninator << DELBA_INITIATOR_POS); 585 delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); 586 mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); 587} 588 589/* 590 * This function cleans up the Rx reorder table by deleting all the entries 591 * and re-initializing. 592 */ 593void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) 594{ 595 struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; 596 unsigned long flags; 597 598 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 599 list_for_each_entry_safe(del_tbl_ptr, tmp_node, 600 &priv->rx_reorder_tbl_ptr, list) { 601 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 602 mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr); 603 spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); 604 } 605 spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); 606 607 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); 608 memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); 609} 610