1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * NXP Wireless LAN device driver: station TX data handling 4 * 5 * Copyright 2011-2024 NXP 6 */ 7 8 #include "cfg.h" 9 #include "util.h" 10 #include "fw.h" 11 #include "main.h" 12 #include "cmdevt.h" 13 #include "wmm.h" 14 15 /* 16 * Fill TxPD for TX packets by inserting it before payload and setting required fields. 17 */ 18 void nxpwifi_process_sta_txpd(struct nxpwifi_private *priv, 19 struct sk_buff *skb) 20 { 21 struct nxpwifi_adapter *adapter = priv->adapter; 22 struct txpd *local_tx_pd; 23 struct nxpwifi_txinfo *tx_info = NXPWIFI_SKB_TXCB(skb); 24 unsigned int pad; 25 u16 pkt_type, pkt_length, pkt_offset; 26 int hroom = adapter->intf_hdr_len; 27 u32 tx_control; 28 29 pkt_type = nxpwifi_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; 30 31 pad = ((uintptr_t)skb->data - (sizeof(*local_tx_pd) + hroom)) & 32 (NXPWIFI_DMA_ALIGN_SZ - 1); 33 skb_push(skb, sizeof(*local_tx_pd) + pad); 34 35 local_tx_pd = (struct txpd *)skb->data; 36 memset(local_tx_pd, 0, sizeof(struct txpd)); 37 local_tx_pd->bss_num = priv->bss_num; 38 local_tx_pd->bss_type = priv->bss_type; 39 40 pkt_length = (u16)(skb->len - (sizeof(struct txpd) + pad)); 41 if (pkt_type == PKT_TYPE_MGMT) 42 pkt_length -= NXPWIFI_MGMT_FRAME_HEADER_SIZE; 43 local_tx_pd->tx_pkt_length = cpu_to_le16(pkt_length); 44 45 local_tx_pd->priority = (u8)skb->priority; 46 local_tx_pd->pkt_delay_2ms = 47 nxpwifi_wmm_compute_drv_pkt_delay(priv, skb); 48 49 if (tx_info->flags & NXPWIFI_BUF_FLAG_EAPOL_TX_STATUS || 50 tx_info->flags & NXPWIFI_BUF_FLAG_ACTION_TX_STATUS) { 51 local_tx_pd->tx_token_id = tx_info->ack_frame_id; 52 local_tx_pd->flags |= NXPWIFI_TXPD_FLAGS_REQ_TX_STATUS; 53 } 54 55 if (local_tx_pd->priority < 56 ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) { 57 /* 58 * Set the priority specific tx_control field, setting of 0 will 59 * cause the default value to be used later in this function 60 */ 61 tx_control = 62 priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd->priority]; 63 local_tx_pd->tx_control = cpu_to_le32(tx_control); 64 } 65 66 if (adapter->pps_uapsd_mode) { 67 if (nxpwifi_check_last_packet_indication(priv)) { 68 adapter->tx_lock_flag = true; 69 local_tx_pd->flags = 70 NXPWIFI_TxPD_POWER_MGMT_LAST_PACKET; 71 } 72 } 73 74 /* Offset of actual data */ 75 pkt_offset = sizeof(struct txpd) + pad; 76 if (pkt_type == PKT_TYPE_MGMT) { 77 /* Set the packet type and add header for management frame */ 78 local_tx_pd->tx_pkt_type = cpu_to_le16(pkt_type); 79 pkt_offset += NXPWIFI_MGMT_FRAME_HEADER_SIZE; 80 } 81 82 local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); 83 84 /* make space for adapter->intf_hdr_len */ 85 skb_push(skb, hroom); 86 87 if (!local_tx_pd->tx_control) 88 /* TxCtrl set by user or default */ 89 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); 90 } 91 92 /* Send a NULL-data frame with TxPD at highest priority. */ 93 int nxpwifi_send_null_packet(struct nxpwifi_private *priv, u8 flags) 94 { 95 struct nxpwifi_adapter *adapter = priv->adapter; 96 struct txpd *local_tx_pd; 97 struct nxpwifi_tx_param tx_param; 98 /* sizeof(struct txpd) + Interface specific header */ 99 #define NULL_PACKET_HDR 64 100 u32 data_len = NULL_PACKET_HDR; 101 struct sk_buff *skb; 102 int ret; 103 struct nxpwifi_txinfo *tx_info = NULL; 104 105 if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) 106 return -EPERM; 107 108 if (!priv->media_connected) 109 return -EPERM; 110 111 if (adapter->data_sent) 112 return -EBUSY; 113 114 skb = dev_alloc_skb(data_len); 115 if (!skb) 116 return -ENOMEM; 117 118 tx_info = NXPWIFI_SKB_TXCB(skb); 119 memset(tx_info, 0, sizeof(*tx_info)); 120 tx_info->bss_num = priv->bss_num; 121 tx_info->bss_type = priv->bss_type; 122 tx_info->pkt_len = data_len - 123 (sizeof(struct txpd) + adapter->intf_hdr_len); 124 skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len); 125 skb_push(skb, sizeof(struct txpd)); 126 127 local_tx_pd = (struct txpd *)skb->data; 128 local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); 129 local_tx_pd->flags = flags; 130 local_tx_pd->priority = WMM_HIGHEST_PRIORITY; 131 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); 132 local_tx_pd->bss_num = priv->bss_num; 133 local_tx_pd->bss_type = priv->bss_type; 134 135 skb_push(skb, adapter->intf_hdr_len); 136 tx_param.next_pkt_len = 0; 137 ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_DATA, 138 skb, &tx_param); 139 140 switch (ret) { 141 case -EBUSY: 142 dev_kfree_skb_any(skb); 143 nxpwifi_dbg(adapter, ERROR, 144 "%s: host_to_card failed: ret=%d\n", 145 __func__, ret); 146 adapter->dbg.num_tx_host_to_card_failure++; 147 break; 148 case 0: 149 dev_kfree_skb_any(skb); 150 nxpwifi_dbg(adapter, DATA, 151 "data: %s: host_to_card succeeded\n", 152 __func__); 153 adapter->tx_lock_flag = true; 154 break; 155 case -EINPROGRESS: 156 adapter->tx_lock_flag = true; 157 break; 158 default: 159 dev_kfree_skb_any(skb); 160 nxpwifi_dbg(adapter, ERROR, 161 "%s: host_to_card failed: ret=%d\n", 162 __func__, ret); 163 adapter->dbg.num_tx_host_to_card_failure++; 164 break; 165 } 166 167 return ret; 168 } 169 170 /* Check whether a last‑packet indication needs to be sent. */ 171 u8 nxpwifi_check_last_packet_indication(struct nxpwifi_private *priv) 172 { 173 struct nxpwifi_adapter *adapter = priv->adapter; 174 u8 ret = false; 175 176 if (!adapter->sleep_period.period) 177 return ret; 178 if (nxpwifi_wmm_lists_empty(adapter)) 179 ret = true; 180 181 if (ret && !adapter->cmd_sent && !adapter->curr_cmd && 182 !nxpwifi_is_command_pending(adapter)) { 183 adapter->delay_null_pkt = false; 184 ret = true; 185 } else { 186 ret = false; 187 adapter->delay_null_pkt = true; 188 } 189 return ret; 190 } 191