1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * NXP Wireless LAN device driver: station TX data handling 4 * 5 * Copyright 2011-2020 NXP 6 */ 7 8 #include "decl.h" 9 #include "ioctl.h" 10 #include "util.h" 11 #include "fw.h" 12 #include "main.h" 13 #include "wmm.h" 14 15 /* 16 * This function fills the TxPD for tx packets. 17 * 18 * The Tx buffer received by this function should already have the 19 * header space allocated for TxPD. 20 * 21 * This function inserts the TxPD in between interface header and actual 22 * data and adjusts the buffer pointers accordingly. 23 * 24 * The following TxPD fields are set by this function, as required - 25 * - BSS number 26 * - Tx packet length and offset 27 * - Priority 28 * - Packet delay 29 * - Priority specific Tx control 30 * - Flags 31 */ 32 void mwifiex_process_sta_txpd(struct mwifiex_private *priv, 33 struct sk_buff *skb) 34 { 35 struct mwifiex_adapter *adapter = priv->adapter; 36 struct txpd *local_tx_pd; 37 struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); 38 unsigned int pad; 39 u16 pkt_type, pkt_offset; 40 int hroom = adapter->intf_hdr_len; 41 42 pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; 43 44 pad = ((uintptr_t)skb->data - (sizeof(*local_tx_pd) + hroom)) & 45 (MWIFIEX_DMA_ALIGN_SZ - 1); 46 skb_push(skb, sizeof(*local_tx_pd) + pad); 47 48 local_tx_pd = (struct txpd *) skb->data; 49 memset(local_tx_pd, 0, sizeof(struct txpd)); 50 local_tx_pd->bss_num = priv->bss_num; 51 local_tx_pd->bss_type = priv->bss_type; 52 local_tx_pd->tx_pkt_length = cpu_to_le16((u16)(skb->len - 53 (sizeof(struct txpd) + 54 pad))); 55 56 local_tx_pd->priority = (u8) skb->priority; 57 local_tx_pd->pkt_delay_2ms = 58 mwifiex_wmm_compute_drv_pkt_delay(priv, skb); 59 60 if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS || 61 tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) { 62 local_tx_pd->tx_token_id = tx_info->ack_frame_id; 63 local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS; 64 } 65 66 if (local_tx_pd->priority < 67 ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) 68 /* 69 * Set the priority specific tx_control field, setting of 0 will 70 * cause the default value to be used later in this function 71 */ 72 local_tx_pd->tx_control = 73 cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> 74 priority]); 75 76 if (adapter->pps_uapsd_mode) { 77 if (mwifiex_check_last_packet_indication(priv)) { 78 adapter->tx_lock_flag = true; 79 local_tx_pd->flags = 80 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; 81 } 82 } 83 84 if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) 85 local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET; 86 87 /* Offset of actual data */ 88 pkt_offset = sizeof(struct txpd) + pad; 89 if (pkt_type == PKT_TYPE_MGMT) { 90 /* Set the packet type and add header for management frame */ 91 local_tx_pd->tx_pkt_type = cpu_to_le16(pkt_type); 92 pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE; 93 } 94 95 local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); 96 97 /* make space for adapter->intf_hdr_len */ 98 skb_push(skb, hroom); 99 100 if (!local_tx_pd->tx_control) 101 /* TxCtrl set by user or default */ 102 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); 103 } 104 105 /* 106 * This function tells firmware to send a NULL data packet. 107 * 108 * The function creates a NULL data packet with TxPD and sends to the 109 * firmware for transmission, with highest priority setting. 110 */ 111 int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) 112 { 113 struct mwifiex_adapter *adapter = priv->adapter; 114 struct txpd *local_tx_pd; 115 struct mwifiex_tx_param tx_param; 116 /* sizeof(struct txpd) + Interface specific header */ 117 #define NULL_PACKET_HDR 64 118 u32 data_len = NULL_PACKET_HDR; 119 struct sk_buff *skb; 120 int ret; 121 struct mwifiex_txinfo *tx_info = NULL; 122 123 if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) 124 return -1; 125 126 if (!priv->media_connected) 127 return -1; 128 129 if (adapter->data_sent) 130 return -1; 131 132 if (adapter->if_ops.is_port_ready && 133 !adapter->if_ops.is_port_ready(priv)) 134 return -1; 135 136 skb = dev_alloc_skb(data_len); 137 if (!skb) 138 return -1; 139 140 tx_info = MWIFIEX_SKB_TXCB(skb); 141 memset(tx_info, 0, sizeof(*tx_info)); 142 tx_info->bss_num = priv->bss_num; 143 tx_info->bss_type = priv->bss_type; 144 tx_info->pkt_len = data_len - 145 (sizeof(struct txpd) + adapter->intf_hdr_len); 146 skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len); 147 skb_push(skb, sizeof(struct txpd)); 148 149 local_tx_pd = (struct txpd *) skb->data; 150 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); 151 local_tx_pd->flags = flags; 152 local_tx_pd->priority = WMM_HIGHEST_PRIORITY; 153 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); 154 local_tx_pd->bss_num = priv->bss_num; 155 local_tx_pd->bss_type = priv->bss_type; 156 157 skb_push(skb, adapter->intf_hdr_len); 158 if (adapter->iface_type == MWIFIEX_USB) { 159 ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, 160 skb, NULL); 161 } else { 162 tx_param.next_pkt_len = 0; 163 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, 164 skb, &tx_param); 165 } 166 switch (ret) { 167 case -EBUSY: 168 dev_kfree_skb_any(skb); 169 mwifiex_dbg(adapter, ERROR, 170 "%s: host_to_card failed: ret=%d\n", 171 __func__, ret); 172 adapter->dbg.num_tx_host_to_card_failure++; 173 break; 174 case -1: 175 dev_kfree_skb_any(skb); 176 mwifiex_dbg(adapter, ERROR, 177 "%s: host_to_card failed: ret=%d\n", 178 __func__, ret); 179 adapter->dbg.num_tx_host_to_card_failure++; 180 break; 181 case 0: 182 dev_kfree_skb_any(skb); 183 mwifiex_dbg(adapter, DATA, 184 "data: %s: host_to_card succeeded\n", 185 __func__); 186 adapter->tx_lock_flag = true; 187 break; 188 case -EINPROGRESS: 189 adapter->tx_lock_flag = true; 190 break; 191 default: 192 break; 193 } 194 195 return ret; 196 } 197 198 /* 199 * This function checks if we need to send last packet indication. 200 */ 201 u8 202 mwifiex_check_last_packet_indication(struct mwifiex_private *priv) 203 { 204 struct mwifiex_adapter *adapter = priv->adapter; 205 u8 ret = false; 206 207 if (!adapter->sleep_period.period) 208 return ret; 209 if (mwifiex_wmm_lists_empty(adapter)) 210 ret = true; 211 212 if (ret && !adapter->cmd_sent && !adapter->curr_cmd && 213 !is_command_pending(adapter)) { 214 adapter->delay_null_pkt = false; 215 ret = true; 216 } else { 217 ret = false; 218 adapter->delay_null_pkt = true; 219 } 220 return ret; 221 } 222