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