Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 1 | /* |
Komal Seelam | b3a3bdf | 2016-02-01 19:22:17 +0530 | [diff] [blame] | 2 | * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 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 | #include <osdep.h> |
| 29 | #include "a_types.h" |
| 30 | #include "athdefs.h" |
| 31 | #include "osapi_linux.h" |
| 32 | #include "targcfg.h" |
| 33 | #include "cdf_lock.h" |
| 34 | #include "cdf_status.h" |
| 35 | #include <cdf_atomic.h> /* cdf_atomic_read */ |
| 36 | #include <targaddrs.h> |
| 37 | #include <bmi_msg.h> |
| 38 | #include "hif_io32.h" |
| 39 | #include <hif.h> |
| 40 | #include "regtable.h" |
| 41 | #define ATH_MODULE_NAME hif |
| 42 | #include <a_debug.h> |
| 43 | #include "hif_main.h" |
| 44 | #include "ce_api.h" |
| 45 | #include "cdf_trace.h" |
| 46 | #include "cds_api.h" |
| 47 | #ifdef CONFIG_CNSS |
| 48 | #include <net/cnss.h> |
| 49 | #else |
| 50 | #include "cnss_stub.h" |
| 51 | #endif |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 52 | #include "epping_main.h" |
| 53 | #include "hif_debug.h" |
| 54 | |
| 55 | /* Track a BMI transaction that is in progress */ |
| 56 | #ifndef BIT |
| 57 | #define BIT(n) (1 << (n)) |
| 58 | #endif |
| 59 | |
| 60 | enum { |
| 61 | BMI_REQ_SEND_DONE = BIT(0), /* the bmi tx completion */ |
| 62 | BMI_RESP_RECV_DONE = BIT(1), /* the bmi respond is received */ |
| 63 | }; |
| 64 | |
| 65 | struct BMI_transaction { |
| 66 | struct HIF_CE_state *hif_state; |
| 67 | cdf_semaphore_t bmi_transaction_sem; |
| 68 | uint8_t *bmi_request_host; /* Req BMI msg in Host addr space */ |
| 69 | cdf_dma_addr_t bmi_request_CE; /* Req BMI msg in CE addr space */ |
| 70 | uint32_t bmi_request_length; /* Length of BMI request */ |
| 71 | uint8_t *bmi_response_host; /* Rsp BMI msg in Host addr space */ |
| 72 | cdf_dma_addr_t bmi_response_CE; /* Rsp BMI msg in CE addr space */ |
| 73 | unsigned int bmi_response_length; /* Length of received response */ |
| 74 | unsigned int bmi_timeout_ms; |
| 75 | uint32_t bmi_transaction_flags; /* flags for the transcation */ |
| 76 | }; |
| 77 | |
| 78 | /* |
| 79 | * send/recv completion functions for BMI. |
| 80 | * NB: The "net_buf" parameter is actually just a |
| 81 | * straight buffer, not an sk_buff. |
| 82 | */ |
| 83 | void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context, |
| 84 | void *transfer_context, cdf_dma_addr_t data, |
| 85 | unsigned int nbytes, |
| 86 | unsigned int transfer_id, unsigned int sw_index, |
| 87 | unsigned int hw_index, uint32_t toeplitz_hash_result) |
| 88 | { |
| 89 | struct BMI_transaction *transaction = |
| 90 | (struct BMI_transaction *)transfer_context; |
Komal Seelam | 02cf2f8 | 2016-02-22 20:44:25 +0530 | [diff] [blame^] | 91 | struct ol_softc *scn = HIF_GET_SOFTC(transaction->hif_state); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 92 | |
| 93 | #ifdef BMI_RSP_POLLING |
| 94 | /* |
| 95 | * Fix EV118783, Release a semaphore after sending |
| 96 | * no matter whether a response is been expecting now. |
| 97 | */ |
| 98 | cdf_semaphore_release(scn->cdf_dev, |
| 99 | &transaction->bmi_transaction_sem); |
| 100 | #else |
| 101 | /* |
| 102 | * If a response is anticipated, we'll complete the |
| 103 | * transaction if the response has been received. |
| 104 | * If no response is anticipated, complete the |
| 105 | * transaction now. |
| 106 | */ |
| 107 | transaction->bmi_transaction_flags |= BMI_REQ_SEND_DONE; |
| 108 | |
| 109 | /* resp is't needed or has already been received, |
| 110 | * never assume resp comes later then this */ |
| 111 | if (!transaction->bmi_response_CE || |
| 112 | (transaction->bmi_transaction_flags & BMI_RESP_RECV_DONE)) { |
| 113 | cdf_semaphore_release(scn->cdf_dev, |
| 114 | &transaction->bmi_transaction_sem); |
| 115 | } |
| 116 | #endif |
| 117 | } |
| 118 | |
| 119 | #ifndef BMI_RSP_POLLING |
| 120 | void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context, |
| 121 | void *transfer_context, cdf_dma_addr_t data, |
| 122 | unsigned int nbytes, |
| 123 | unsigned int transfer_id, unsigned int flags) |
| 124 | { |
| 125 | struct BMI_transaction *transaction = |
| 126 | (struct BMI_transaction *)transfer_context; |
Komal Seelam | 02cf2f8 | 2016-02-22 20:44:25 +0530 | [diff] [blame^] | 127 | struct ol_softc *scn = HIF_GET_SOFTC(transaction->hif_state); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 128 | |
| 129 | transaction->bmi_response_length = nbytes; |
| 130 | transaction->bmi_transaction_flags |= BMI_RESP_RECV_DONE; |
| 131 | |
| 132 | /* when both send/recv are done, the sem can be released */ |
| 133 | if (transaction->bmi_transaction_flags & BMI_REQ_SEND_DONE) { |
| 134 | cdf_semaphore_release(scn->cdf_dev, |
| 135 | &transaction->bmi_transaction_sem); |
| 136 | } |
| 137 | } |
| 138 | #endif |
| 139 | |
Komal Seelam | 02cf2f8 | 2016-02-22 20:44:25 +0530 | [diff] [blame^] | 140 | CDF_STATUS hif_exchange_bmi_msg(struct ol_softc *hif_ctx, |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 141 | uint8_t *bmi_request, |
| 142 | uint32_t request_length, |
| 143 | uint8_t *bmi_response, |
| 144 | uint32_t *bmi_response_lengthp, uint32_t TimeoutMS) |
| 145 | { |
Komal Seelam | 02cf2f8 | 2016-02-22 20:44:25 +0530 | [diff] [blame^] | 146 | struct ol_softc *scn = HIF_GET_SOFTC(hif_ctx); |
| 147 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 148 | struct HIF_CE_pipe_info *send_pipe_info = |
| 149 | &(hif_state->pipe_info[BMI_CE_NUM_TO_TARG]); |
| 150 | struct CE_handle *ce_send_hdl = send_pipe_info->ce_hdl; |
| 151 | cdf_dma_addr_t CE_request, CE_response = 0; |
| 152 | struct BMI_transaction *transaction = NULL; |
| 153 | int status = CDF_STATUS_SUCCESS; |
| 154 | struct HIF_CE_pipe_info *recv_pipe_info = |
| 155 | &(hif_state->pipe_info[BMI_CE_NUM_TO_HOST]); |
| 156 | struct CE_handle *ce_recv = recv_pipe_info->ce_hdl; |
| 157 | unsigned int mux_id = 0; |
| 158 | unsigned int transaction_id = 0xffff; |
| 159 | unsigned int user_flags = 0; |
Komal Seelam | b3a3bdf | 2016-02-01 19:22:17 +0530 | [diff] [blame] | 160 | struct bmi_info *info = hif_get_bmi_ctx(scn); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 161 | #ifdef BMI_RSP_POLLING |
| 162 | cdf_dma_addr_t buf; |
| 163 | unsigned int completed_nbytes, id, flags; |
| 164 | int i; |
| 165 | #endif |
| 166 | |
| 167 | transaction = |
| 168 | (struct BMI_transaction *)cdf_mem_malloc(sizeof(*transaction)); |
| 169 | if (unlikely(!transaction)) { |
| 170 | HIF_ERROR("%s: no memory", __func__); |
| 171 | return CDF_STATUS_E_NOMEM; |
| 172 | } |
| 173 | transaction_id = (mux_id & MUX_ID_MASK) | |
| 174 | (transaction_id & TRANSACTION_ID_MASK); |
| 175 | #ifdef QCA_WIFI_3_0 |
| 176 | user_flags &= DESC_DATA_FLAG_MASK; |
| 177 | #endif |
| 178 | A_TARGET_ACCESS_LIKELY(scn); |
| 179 | |
| 180 | /* Initialize bmi_transaction_sem to block */ |
| 181 | cdf_semaphore_init(&transaction->bmi_transaction_sem); |
| 182 | cdf_semaphore_acquire(scn->cdf_dev, &transaction->bmi_transaction_sem); |
| 183 | |
| 184 | transaction->hif_state = hif_state; |
| 185 | transaction->bmi_request_host = bmi_request; |
| 186 | transaction->bmi_request_length = request_length; |
| 187 | transaction->bmi_response_length = 0; |
| 188 | transaction->bmi_timeout_ms = TimeoutMS; |
| 189 | transaction->bmi_transaction_flags = 0; |
| 190 | |
| 191 | /* |
| 192 | * CE_request = dma_map_single(dev, |
| 193 | * (void *)bmi_request, request_length, DMA_TO_DEVICE); |
| 194 | */ |
Komal Seelam | b3a3bdf | 2016-02-01 19:22:17 +0530 | [diff] [blame] | 195 | CE_request = info->bmi_cmd_da; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 196 | transaction->bmi_request_CE = CE_request; |
| 197 | |
| 198 | if (bmi_response) { |
| 199 | |
| 200 | /* |
| 201 | * CE_response = dma_map_single(dev, bmi_response, |
| 202 | * BMI_DATASZ_MAX, DMA_FROM_DEVICE); |
| 203 | */ |
Komal Seelam | b3a3bdf | 2016-02-01 19:22:17 +0530 | [diff] [blame] | 204 | CE_response = info->bmi_rsp_da; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 205 | transaction->bmi_response_host = bmi_response; |
| 206 | transaction->bmi_response_CE = CE_response; |
| 207 | /* dma_cache_sync(dev, bmi_response, |
| 208 | BMI_DATASZ_MAX, DMA_FROM_DEVICE); */ |
| 209 | cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, |
| 210 | CE_response, |
| 211 | BMI_DATASZ_MAX, |
| 212 | DMA_FROM_DEVICE); |
| 213 | ce_recv_buf_enqueue(ce_recv, transaction, |
| 214 | transaction->bmi_response_CE); |
| 215 | /* NB: see HIF_BMI_recv_done */ |
| 216 | } else { |
| 217 | transaction->bmi_response_host = NULL; |
| 218 | transaction->bmi_response_CE = 0; |
| 219 | } |
| 220 | |
| 221 | /* dma_cache_sync(dev, bmi_request, request_length, DMA_TO_DEVICE); */ |
| 222 | cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_request, |
| 223 | request_length, DMA_TO_DEVICE); |
| 224 | |
| 225 | status = |
| 226 | ce_send(ce_send_hdl, transaction, |
| 227 | CE_request, request_length, |
| 228 | transaction_id, 0, user_flags); |
| 229 | ASSERT(status == CDF_STATUS_SUCCESS); |
| 230 | /* NB: see hif_bmi_send_done */ |
| 231 | |
| 232 | /* TBDXXX: handle timeout */ |
| 233 | |
| 234 | /* Wait for BMI request/response transaction to complete */ |
| 235 | /* Always just wait for BMI request here if |
| 236 | * BMI_RSP_POLLING is defined */ |
| 237 | while (cdf_semaphore_acquire |
| 238 | (scn->cdf_dev, &transaction->bmi_transaction_sem)) { |
| 239 | /*need some break out condition(time out?) */ |
| 240 | } |
| 241 | |
| 242 | if (bmi_response) { |
| 243 | #ifdef BMI_RSP_POLLING |
| 244 | /* Fix EV118783, do not wait a semaphore for the BMI response |
| 245 | * since the relative interruption may be lost. |
| 246 | * poll the BMI response instead. |
| 247 | */ |
| 248 | i = 0; |
| 249 | while (ce_completed_recv_next( |
| 250 | ce_recv, NULL, NULL, &buf, |
| 251 | &completed_nbytes, &id, |
| 252 | &flags) != CDF_STATUS_SUCCESS) { |
| 253 | if (i++ > BMI_RSP_TO_MILLISEC) { |
| 254 | HIF_ERROR("%s:error, can't get bmi response\n", |
| 255 | __func__); |
| 256 | status = CDF_STATUS_E_BUSY; |
| 257 | break; |
| 258 | } |
| 259 | OS_DELAY(1000); |
| 260 | } |
| 261 | |
| 262 | if ((status == CDF_STATUS_SUCCESS) && bmi_response_lengthp) |
| 263 | *bmi_response_lengthp = completed_nbytes; |
| 264 | #else |
| 265 | if ((status == CDF_STATUS_SUCCESS) && bmi_response_lengthp) { |
| 266 | *bmi_response_lengthp = |
| 267 | transaction->bmi_response_length; |
| 268 | } |
| 269 | #endif |
| 270 | |
| 271 | } |
| 272 | |
| 273 | /* dma_unmap_single(dev, transaction->bmi_request_CE, |
| 274 | request_length, DMA_TO_DEVICE); */ |
| 275 | /* bus_unmap_single(scn->sc_osdev, |
| 276 | transaction->bmi_request_CE, |
| 277 | request_length, BUS_DMA_TODEVICE); */ |
| 278 | |
| 279 | if (status != CDF_STATUS_SUCCESS) { |
| 280 | cdf_dma_addr_t unused_buffer; |
| 281 | unsigned int unused_nbytes; |
| 282 | unsigned int unused_id; |
| 283 | unsigned int toeplitz_hash_result; |
| 284 | |
| 285 | ce_cancel_send_next(ce_send_hdl, |
| 286 | NULL, NULL, &unused_buffer, |
| 287 | &unused_nbytes, &unused_id, |
| 288 | &toeplitz_hash_result); |
| 289 | } |
| 290 | |
| 291 | A_TARGET_ACCESS_UNLIKELY(scn); |
| 292 | cdf_mem_free(transaction); |
| 293 | return status; |
| 294 | } |