1 /* 2 * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /*======================================================================== 20 21 \file epping_tx.c 22 23 \brief WLAN End Point Ping test tool implementation 24 25 ========================================================================*/ 26 27 /*-------------------------------------------------------------------------- 28 Include Files 29 ------------------------------------------------------------------------*/ 30 #include <cds_api.h> 31 #include <cds_sched.h> 32 #include <linux/etherdevice.h> 33 #include <linux/firmware.h> 34 #include <wni_api.h> 35 #include <wlan_ptt_sock_svc.h> 36 #include <linux/wireless.h> 37 #include <net/cfg80211.h> 38 #include <linux/rtnetlink.h> 39 #include <linux/semaphore.h> 40 #include <linux/ctype.h> 41 #include "epping_main.h" 42 #include "epping_internal.h" 43 #include "epping_test.h" 44 45 #define TX_RETRY_TIMEOUT_IN_MS 1 46 47 static bool enb_tx_dump; 48 49 void epping_tx_dup_pkt(epping_adapter_t *adapter, 50 HTC_ENDPOINT_ID eid, qdf_nbuf_t skb) 51 { 52 struct epping_cookie *cookie = NULL; 53 int skb_len, ret; 54 qdf_nbuf_t new_skb; 55 56 cookie = epping_alloc_cookie(adapter->pEpping_ctx); 57 if (!cookie) { 58 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 59 "%s: epping_alloc_cookie returns no resource\n", 60 __func__); 61 return; 62 } 63 new_skb = qdf_nbuf_copy(skb); 64 if (!new_skb) { 65 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 66 "%s: qdf_nbuf_copy returns no resource\n", __func__); 67 epping_free_cookie(adapter->pEpping_ctx, cookie); 68 return; 69 } 70 SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, 71 cookie, qdf_nbuf_data(skb), 72 qdf_nbuf_len(new_skb), eid, 0); 73 SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb); 74 skb_len = (int)qdf_nbuf_len(new_skb); 75 /* send the packet */ 76 ret = htc_send_pkt(adapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); 77 if (ret != QDF_STATUS_SUCCESS) { 78 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 79 "%s: htc_send_pkt failed, ret = %d\n", __func__, ret); 80 epping_free_cookie(adapter->pEpping_ctx, cookie); 81 qdf_nbuf_free(new_skb); 82 return; 83 } 84 adapter->stats.tx_bytes += skb_len; 85 ++adapter->stats.tx_packets; 86 if (((adapter->stats.tx_packets + 87 adapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && 88 (adapter->stats.tx_packets || adapter->stats.tx_dropped)) { 89 epping_log_stats(adapter, __func__); 90 } 91 } 92 93 static int epping_tx_send_int(qdf_nbuf_t skb, epping_adapter_t *adapter) 94 { 95 EPPING_HEADER *eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb); 96 HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED; 97 struct epping_cookie *cookie = NULL; 98 uint8_t ac = 0; 99 QDF_STATUS ret = QDF_STATUS_SUCCESS; 100 int skb_len; 101 EPPING_HEADER tmpHdr = *eppingHdr; 102 103 /* allocate resource for this packet */ 104 cookie = epping_alloc_cookie(adapter->pEpping_ctx); 105 /* no resource */ 106 if (!cookie) { 107 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 108 "%s: epping_alloc_cookie returns no resource\n", 109 __func__); 110 return A_ERROR; 111 } 112 113 if (enb_tx_dump) 114 epping_hex_dump((void *)eppingHdr, skb->len, __func__); 115 /* 116 * a quirk of linux, the payload of the frame is 32-bit aligned and thus 117 * the addition of the HTC header will mis-align the start of the HTC 118 * frame, so we add some padding which will be stripped off in the target 119 */ 120 if (EPPING_ALIGNMENT_PAD > 0) { 121 A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD); 122 } 123 /* prepare ep/HTC information */ 124 ac = eppingHdr->StreamNo_h; 125 eid = adapter->pEpping_ctx->EppingEndpoint[ac]; 126 if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) { 127 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 128 "%s: invalid eid = %d, ac = %d\n", __func__, eid, 129 ac); 130 return A_ERROR; 131 } 132 if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT || 133 tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) { 134 epping_set_kperf_flag(adapter, eid, tmpHdr.CmdBuffer_t[0]); 135 } 136 SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, 137 cookie, qdf_nbuf_data(skb), qdf_nbuf_len(skb), 138 eid, 0); 139 SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb); 140 skb_len = skb->len; 141 /* send the packet */ 142 ret = htc_send_pkt(adapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); 143 epping_log_packet(adapter, &tmpHdr, ret, __func__); 144 if (ret != QDF_STATUS_SUCCESS) { 145 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 146 "%s: htc_send_pkt failed, status = %d\n", __func__, 147 ret); 148 epping_free_cookie(adapter->pEpping_ctx, cookie); 149 return A_ERROR; 150 } 151 adapter->stats.tx_bytes += skb_len; 152 ++adapter->stats.tx_packets; 153 if (((adapter->stats.tx_packets + 154 adapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && 155 (adapter->stats.tx_packets || adapter->stats.tx_dropped)) { 156 epping_log_stats(adapter, __func__); 157 } 158 159 return 0; 160 } 161 162 void epping_tx_timer_expire(epping_adapter_t *adapter) 163 { 164 qdf_nbuf_t nodrop_skb; 165 166 EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__, 167 qdf_nbuf_queue_len(&adapter->nodrop_queue)); 168 169 if (!qdf_nbuf_queue_len(&adapter->nodrop_queue)) { 170 /* nodrop queue is empty so no need to arm timer */ 171 adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; 172 return; 173 } 174 175 /* try to flush nodrop queue */ 176 while ((nodrop_skb = qdf_nbuf_queue_remove(&adapter->nodrop_queue))) { 177 htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, true); 178 if (epping_tx_send_int(nodrop_skb, adapter)) { 179 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 180 "%s: nodrop: %pK xmit fail in timer\n", 181 __func__, nodrop_skb); 182 /* fail to xmit so put the nodrop packet to the nodrop queue */ 183 qdf_nbuf_queue_insert_head(&adapter->nodrop_queue, 184 nodrop_skb); 185 break; 186 } else { 187 htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, false); 188 EPPING_LOG(QDF_TRACE_LEVEL_INFO, 189 "%s: nodrop: %pK xmit ok in timer\n", 190 __func__, nodrop_skb); 191 } 192 } 193 194 /* if nodrop queue is not empty, continue to arm timer */ 195 if (nodrop_skb) { 196 qdf_spin_lock_bh(&adapter->data_lock); 197 /* if nodrop queue is not empty, continue to arm timer */ 198 if (adapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { 199 adapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; 200 qdf_timer_mod(&adapter->epping_timer, 201 TX_RETRY_TIMEOUT_IN_MS); 202 } 203 qdf_spin_unlock_bh(&adapter->data_lock); 204 } else { 205 adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; 206 } 207 } 208 209 int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *adapter) 210 { 211 qdf_nbuf_t nodrop_skb; 212 EPPING_HEADER *eppingHdr; 213 uint8_t ac = 0; 214 215 eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb); 216 217 if (!IS_EPPING_PACKET(eppingHdr)) { 218 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 219 "%s: Recived non endpoint ping packets\n", __func__); 220 /* no packet to send, cleanup */ 221 qdf_nbuf_free(skb); 222 return -ENOMEM; 223 } 224 225 /* the stream ID is mapped to an access class */ 226 ac = eppingHdr->StreamNo_h; 227 /* hard coded two ep ids */ 228 if (ac != 0 && ac != 1) { 229 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 230 "%s: ac %d is not mapped to mboxping service\n", 231 __func__, ac); 232 qdf_nbuf_free(skb); 233 return -ENOMEM; 234 } 235 236 /* 237 * some EPPING packets cannot be dropped no matter what access class 238 * it was sent on. A special care has been taken: 239 * 1. when there is no TX resource, queue the control packets to 240 * a special queue 241 * 2. when there is TX resource, send the queued control packets first 242 * and then other packets 243 * 3. a timer launches to check if there is queued control packets and 244 * flush them 245 */ 246 247 /* check the nodrop queue first */ 248 while ((nodrop_skb = qdf_nbuf_queue_remove(&adapter->nodrop_queue))) { 249 htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, true); 250 if (epping_tx_send_int(nodrop_skb, adapter)) { 251 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 252 "%s: nodrop: %pK xmit fail\n", __func__, 253 nodrop_skb); 254 /* fail to xmit so put the nodrop packet to the nodrop queue */ 255 qdf_nbuf_queue_insert_head(&adapter->nodrop_queue, 256 nodrop_skb); 257 /* no cookie so free the current skb */ 258 goto tx_fail; 259 } else { 260 htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, false); 261 EPPING_LOG(QDF_TRACE_LEVEL_INFO, 262 "%s: nodrop: %pK xmit ok\n", __func__, 263 nodrop_skb); 264 } 265 } 266 267 /* send the original packet */ 268 if (epping_tx_send_int(skb, adapter)) 269 goto tx_fail; 270 271 return 0; 272 273 tx_fail: 274 if (!IS_EPING_PACKET_NO_DROP(eppingHdr)) { 275 /* allow to drop the skb so drop it */ 276 qdf_nbuf_free(skb); 277 ++adapter->stats.tx_dropped; 278 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 279 "%s: Tx skb %pK dropped, stats.tx_dropped = %ld\n", 280 __func__, skb, adapter->stats.tx_dropped); 281 return -ENOMEM; 282 } else { 283 EPPING_LOG(QDF_TRACE_LEVEL_FATAL, 284 "%s: nodrop: %pK queued\n", __func__, skb); 285 qdf_nbuf_queue_add(&adapter->nodrop_queue, skb); 286 qdf_spin_lock_bh(&adapter->data_lock); 287 if (adapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { 288 adapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; 289 qdf_timer_mod(&adapter->epping_timer, 290 TX_RETRY_TIMEOUT_IN_MS); 291 } 292 qdf_spin_unlock_bh(&adapter->data_lock); 293 } 294 295 return 0; 296 } 297 298 #ifdef HIF_SDIO 299 enum htc_send_full_action epping_tx_queue_full(void *Context, 300 HTC_PACKET *pPacket) 301 { 302 /* 303 * Call netif_stop_queue frequently will impact the mboxping tx t-put. 304 * Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid. 305 */ 306 return HTC_SEND_FULL_KEEP; 307 } 308 #endif /* HIF_SDIO */ 309 void epping_tx_complete(void *ctx, HTC_PACKET *htc_pkt) 310 { 311 epping_context_t *pEpping_ctx = (epping_context_t *) ctx; 312 epping_adapter_t *adapter = pEpping_ctx->epping_adapter; 313 struct net_device *dev = adapter->dev; 314 QDF_STATUS status; 315 HTC_ENDPOINT_ID eid; 316 qdf_nbuf_t pktSkb; 317 struct epping_cookie *cookie; 318 A_BOOL flushing = false; 319 qdf_nbuf_queue_t skb_queue; 320 321 if (!htc_pkt) 322 return; 323 324 qdf_nbuf_queue_init(&skb_queue); 325 326 qdf_spin_lock_bh(&adapter->data_lock); 327 328 status = htc_pkt->Status; 329 eid = htc_pkt->Endpoint; 330 pktSkb = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); 331 cookie = htc_pkt->pPktContext; 332 333 if (!pktSkb) { 334 EPPING_LOG(QDF_TRACE_LEVEL_ERROR, 335 "%s: NULL skb from hc packet", __func__); 336 QDF_BUG(0); 337 } else { 338 if (htc_pkt->pBuffer != qdf_nbuf_data(pktSkb)) { 339 EPPING_LOG(QDF_TRACE_LEVEL_ERROR, 340 "%s: htc_pkt buffer not equal to skb->data", 341 __func__); 342 QDF_BUG(0); 343 } 344 /* add this to the list, use faster non-lock API */ 345 qdf_nbuf_queue_add(&skb_queue, pktSkb); 346 347 if (QDF_IS_STATUS_SUCCESS(status)) { 348 if (htc_pkt->ActualLength != 349 qdf_nbuf_len(pktSkb)) { 350 EPPING_LOG(QDF_TRACE_LEVEL_ERROR, 351 "%s: htc_pkt length not equal to skb->len", 352 __func__); 353 QDF_BUG(0); 354 } 355 } 356 } 357 358 EPPING_LOG(QDF_TRACE_LEVEL_INFO, 359 "%s skb=%pK data=%pK len=0x%x eid=%d ", 360 __func__, pktSkb, htc_pkt->pBuffer, 361 htc_pkt->ActualLength, eid); 362 363 if (QDF_IS_STATUS_ERROR(status)) { 364 if (status == QDF_STATUS_E_CANCELED) { 365 /* a packet was flushed */ 366 flushing = true; 367 } 368 if (status != QDF_STATUS_E_RESOURCES) { 369 EPPING_LOG(QDF_TRACE_LEVEL_ERROR, 370 "%s() -TX ERROR, status: 0x%x", 371 __func__, status); 372 } 373 } else { 374 EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: OK\n", __func__); 375 flushing = false; 376 } 377 378 epping_free_cookie(adapter->pEpping_ctx, cookie); 379 qdf_spin_unlock_bh(&adapter->data_lock); 380 381 /* free all skbs in our local list */ 382 while (qdf_nbuf_queue_len(&skb_queue)) { 383 /* use non-lock version */ 384 pktSkb = qdf_nbuf_queue_remove(&skb_queue); 385 if (!pktSkb) 386 break; 387 qdf_nbuf_tx_free(pktSkb, QDF_NBUF_PKT_ERROR); 388 pEpping_ctx->total_tx_acks++; 389 } 390 391 if (!flushing) { 392 netif_wake_queue(dev); 393 } 394 } 395