Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP Wireless LAN device driver: station TX data handling
0004  *
0005  * Copyright 2011-2020 NXP
0006  */
0007 
0008 #include "decl.h"
0009 #include "ioctl.h"
0010 #include "util.h"
0011 #include "fw.h"
0012 #include "main.h"
0013 #include "wmm.h"
0014 
0015 /*
0016  * This function fills the TxPD for tx packets.
0017  *
0018  * The Tx buffer received by this function should already have the
0019  * header space allocated for TxPD.
0020  *
0021  * This function inserts the TxPD in between interface header and actual
0022  * data and adjusts the buffer pointers accordingly.
0023  *
0024  * The following TxPD fields are set by this function, as required -
0025  *      - BSS number
0026  *      - Tx packet length and offset
0027  *      - Priority
0028  *      - Packet delay
0029  *      - Priority specific Tx control
0030  *      - Flags
0031  */
0032 void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
0033                 struct sk_buff *skb)
0034 {
0035     struct mwifiex_adapter *adapter = priv->adapter;
0036     struct txpd *local_tx_pd;
0037     struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
0038     unsigned int pad;
0039     u16 pkt_type, pkt_offset;
0040     int hroom = adapter->intf_hdr_len;
0041 
0042     if (!skb->len) {
0043         mwifiex_dbg(adapter, ERROR,
0044                 "Tx: bad packet length: %d\n", skb->len);
0045         tx_info->status_code = -1;
0046         return skb->data;
0047     }
0048 
0049     BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN);
0050 
0051     pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
0052 
0053     pad = ((uintptr_t)skb->data - (sizeof(*local_tx_pd) + hroom)) &
0054            (MWIFIEX_DMA_ALIGN_SZ - 1);
0055     skb_push(skb, sizeof(*local_tx_pd) + pad);
0056 
0057     local_tx_pd = (struct txpd *) skb->data;
0058     memset(local_tx_pd, 0, sizeof(struct txpd));
0059     local_tx_pd->bss_num = priv->bss_num;
0060     local_tx_pd->bss_type = priv->bss_type;
0061     local_tx_pd->tx_pkt_length = cpu_to_le16((u16)(skb->len -
0062                                (sizeof(struct txpd) +
0063                             pad)));
0064 
0065     local_tx_pd->priority = (u8) skb->priority;
0066     local_tx_pd->pkt_delay_2ms =
0067                 mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
0068 
0069     if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS ||
0070         tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) {
0071         local_tx_pd->tx_token_id = tx_info->ack_frame_id;
0072         local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS;
0073     }
0074 
0075     if (local_tx_pd->priority <
0076         ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
0077         /*
0078          * Set the priority specific tx_control field, setting of 0 will
0079          *   cause the default value to be used later in this function
0080          */
0081         local_tx_pd->tx_control =
0082             cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd->
0083                                    priority]);
0084 
0085     if (adapter->pps_uapsd_mode) {
0086         if (mwifiex_check_last_packet_indication(priv)) {
0087             adapter->tx_lock_flag = true;
0088             local_tx_pd->flags =
0089                 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
0090         }
0091     }
0092 
0093     if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT)
0094         local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET;
0095 
0096     /* Offset of actual data */
0097     pkt_offset = sizeof(struct txpd) + pad;
0098     if (pkt_type == PKT_TYPE_MGMT) {
0099         /* Set the packet type and add header for management frame */
0100         local_tx_pd->tx_pkt_type = cpu_to_le16(pkt_type);
0101         pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
0102     }
0103 
0104     local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset);
0105 
0106     /* make space for adapter->intf_hdr_len */
0107     skb_push(skb, hroom);
0108 
0109     if (!local_tx_pd->tx_control)
0110         /* TxCtrl set by user or default */
0111         local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
0112 
0113     return skb->data;
0114 }
0115 
0116 /*
0117  * This function tells firmware to send a NULL data packet.
0118  *
0119  * The function creates a NULL data packet with TxPD and sends to the
0120  * firmware for transmission, with highest priority setting.
0121  */
0122 int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
0123 {
0124     struct mwifiex_adapter *adapter = priv->adapter;
0125     struct txpd *local_tx_pd;
0126     struct mwifiex_tx_param tx_param;
0127 /* sizeof(struct txpd) + Interface specific header */
0128 #define NULL_PACKET_HDR 64
0129     u32 data_len = NULL_PACKET_HDR;
0130     struct sk_buff *skb;
0131     int ret;
0132     struct mwifiex_txinfo *tx_info = NULL;
0133 
0134     if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags))
0135         return -1;
0136 
0137     if (!priv->media_connected)
0138         return -1;
0139 
0140     if (adapter->data_sent)
0141         return -1;
0142 
0143     if (adapter->if_ops.is_port_ready &&
0144         !adapter->if_ops.is_port_ready(priv))
0145         return -1;
0146 
0147     skb = dev_alloc_skb(data_len);
0148     if (!skb)
0149         return -1;
0150 
0151     tx_info = MWIFIEX_SKB_TXCB(skb);
0152     memset(tx_info, 0, sizeof(*tx_info));
0153     tx_info->bss_num = priv->bss_num;
0154     tx_info->bss_type = priv->bss_type;
0155     tx_info->pkt_len = data_len -
0156             (sizeof(struct txpd) + adapter->intf_hdr_len);
0157     skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len);
0158     skb_push(skb, sizeof(struct txpd));
0159 
0160     local_tx_pd = (struct txpd *) skb->data;
0161     local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
0162     local_tx_pd->flags = flags;
0163     local_tx_pd->priority = WMM_HIGHEST_PRIORITY;
0164     local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
0165     local_tx_pd->bss_num = priv->bss_num;
0166     local_tx_pd->bss_type = priv->bss_type;
0167 
0168     skb_push(skb, adapter->intf_hdr_len);
0169     if (adapter->iface_type == MWIFIEX_USB) {
0170         ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
0171                            skb, NULL);
0172     } else {
0173         tx_param.next_pkt_len = 0;
0174         ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
0175                            skb, &tx_param);
0176     }
0177     switch (ret) {
0178     case -EBUSY:
0179         dev_kfree_skb_any(skb);
0180         mwifiex_dbg(adapter, ERROR,
0181                 "%s: host_to_card failed: ret=%d\n",
0182                 __func__, ret);
0183         adapter->dbg.num_tx_host_to_card_failure++;
0184         break;
0185     case -1:
0186         dev_kfree_skb_any(skb);
0187         mwifiex_dbg(adapter, ERROR,
0188                 "%s: host_to_card failed: ret=%d\n",
0189                 __func__, ret);
0190         adapter->dbg.num_tx_host_to_card_failure++;
0191         break;
0192     case 0:
0193         dev_kfree_skb_any(skb);
0194         mwifiex_dbg(adapter, DATA,
0195                 "data: %s: host_to_card succeeded\n",
0196                 __func__);
0197         adapter->tx_lock_flag = true;
0198         break;
0199     case -EINPROGRESS:
0200         adapter->tx_lock_flag = true;
0201         break;
0202     default:
0203         break;
0204     }
0205 
0206     return ret;
0207 }
0208 
0209 /*
0210  * This function checks if we need to send last packet indication.
0211  */
0212 u8
0213 mwifiex_check_last_packet_indication(struct mwifiex_private *priv)
0214 {
0215     struct mwifiex_adapter *adapter = priv->adapter;
0216     u8 ret = false;
0217 
0218     if (!adapter->sleep_period.period)
0219         return ret;
0220     if (mwifiex_wmm_lists_empty(adapter))
0221             ret = true;
0222 
0223     if (ret && !adapter->cmd_sent && !adapter->curr_cmd &&
0224         !is_command_pending(adapter)) {
0225         adapter->delay_null_pkt = false;
0226         ret = true;
0227     } else {
0228         ret = false;
0229         adapter->delay_null_pkt = true;
0230     }
0231     return ret;
0232 }