1 /* 2 * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* OS abstraction libraries */ 21 #include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */ 22 #include <qdf_atomic.h> /* qdf_atomic_read, etc. */ 23 #include <qdf_util.h> /* qdf_unlikely */ 24 25 /* APIs for other modules */ 26 #include <htt.h> /* HTT_TX_EXT_TID_MGMT */ 27 #include <ol_htt_tx_api.h> /* htt_tx_desc_tid */ 28 29 /* internal header files relevant for all systems */ 30 #include <ol_txrx_internal.h> /* TXRX_ASSERT1 */ 31 #include <ol_tx_desc.h> /* ol_tx_desc */ 32 #include <ol_tx_send.h> /* ol_tx_send */ 33 #include <ol_txrx.h> 34 35 /* internal header files relevant only for HL systems */ 36 #include <ol_tx_classify.h> /* ol_tx_classify, ol_tx_classify_mgmt */ 37 #include <ol_tx_queue.h> /* ol_tx_enqueue */ 38 #include <ol_tx_sched.h> /* ol_tx_sched */ 39 40 /* internal header files relevant only for specific systems (Pronto) */ 41 #include <ol_txrx_encap.h> /* OL_TX_ENCAP, etc */ 42 #include <ol_tx.h> 43 #include <cdp_txrx_ipa.h> 44 45 /** 46 * ol_tx_data() - send data frame 47 * @soc_hdl: datapath soc handle 48 * @vdev_id: virtual interface id 49 * @skb: skb 50 * 51 * Return: skb/NULL for success 52 */ ol_tx_data(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t skb)53 qdf_nbuf_t ol_tx_data(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, 54 qdf_nbuf_t skb) 55 { 56 struct ol_txrx_pdev_t *pdev; 57 qdf_nbuf_t ret; 58 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); 59 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, 60 vdev_id); 61 62 if (qdf_unlikely(!vdev)) { 63 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, 64 "%s:vdev is null", __func__); 65 return skb; 66 } 67 68 pdev = vdev->pdev; 69 70 if (qdf_unlikely(!pdev)) { 71 QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, 72 "%s:pdev is null", __func__); 73 return skb; 74 } 75 76 if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) 77 && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) 78 && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) 79 qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); 80 81 /* Terminate the (single-element) list of tx frames */ 82 qdf_nbuf_set_next(skb, NULL); 83 ret = OL_TX_SEND(vdev, skb); 84 if (ret) { 85 ol_txrx_dbg("Failed to tx"); 86 return ret; 87 } 88 89 return NULL; 90 } 91 92 #ifdef IPA_OFFLOAD ol_tx_send_ipa_data_frame(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t skb)93 qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, 94 qdf_nbuf_t skb) 95 { 96 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); 97 struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id( 98 soc, OL_TXRX_PDEV_ID); 99 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, 100 vdev_id); 101 qdf_nbuf_t ret; 102 103 if (qdf_unlikely(!pdev)) { 104 ol_txrx_err("Invalid pdev"); 105 return skb; 106 } 107 if (qdf_unlikely(!vdev)) { 108 ol_txrx_err("Invalid vdev, vdev_id:%d", vdev_id); 109 return skb; 110 } 111 112 if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) 113 && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) 114 && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) 115 qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); 116 117 /* Terminate the (single-element) list of tx frames */ 118 qdf_nbuf_set_next(skb, NULL); 119 120 /* 121 * Add SKB to internal tracking table before further processing 122 * in WLAN driver. 123 */ 124 qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__); 125 126 ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb); 127 if (ret) { 128 ol_txrx_dbg("Failed to tx"); 129 return ret; 130 } 131 132 return NULL; 133 } 134 #endif 135 136 void ol_txrx_data_tx_cb_set(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,ol_txrx_data_tx_cb callback,void * ctxt)137 ol_txrx_data_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, 138 ol_txrx_data_tx_cb callback, void *ctxt) 139 { 140 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); 141 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, 142 vdev_id); 143 struct ol_txrx_pdev_t *pdev; 144 145 if (!vdev || !vdev->pdev) 146 return; 147 148 pdev = vdev->pdev; 149 pdev->tx_data_callback.func = callback; 150 pdev->tx_data_callback.ctxt = ctxt; 151 } 152 153 QDF_STATUS ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t * soc_hdl,uint8_t pdev_id,uint8_t type,ol_txrx_mgmt_tx_cb download_cb,ol_txrx_mgmt_tx_cb ota_ack_cb,void * ctxt)154 ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, uint8_t type, 155 ol_txrx_mgmt_tx_cb download_cb, 156 ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt) 157 { 158 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); 159 struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, 160 pdev_id); 161 162 if (!pdev) 163 return QDF_STATUS_E_FAILURE; 164 165 TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); 166 pdev->tx_mgmt_cb.download_cb = download_cb; 167 pdev->tx_mgmt_cb.ota_ack_cb = ota_ack_cb; 168 pdev->tx_mgmt_cb.ctxt = ctxt; 169 170 return QDF_STATUS_SUCCESS; 171 } 172 173 int ol_txrx_mgmt_send_ext(struct cdp_soc_t * soc_hdl,uint8_t vdev_id,qdf_nbuf_t tx_mgmt_frm,uint8_t type,uint8_t use_6mbps,uint16_t chanfreq)174 ol_txrx_mgmt_send_ext(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, 175 qdf_nbuf_t tx_mgmt_frm, uint8_t type, 176 uint8_t use_6mbps, uint16_t chanfreq) 177 { 178 struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); 179 ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, 180 vdev_id); 181 struct ol_txrx_pdev_t *pdev; 182 struct ol_tx_desc_t *tx_desc; 183 struct ol_txrx_msdu_info_t tx_msdu_info; 184 int result = 0; 185 186 if (!vdev || !vdev->pdev) 187 return QDF_STATUS_E_FAULT; 188 189 pdev = vdev->pdev; 190 tx_msdu_info.tso_info.is_tso = 0; 191 192 tx_msdu_info.htt.action.use_6mbps = use_6mbps; 193 tx_msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; 194 tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; 195 tx_msdu_info.htt.action.do_tx_complete = 196 pdev->tx_mgmt_cb.ota_ack_cb ? 1 : 0; 197 198 /* 199 * FIX THIS: l2_hdr_type should only specify L2 header type 200 * The Peregrine/Rome HTT layer provides the FW with a "pkt type" 201 * that is a combination of L2 header type and 802.11 frame type. 202 * If the 802.11 frame type is "mgmt", then the HTT pkt type is "mgmt". 203 * But if the 802.11 frame type is "data", then the HTT pkt type is 204 * the L2 header type (more or less): 802.3 vs. Native WiFi 205 * (basic 802.11). 206 * (Or the header type can be "raw", which is any version of the 802.11 207 * header, and also implies that some of the offloaded tx data 208 * processing steps may not apply.) 209 * For efficiency, the Peregrine/Rome HTT uses the msdu_info's 210 * l2_hdr_type field to program the HTT pkt type. Thus, this txrx SW 211 * needs to overload the l2_hdr_type to indicate whether the frame is 212 * data vs. mgmt, as well as 802.3 L2 header vs. 802.11 L2 header. 213 * To fix this, the msdu_info's l2_hdr_type should be left specifying 214 * just the L2 header type. For mgmt frames, there should be a 215 * separate function to patch the HTT pkt type to store a "mgmt" value 216 * rather than the L2 header type. Then the HTT pkt type can be 217 * programmed efficiently for data frames, and the msdu_info's 218 * l2_hdr_type field won't be confusingly overloaded to hold the 802.11 219 * frame type rather than the L2 header type. 220 */ 221 /* 222 * FIX THIS: remove duplication of htt_frm_type_mgmt and 223 * htt_pkt_type_mgmt 224 * The htt module expects a "enum htt_pkt_type" value. 225 * The htt_dxe module expects a "enum htt_frm_type" value. 226 * This needs to be cleaned up, so both versions of htt use a 227 * consistent method of specifying the frame type. 228 */ 229 #ifdef QCA_SUPPORT_INTEGRATED_SOC 230 /* tx mgmt frames always come with a 802.11 header */ 231 tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_native_wifi; 232 tx_msdu_info.htt.info.frame_type = htt_frm_type_mgmt; 233 #else 234 tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_mgmt; 235 tx_msdu_info.htt.info.frame_type = htt_pkt_type_mgmt; 236 #endif 237 238 tx_msdu_info.peer = NULL; 239 240 tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm, 241 &tx_msdu_info); 242 if (!tx_desc) 243 return -EINVAL; /* can't accept the tx mgmt frame */ 244 245 TXRX_STATS_MSDU_INCR(pdev, tx.mgmt, tx_mgmt_frm); 246 TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); 247 tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE; 248 249 result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm, 250 &tx_msdu_info, chanfreq); 251 252 return 0; /* accepted the tx mgmt frame */ 253 } 254