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