1 /* 2 * Copyright (c) 2013-2020 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 #define ATH_MODULE_NAME hif 21 #include "a_debug.h" 22 23 #include <qdf_types.h> 24 #include <qdf_status.h> 25 #include <qdf_timer.h> 26 #include <qdf_time.h> 27 #include <qdf_lock.h> 28 #include <qdf_mem.h> 29 #include <qdf_util.h> 30 #include <qdf_defer.h> 31 #include <qdf_atomic.h> 32 #include <qdf_nbuf.h> 33 #include <athdefs.h> 34 #include <qdf_net_types.h> 35 #include <a_types.h> 36 #include <athdefs.h> 37 #include <a_osapi.h> 38 #include <hif.h> 39 #include <htc_services.h> 40 #include "hif_sdio_internal.h" 41 #include "if_sdio.h" 42 #include "regtable_sdio.h" 43 44 /** 45 * hif_dev_alloc_rx_buffer() - allocate rx buffer. 46 * @pdev: sdio device context 47 * 48 * 49 * Return: htc buffer pointer 50 */ 51 HTC_PACKET *hif_dev_alloc_rx_buffer(struct hif_sdio_device *pdev) 52 { 53 HTC_PACKET *packet; 54 qdf_nbuf_t netbuf; 55 uint32_t bufsize = 0, headsize = 0; 56 57 bufsize = HIF_SDIO_RX_BUFFER_SIZE + HIF_SDIO_RX_DATA_OFFSET; 58 headsize = sizeof(HTC_PACKET); 59 netbuf = qdf_nbuf_alloc(NULL, bufsize + headsize, 0, 4, false); 60 if (!netbuf) { 61 hif_err_rl("Allocate netbuf failed"); 62 return NULL; 63 } 64 packet = (HTC_PACKET *) qdf_nbuf_data(netbuf); 65 qdf_nbuf_reserve(netbuf, headsize); 66 67 SET_HTC_PACKET_INFO_RX_REFILL(packet, 68 pdev, 69 qdf_nbuf_data(netbuf), 70 bufsize, ENDPOINT_0); 71 SET_HTC_PACKET_NET_BUF_CONTEXT(packet, netbuf); 72 return packet; 73 } 74 75 /** 76 * hif_dev_create() - create hif device after probe. 77 * @hif_device: HIF context 78 * @callbacks: htc callbacks 79 * @target: HIF target 80 * 81 * 82 * Return: int 83 */ 84 struct hif_sdio_device *hif_dev_create(struct hif_sdio_dev *hif_device, 85 struct hif_msg_callbacks *callbacks, void *target) 86 { 87 88 QDF_STATUS status; 89 struct hif_sdio_device *pdev; 90 91 HIF_ENTER(); 92 pdev = qdf_mem_malloc(sizeof(struct hif_sdio_device)); 93 if (!pdev) { 94 A_ASSERT(false); 95 return NULL; 96 } 97 98 qdf_spinlock_create(&pdev->Lock); 99 qdf_spinlock_create(&pdev->TxLock); 100 qdf_spinlock_create(&pdev->RxLock); 101 102 pdev->HIFDevice = hif_device; 103 pdev->pTarget = target; 104 status = hif_configure_device(NULL, hif_device, 105 HIF_DEVICE_SET_HTC_CONTEXT, 106 (void *)pdev, sizeof(pdev)); 107 if (status != QDF_STATUS_SUCCESS) 108 hif_err("set context failed"); 109 110 A_MEMCPY(&pdev->hif_callbacks, callbacks, sizeof(*callbacks)); 111 112 HIF_EXIT(); 113 return pdev; 114 } 115 116 /** 117 * hif_dev_destroy() - destroy hif device. 118 * @pdev: sdio device context 119 * 120 * 121 * Return: none 122 */ 123 void hif_dev_destroy(struct hif_sdio_device *pdev) 124 { 125 QDF_STATUS status; 126 127 status = hif_configure_device(NULL, pdev->HIFDevice, 128 HIF_DEVICE_SET_HTC_CONTEXT, 129 (void *)NULL, 0); 130 if (status != QDF_STATUS_SUCCESS) 131 hif_err("set context failed"); 132 133 qdf_mem_free(pdev); 134 } 135 136 /** 137 * hif_dev_from_hif() - get sdio device from hif device. 138 * @hif_device: hif device context 139 * 140 * 141 * Return: hif sdio device context 142 */ 143 struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device) 144 { 145 struct hif_sdio_device *pdev = NULL; 146 QDF_STATUS status; 147 148 status = hif_configure_device(NULL, hif_device, 149 HIF_DEVICE_GET_HTC_CONTEXT, 150 (void **)&pdev, 151 sizeof(struct hif_sdio_device)); 152 if (status != QDF_STATUS_SUCCESS) 153 hif_err("set context failed"); 154 155 return pdev; 156 } 157 158 /** 159 * hif_dev_disable_interrupts() - disable hif device interrupts. 160 * @pdev: sdio device context 161 * 162 * 163 * Return: int 164 */ 165 QDF_STATUS hif_dev_disable_interrupts(struct hif_sdio_device *pdev) 166 { 167 QDF_STATUS status = QDF_STATUS_SUCCESS; 168 169 HIF_ENTER(); 170 171 hif_dev_mask_interrupts(pdev); 172 173 /* To Do mask the host controller interrupts */ 174 hif_mask_interrupt(pdev->HIFDevice); 175 176 HIF_EXIT(); 177 return status; 178 } 179 180 /** 181 * hif_dev_enable_interrupts() - enables hif device interrupts. 182 * @pdev: sdio device context 183 * 184 * 185 * Return: int 186 */ 187 QDF_STATUS hif_dev_enable_interrupts(struct hif_sdio_device *pdev) 188 { 189 QDF_STATUS status; 190 191 HIF_ENTER(); 192 193 /* for good measure, make sure interrupt are disabled 194 * before unmasking at the HIF layer. 195 * The rationale here is that between device insertion 196 * (where we clear the interrupts the first time) 197 * and when HTC is finally ready to handle interrupts, 198 * other software can perform target "soft" resets. 199 */ 200 status = hif_dev_disable_interrupts(pdev); 201 202 /* Unmask the host controller interrupts */ 203 hif_un_mask_interrupt(pdev->HIFDevice); 204 205 hif_dev_unmask_interrupts(pdev); 206 207 HIF_EXIT(); 208 209 return status; 210 } 211 212 /** 213 * hif_dev_setup() - set up sdio device. 214 * @pdev: sdio device context 215 * 216 * 217 * Return: int 218 */ 219 QDF_STATUS hif_dev_setup(struct hif_sdio_device *pdev) 220 { 221 QDF_STATUS status; 222 struct htc_callbacks htc_cbs; 223 struct hif_sdio_dev *hif_device = pdev->HIFDevice; 224 225 HIF_ENTER(); 226 227 status = hif_dev_setup_device(pdev); 228 229 if (status != QDF_STATUS_SUCCESS) { 230 hif_err("device specific setup failed"); 231 return QDF_STATUS_E_INVAL; 232 } 233 234 pdev->BlockMask = pdev->BlockSize - 1; 235 A_ASSERT((pdev->BlockSize & pdev->BlockMask) == 0); 236 237 /* assume we can process HIF interrupt events asynchronously */ 238 pdev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC; 239 240 /* see if the HIF layer overrides this assumption */ 241 hif_configure_device(NULL, hif_device, 242 HIF_DEVICE_GET_IRQ_PROC_MODE, 243 &pdev->HifIRQProcessingMode, 244 sizeof(pdev->HifIRQProcessingMode)); 245 246 switch (pdev->HifIRQProcessingMode) { 247 case HIF_DEVICE_IRQ_SYNC_ONLY: 248 AR_DEBUG_PRINTF(ATH_DEBUG_WARN, 249 ("HIF Interrupt processing is SYNC ONLY\n")); 250 /* see if HIF layer wants HTC to yield */ 251 hif_configure_device(NULL, hif_device, 252 HIF_DEVICE_GET_IRQ_YIELD_PARAMS, 253 &pdev->HifIRQYieldParams, 254 sizeof(pdev->HifIRQYieldParams)); 255 256 if (pdev->HifIRQYieldParams.recv_packet_yield_count > 0) { 257 AR_DEBUG_PRINTF(ATH_DEBUG_WARN, 258 ("HIF req of DSR yield per %d RECV packets\n", 259 pdev->HifIRQYieldParams. 260 recv_packet_yield_count)); 261 pdev->DSRCanYield = true; 262 } 263 break; 264 case HIF_DEVICE_IRQ_ASYNC_SYNC: 265 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, 266 ("HIF Interrupt processing is ASYNC and SYNC\n")); 267 break; 268 default: 269 A_ASSERT(false); 270 break; 271 } 272 273 pdev->HifMaskUmaskRecvEvent = NULL; 274 275 /* see if the HIF layer implements the mask/unmask recv 276 * events function 277 */ 278 hif_configure_device(NULL, hif_device, 279 HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC, 280 &pdev->HifMaskUmaskRecvEvent, 281 sizeof(pdev->HifMaskUmaskRecvEvent)); 282 283 status = hif_dev_disable_interrupts(pdev); 284 285 qdf_mem_zero(&htc_cbs, sizeof(struct htc_callbacks)); 286 /* the device layer handles these */ 287 htc_cbs.rw_compl_handler = hif_dev_rw_completion_handler; 288 htc_cbs.dsr_handler = hif_dev_dsr_handler; 289 htc_cbs.context = pdev; 290 status = hif_attach_htc(pdev->HIFDevice, &htc_cbs); 291 292 HIF_EXIT(); 293 return status; 294 } 295