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 if (!skb->len) { 43 mwifiex_dbg(adapter, ERROR, 44 "Tx: bad packet length: %d\n", skb->len); 45 tx_info->status_code = -1; 46 return skb->data; 47 } 48 49 BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN); 50 51 pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; 52 53 pad = ((uintptr_t)skb->data - (sizeof(*local_tx_pd) + hroom)) & 54 (MWIFIEX_DMA_ALIGN_SZ - 1); 55 skb_push(skb, sizeof(*local_tx_pd) + pad); 56 57 local_tx_pd = (struct txpd *) skb->data; 58 memset(local_tx_pd, 0, sizeof(struct txpd)); 59 local_tx_pd->bss_num = priv->bss_num; 60 local_tx_pd->bss_type = priv->bss_type; 61 local_tx_pd->tx_pkt_length = cpu_to_le16((u16)(skb->len - 62 (sizeof(struct txpd) + 63 pad))); 64 65 local_tx_pd->priority = (u8) skb->priority; 66 local_tx_pd->pkt_delay_2ms = 67 mwifiex_wmm_compute_drv_pkt_delay(priv, skb); 68 69 if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS || 70 tx_info->flags & MWIFIEX_BUF_FLAG_ACTION_TX_STATUS) { 71 local_tx_pd->tx_token_id = tx_info->ack_frame_id; 72 local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS; 73 } 74 75 if (local_tx_pd->priority < 76 ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) 77 /* 78 * Set the priority specific tx_control field, setting of 0 will 79 * cause the default value to be used later in this function 80 */ 81 local_tx_pd->tx_control = 82 cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> 83 priority]); 84 85 if (adapter->pps_uapsd_mode) { 86 if (mwifiex_check_last_packet_indication(priv)) { 87 adapter->tx_lock_flag = true; 88 local_tx_pd->flags = 89 MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; 90 } 91 } 92 93 if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) 94 local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET; 95 96 /* Offset of actual data */ 97 pkt_offset = sizeof(struct txpd) + pad; 98 if (pkt_type == PKT_TYPE_MGMT) { 99 /* Set the packet type and add header for management frame */ 100 local_tx_pd->tx_pkt_type = cpu_to_le16(pkt_type); 101 pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE; 102 } 103 104 local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); 105 106 /* make space for adapter->intf_hdr_len */ 107 skb_push(skb, hroom); 108 109 if (!local_tx_pd->tx_control) 110 /* TxCtrl set by user or default */ 111 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); 112 113 return skb->data; 114 } 115 116 /* 117 * This function tells firmware to send a NULL data packet. 118 * 119 * The function creates a NULL data packet with TxPD and sends to the 120 * firmware for transmission, with highest priority setting. 121 */ 122 int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) 123 { 124 struct mwifiex_adapter *adapter = priv->adapter; 125 struct txpd *local_tx_pd; 126 struct mwifiex_tx_param tx_param; 127 /* sizeof(struct txpd) + Interface specific header */ 128 #define NULL_PACKET_HDR 64 129 u32 data_len = NULL_PACKET_HDR; 130 struct sk_buff *skb; 131 int ret; 132 struct mwifiex_txinfo *tx_info = NULL; 133 134 if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) 135 return -1; 136 137 if (!priv->media_connected) 138 return -1; 139 140 if (adapter->data_sent) 141 return -1; 142 143 if (adapter->if_ops.is_port_ready && 144 !adapter->if_ops.is_port_ready(priv)) 145 return -1; 146 147 skb = dev_alloc_skb(data_len); 148 if (!skb) 149 return -1; 150 151 tx_info = MWIFIEX_SKB_TXCB(skb); 152 memset(tx_info, 0, sizeof(*tx_info)); 153 tx_info->bss_num = priv->bss_num; 154 tx_info->bss_type = priv->bss_type; 155 tx_info->pkt_len = data_len - 156 (sizeof(struct txpd) + adapter->intf_hdr_len); 157 skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len); 158 skb_push(skb, sizeof(struct txpd)); 159 160 local_tx_pd = (struct txpd *) skb->data; 161 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); 162 local_tx_pd->flags = flags; 163 local_tx_pd->priority = WMM_HIGHEST_PRIORITY; 164 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); 165 local_tx_pd->bss_num = priv->bss_num; 166 local_tx_pd->bss_type = priv->bss_type; 167 168 skb_push(skb, adapter->intf_hdr_len); 169 if (adapter->iface_type == MWIFIEX_USB) { 170 ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, 171 skb, NULL); 172 } else { 173 tx_param.next_pkt_len = 0; 174 ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, 175 skb, &tx_param); 176 } 177 switch (ret) { 178 case -EBUSY: 179 dev_kfree_skb_any(skb); 180 mwifiex_dbg(adapter, ERROR, 181 "%s: host_to_card failed: ret=%d\n", 182 __func__, ret); 183 adapter->dbg.num_tx_host_to_card_failure++; 184 break; 185 case -1: 186 dev_kfree_skb_any(skb); 187 mwifiex_dbg(adapter, ERROR, 188 "%s: host_to_card failed: ret=%d\n", 189 __func__, ret); 190 adapter->dbg.num_tx_host_to_card_failure++; 191 break; 192 case 0: 193 dev_kfree_skb_any(skb); 194 mwifiex_dbg(adapter, DATA, 195 "data: %s: host_to_card succeeded\n", 196 __func__); 197 adapter->tx_lock_flag = true; 198 break; 199 case -EINPROGRESS: 200 adapter->tx_lock_flag = true; 201 break; 202 default: 203 break; 204 } 205 206 return ret; 207 } 208 209 /* 210 * This function checks if we need to send last packet indication. 211 */ 212 u8 213 mwifiex_check_last_packet_indication(struct mwifiex_private *priv) 214 { 215 struct mwifiex_adapter *adapter = priv->adapter; 216 u8 ret = false; 217 218 if (!adapter->sleep_period.period) 219 return ret; 220 if (mwifiex_wmm_lists_empty(adapter)) 221 ret = true; 222 223 if (ret && !adapter->cmd_sent && !adapter->curr_cmd && 224 !is_command_pending(adapter)) { 225 adapter->delay_null_pkt = false; 226 ret = true; 227 } else { 228 ret = false; 229 adapter->delay_null_pkt = true; 230 } 231 return ret; 232 } 233