root/drivers/net/wireless/marvell/mwifiex/txrx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mwifiex_handle_rx_packet
  2. mwifiex_process_tx
  3. mwifiex_host_to_card
  4. mwifiex_dequeue_tx_queue
  5. mwifiex_process_tx_queue
  6. mwifiex_write_data_complete
  7. mwifiex_parse_tx_status_event

   1 /*
   2  * Marvell Wireless LAN device driver: generic TX/RX data handling
   3  *
   4  * Copyright (C) 2011-2014, Marvell International Ltd.
   5  *
   6  * This software file (the "File") is distributed by Marvell International
   7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
   8  * (the "License").  You may use, redistribute and/or modify this File in
   9  * accordance with the terms and conditions of the License, a copy of which
  10  * is available by writing to the Free Software Foundation, Inc.,
  11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13  *
  14  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17  * this warranty disclaimer.
  18  */
  19 
  20 #include "decl.h"
  21 #include "ioctl.h"
  22 #include "util.h"
  23 #include "fw.h"
  24 #include "main.h"
  25 #include "wmm.h"
  26 
  27 /*
  28  * This function processes the received buffer.
  29  *
  30  * Main responsibility of this function is to parse the RxPD to
  31  * identify the correct interface this packet is headed for and
  32  * forwarding it to the associated handling function, where the
  33  * packet will be further processed and sent to kernel/upper layer
  34  * if required.
  35  */
  36 int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
  37                              struct sk_buff *skb)
  38 {
  39         struct mwifiex_private *priv =
  40                 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
  41         struct rxpd *local_rx_pd;
  42         struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
  43         int ret;
  44 
  45         local_rx_pd = (struct rxpd *) (skb->data);
  46         /* Get the BSS number from rxpd, get corresponding priv */
  47         priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
  48                                       BSS_NUM_MASK, local_rx_pd->bss_type);
  49         if (!priv)
  50                 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
  51 
  52         if (!priv) {
  53                 mwifiex_dbg(adapter, ERROR,
  54                             "data: priv not found. Drop RX packet\n");
  55                 dev_kfree_skb_any(skb);
  56                 return -1;
  57         }
  58 
  59         mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data,
  60                          min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
  61 
  62         memset(rx_info, 0, sizeof(*rx_info));
  63         rx_info->bss_num = priv->bss_num;
  64         rx_info->bss_type = priv->bss_type;
  65 
  66         if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
  67                 ret = mwifiex_process_uap_rx_packet(priv, skb);
  68         else
  69                 ret = mwifiex_process_sta_rx_packet(priv, skb);
  70 
  71         return ret;
  72 }
  73 EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
  74 
  75 /*
  76  * This function sends a packet to device.
  77  *
  78  * It processes the packet to add the TxPD, checks condition and
  79  * sends the processed packet to firmware for transmission.
  80  *
  81  * On successful completion, the function calls the completion callback
  82  * and logs the time.
  83  */
  84 int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
  85                        struct mwifiex_tx_param *tx_param)
  86 {
  87         int hroom, ret = -1;
  88         struct mwifiex_adapter *adapter = priv->adapter;
  89         u8 *head_ptr;
  90         struct txpd *local_tx_pd = NULL;
  91         struct mwifiex_sta_node *dest_node;
  92         struct ethhdr *hdr = (void *)skb->data;
  93 
  94         hroom = adapter->intf_hdr_len;
  95 
  96         if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
  97                 dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest);
  98                 if (dest_node) {
  99                         dest_node->stats.tx_bytes += skb->len;
 100                         dest_node->stats.tx_packets++;
 101                 }
 102 
 103                 head_ptr = mwifiex_process_uap_txpd(priv, skb);
 104         } else {
 105                 head_ptr = mwifiex_process_sta_txpd(priv, skb);
 106         }
 107 
 108         if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
 109                 skb_queue_tail(&adapter->tx_data_q, skb);
 110                 atomic_inc(&adapter->tx_queued);
 111                 return 0;
 112         }
 113 
 114         if (head_ptr) {
 115                 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
 116                         local_tx_pd = (struct txpd *)(head_ptr + hroom);
 117                 if (adapter->iface_type == MWIFIEX_USB) {
 118                         ret = adapter->if_ops.host_to_card(adapter,
 119                                                            priv->usb_port,
 120                                                            skb, tx_param);
 121                 } else {
 122                         ret = adapter->if_ops.host_to_card(adapter,
 123                                                            MWIFIEX_TYPE_DATA,
 124                                                            skb, tx_param);
 125                 }
 126         }
 127         mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
 128                          min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
 129 
 130         switch (ret) {
 131         case -ENOSR:
 132                 mwifiex_dbg(adapter, DATA, "data: -ENOSR is returned\n");
 133                 break;
 134         case -EBUSY:
 135                 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
 136                     (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) {
 137                                 priv->adapter->tx_lock_flag = false;
 138                                 if (local_tx_pd)
 139                                         local_tx_pd->flags = 0;
 140                 }
 141                 mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
 142                 break;
 143         case -1:
 144                 mwifiex_dbg(adapter, ERROR,
 145                             "mwifiex_write_data_async failed: 0x%X\n",
 146                             ret);
 147                 adapter->dbg.num_tx_host_to_card_failure++;
 148                 mwifiex_write_data_complete(adapter, skb, 0, ret);
 149                 break;
 150         case -EINPROGRESS:
 151                 break;
 152         case 0:
 153                 mwifiex_write_data_complete(adapter, skb, 0, ret);
 154                 break;
 155         default:
 156                 break;
 157         }
 158 
 159         return ret;
 160 }
 161 
 162 static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
 163                                 struct sk_buff *skb,
 164                                 struct mwifiex_tx_param *tx_param)
 165 {
 166         struct txpd *local_tx_pd = NULL;
 167         u8 *head_ptr = skb->data;
 168         int ret = 0;
 169         struct mwifiex_private *priv;
 170         struct mwifiex_txinfo *tx_info;
 171 
 172         tx_info = MWIFIEX_SKB_TXCB(skb);
 173         priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
 174                                       tx_info->bss_type);
 175         if (!priv) {
 176                 mwifiex_dbg(adapter, ERROR,
 177                             "data: priv not found. Drop TX packet\n");
 178                 adapter->dbg.num_tx_host_to_card_failure++;
 179                 mwifiex_write_data_complete(adapter, skb, 0, 0);
 180                 return ret;
 181         }
 182         if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
 183                 local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len);
 184 
 185         if (adapter->iface_type == MWIFIEX_USB) {
 186                 ret = adapter->if_ops.host_to_card(adapter,
 187                                                    priv->usb_port,
 188                                                    skb, tx_param);
 189         } else {
 190                 ret = adapter->if_ops.host_to_card(adapter,
 191                                                    MWIFIEX_TYPE_DATA,
 192                                                    skb, tx_param);
 193         }
 194         switch (ret) {
 195         case -ENOSR:
 196                 mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
 197                 break;
 198         case -EBUSY:
 199                 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
 200                     (adapter->pps_uapsd_mode) &&
 201                     (adapter->tx_lock_flag)) {
 202                         priv->adapter->tx_lock_flag = false;
 203                         if (local_tx_pd)
 204                                 local_tx_pd->flags = 0;
 205                 }
 206                 skb_queue_head(&adapter->tx_data_q, skb);
 207                 if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
 208                         atomic_add(tx_info->aggr_num, &adapter->tx_queued);
 209                 else
 210                         atomic_inc(&adapter->tx_queued);
 211                 mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
 212                 break;
 213         case -1:
 214                 mwifiex_dbg(adapter, ERROR,
 215                             "mwifiex_write_data_async failed: 0x%X\n", ret);
 216                 adapter->dbg.num_tx_host_to_card_failure++;
 217                 mwifiex_write_data_complete(adapter, skb, 0, ret);
 218                 break;
 219         case -EINPROGRESS:
 220                 break;
 221         case 0:
 222                 mwifiex_write_data_complete(adapter, skb, 0, ret);
 223                 break;
 224         default:
 225                 break;
 226         }
 227         return ret;
 228 }
 229 
 230 static int
 231 mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter)
 232 {
 233         struct sk_buff *skb, *skb_next;
 234         struct mwifiex_txinfo *tx_info;
 235         struct mwifiex_tx_param tx_param;
 236 
 237         skb = skb_dequeue(&adapter->tx_data_q);
 238         if (!skb)
 239                 return -1;
 240 
 241         tx_info = MWIFIEX_SKB_TXCB(skb);
 242         if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
 243                 atomic_sub(tx_info->aggr_num, &adapter->tx_queued);
 244         else
 245                 atomic_dec(&adapter->tx_queued);
 246 
 247         if (!skb_queue_empty(&adapter->tx_data_q))
 248                 skb_next = skb_peek(&adapter->tx_data_q);
 249         else
 250                 skb_next = NULL;
 251         tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0);
 252         if (!tx_param.next_pkt_len) {
 253                 if (!mwifiex_wmm_lists_empty(adapter))
 254                         tx_param.next_pkt_len = 1;
 255         }
 256         return mwifiex_host_to_card(adapter, skb, &tx_param);
 257 }
 258 
 259 void
 260 mwifiex_process_tx_queue(struct mwifiex_adapter *adapter)
 261 {
 262         do {
 263                 if (adapter->data_sent || adapter->tx_lock_flag)
 264                         break;
 265                 if (mwifiex_dequeue_tx_queue(adapter))
 266                         break;
 267         } while (!skb_queue_empty(&adapter->tx_data_q));
 268 }
 269 
 270 /*
 271  * Packet send completion callback handler.
 272  *
 273  * It either frees the buffer directly or forwards it to another
 274  * completion callback which checks conditions, updates statistics,
 275  * wakes up stalled traffic queue if required, and then frees the buffer.
 276  */
 277 int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
 278                                 struct sk_buff *skb, int aggr, int status)
 279 {
 280         struct mwifiex_private *priv;
 281         struct mwifiex_txinfo *tx_info;
 282         struct netdev_queue *txq;
 283         int index;
 284 
 285         if (!skb)
 286                 return 0;
 287 
 288         tx_info = MWIFIEX_SKB_TXCB(skb);
 289         priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
 290                                       tx_info->bss_type);
 291         if (!priv)
 292                 goto done;
 293 
 294         mwifiex_set_trans_start(priv->netdev);
 295 
 296         if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
 297                 atomic_dec_return(&adapter->pending_bridged_pkts);
 298 
 299         if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
 300                 goto done;
 301 
 302         if (!status) {
 303                 priv->stats.tx_packets++;
 304                 priv->stats.tx_bytes += tx_info->pkt_len;
 305                 if (priv->tx_timeout_cnt)
 306                         priv->tx_timeout_cnt = 0;
 307         } else {
 308                 priv->stats.tx_errors++;
 309         }
 310 
 311         if (aggr)
 312                 /* For skb_aggr, do not wake up tx queue */
 313                 goto done;
 314 
 315         atomic_dec(&adapter->tx_pending);
 316 
 317         index = mwifiex_1d_to_wmm_queue[skb->priority];
 318         if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) {
 319                 txq = netdev_get_tx_queue(priv->netdev, index);
 320                 if (netif_tx_queue_stopped(txq)) {
 321                         netif_tx_wake_queue(txq);
 322                         mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index);
 323                 }
 324         }
 325 done:
 326         dev_kfree_skb_any(skb);
 327 
 328         return 0;
 329 }
 330 EXPORT_SYMBOL_GPL(mwifiex_write_data_complete);
 331 
 332 void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
 333                                    void *event_body)
 334 {
 335         struct tx_status_event *tx_status = (void *)priv->adapter->event_body;
 336         struct sk_buff *ack_skb;
 337         struct mwifiex_txinfo *tx_info;
 338 
 339         if (!tx_status->tx_token_id)
 340                 return;
 341 
 342         spin_lock_bh(&priv->ack_status_lock);
 343         ack_skb = idr_remove(&priv->ack_status_frames, tx_status->tx_token_id);
 344         spin_unlock_bh(&priv->ack_status_lock);
 345 
 346         if (ack_skb) {
 347                 tx_info = MWIFIEX_SKB_TXCB(ack_skb);
 348 
 349                 if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) {
 350                         /* consumes ack_skb */
 351                         skb_complete_wifi_ack(ack_skb, !tx_status->status);
 352                 } else {
 353                         /* Remove broadcast address which was added by driver */
 354                         memmove(ack_skb->data +
 355                                 sizeof(struct ieee80211_hdr_3addr) +
 356                                 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16),
 357                                 ack_skb->data +
 358                                 sizeof(struct ieee80211_hdr_3addr) +
 359                                 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) +
 360                                 ETH_ALEN, ack_skb->len -
 361                                 (sizeof(struct ieee80211_hdr_3addr) +
 362                                 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) +
 363                                 ETH_ALEN));
 364                         ack_skb->len = ack_skb->len - ETH_ALEN;
 365                         /* Remove driver's proprietary header including 2 bytes
 366                          * of packet length and pass actual management frame buffer
 367                          * to cfg80211.
 368                          */
 369                         cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie,
 370                                                 ack_skb->data +
 371                                                 MWIFIEX_MGMT_FRAME_HEADER_SIZE +
 372                                                 sizeof(u16), ack_skb->len -
 373                                                 (MWIFIEX_MGMT_FRAME_HEADER_SIZE
 374                                                  + sizeof(u16)),
 375                                                 !tx_status->status, GFP_ATOMIC);
 376                         dev_kfree_skb_any(ack_skb);
 377                 }
 378         }
 379 }

/* [<][>][^][v][top][bottom][index][help] */