Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 1 | /** |
| 2 | * Copyright (c) 2014 Redpine Signals Inc. |
| 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above |
| 6 | * copyright notice and this permission notice appear in all copies. |
| 7 | * |
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 15 | * |
| 16 | */ |
| 17 | |
| 18 | #include <linux/firmware.h> |
| 19 | #include "rsi_sdio.h" |
| 20 | #include "rsi_common.h" |
| 21 | |
| 22 | /** |
| 23 | * rsi_sdio_master_access_msword() - This function sets the AHB master access |
| 24 | * MS word in the SDIO slave registers. |
| 25 | * @adapter: Pointer to the adapter structure. |
| 26 | * @ms_word: ms word need to be initialized. |
| 27 | * |
| 28 | * Return: status: 0 on success, -1 on failure. |
| 29 | */ |
| 30 | static int rsi_sdio_master_access_msword(struct rsi_hw *adapter, |
| 31 | u16 ms_word) |
| 32 | { |
| 33 | u8 byte; |
| 34 | u8 function = 0; |
| 35 | int status = 0; |
| 36 | |
| 37 | byte = (u8)(ms_word & 0x00FF); |
| 38 | |
| 39 | rsi_dbg(INIT_ZONE, |
| 40 | "%s: MASTER_ACCESS_MSBYTE:0x%x\n", __func__, byte); |
| 41 | |
| 42 | status = rsi_sdio_write_register(adapter, |
| 43 | function, |
| 44 | SDIO_MASTER_ACCESS_MSBYTE, |
| 45 | &byte); |
| 46 | if (status) { |
| 47 | rsi_dbg(ERR_ZONE, |
| 48 | "%s: fail to access MASTER_ACCESS_MSBYTE\n", |
| 49 | __func__); |
| 50 | return -1; |
| 51 | } |
| 52 | |
| 53 | byte = (u8)(ms_word >> 8); |
| 54 | |
| 55 | rsi_dbg(INIT_ZONE, "%s:MASTER_ACCESS_LSBYTE:0x%x\n", __func__, byte); |
| 56 | status = rsi_sdio_write_register(adapter, |
| 57 | function, |
| 58 | SDIO_MASTER_ACCESS_LSBYTE, |
| 59 | &byte); |
| 60 | return status; |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * rsi_copy_to_card() - This function includes the actual funtionality of |
| 65 | * copying the TA firmware to the card.Basically this |
| 66 | * function includes opening the TA file,reading the |
| 67 | * TA file and writing their values in blocks of data. |
| 68 | * @common: Pointer to the driver private structure. |
| 69 | * @fw: Pointer to the firmware value to be written. |
| 70 | * @len: length of firmware file. |
| 71 | * @num_blocks: Number of blocks to be written to the card. |
| 72 | * |
| 73 | * Return: 0 on success and -1 on failure. |
| 74 | */ |
| 75 | static int rsi_copy_to_card(struct rsi_common *common, |
| 76 | const u8 *fw, |
| 77 | u32 len, |
| 78 | u32 num_blocks) |
| 79 | { |
| 80 | struct rsi_hw *adapter = common->priv; |
| 81 | struct rsi_91x_sdiodev *dev = |
| 82 | (struct rsi_91x_sdiodev *)adapter->rsi_dev; |
| 83 | u32 indx, ii; |
| 84 | u32 block_size = dev->tx_blk_size; |
| 85 | u32 lsb_address; |
| 86 | __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR, |
| 87 | TA_PC_ZERO, TA_RELEASE_THREAD_VALUE }; |
| 88 | u32 address[] = { TA_HOLD_THREAD_REG, TA_SOFT_RESET_REG, |
| 89 | TA_TH0_PC_REG, TA_RELEASE_THREAD_REG }; |
| 90 | u32 base_address; |
| 91 | u16 msb_address; |
| 92 | |
| 93 | base_address = TA_LOAD_ADDRESS; |
| 94 | msb_address = base_address >> 16; |
| 95 | |
| 96 | for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { |
| 97 | lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); |
| 98 | if (rsi_sdio_write_register_multiple(adapter, |
| 99 | lsb_address, |
| 100 | (u8 *)(fw + indx), |
| 101 | block_size)) { |
| 102 | rsi_dbg(ERR_ZONE, |
| 103 | "%s: Unable to load %s blk\n", __func__, |
| 104 | FIRMWARE_RSI9113); |
| 105 | return -1; |
| 106 | } |
| 107 | rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); |
| 108 | base_address += block_size; |
| 109 | if ((base_address >> 16) != msb_address) { |
| 110 | msb_address += 1; |
| 111 | if (rsi_sdio_master_access_msword(adapter, |
| 112 | msb_address)) { |
| 113 | rsi_dbg(ERR_ZONE, |
| 114 | "%s: Unable to set ms word reg\n", |
| 115 | __func__); |
| 116 | return -1; |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | if (len % block_size) { |
| 122 | lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); |
| 123 | if (rsi_sdio_write_register_multiple(adapter, |
| 124 | lsb_address, |
| 125 | (u8 *)(fw + indx), |
| 126 | len % block_size)) { |
| 127 | rsi_dbg(ERR_ZONE, |
| 128 | "%s: Unable to load f/w\n", __func__); |
| 129 | return -1; |
| 130 | } |
| 131 | } |
| 132 | rsi_dbg(INIT_ZONE, |
| 133 | "%s: Succesfully loaded TA instructions\n", __func__); |
| 134 | |
| 135 | if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { |
| 136 | rsi_dbg(ERR_ZONE, |
| 137 | "%s: Unable to set ms word to common reg\n", |
| 138 | __func__); |
| 139 | return -1; |
| 140 | } |
| 141 | |
| 142 | for (ii = 0; ii < ARRAY_SIZE(data); ii++) { |
| 143 | /* Bringing TA out of reset */ |
| 144 | if (rsi_sdio_write_register_multiple(adapter, |
| 145 | (address[ii] | |
| 146 | RSI_SD_REQUEST_MASTER), |
| 147 | (u8 *)&data[ii], |
| 148 | 4)) { |
| 149 | rsi_dbg(ERR_ZONE, |
| 150 | "%s: Unable to hold TA threads\n", __func__); |
| 151 | return -1; |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); |
| 156 | return 0; |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * rsi_load_ta_instructions() - This function includes the actual funtionality |
| 161 | * of loading the TA firmware.This function also |
| 162 | * includes opening the TA file,reading the TA |
| 163 | * file and writing their value in blocks of data. |
| 164 | * @common: Pointer to the driver private structure. |
| 165 | * |
| 166 | * Return: status: 0 on success, -1 on failure. |
| 167 | */ |
| 168 | static int rsi_load_ta_instructions(struct rsi_common *common) |
| 169 | { |
| 170 | struct rsi_hw *adapter = common->priv; |
| 171 | struct rsi_91x_sdiodev *dev = |
| 172 | (struct rsi_91x_sdiodev *)adapter->rsi_dev; |
| 173 | u32 len; |
| 174 | u32 num_blocks; |
Mike Looijmans | 5d5cd85 | 2015-07-28 07:51:01 +0200 | [diff] [blame] | 175 | const u8 *fw; |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 176 | const struct firmware *fw_entry = NULL; |
| 177 | u32 block_size = dev->tx_blk_size; |
| 178 | int status = 0; |
| 179 | u32 base_address; |
| 180 | u16 msb_address; |
| 181 | |
| 182 | if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { |
| 183 | rsi_dbg(ERR_ZONE, |
| 184 | "%s: Unable to set ms word to common reg\n", |
| 185 | __func__); |
| 186 | return -1; |
| 187 | } |
| 188 | base_address = TA_LOAD_ADDRESS; |
| 189 | msb_address = (base_address >> 16); |
| 190 | |
| 191 | if (rsi_sdio_master_access_msword(adapter, msb_address)) { |
| 192 | rsi_dbg(ERR_ZONE, |
| 193 | "%s: Unable to set ms word reg\n", __func__); |
| 194 | return -1; |
| 195 | } |
| 196 | |
| 197 | status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); |
| 198 | if (status < 0) { |
| 199 | rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", |
| 200 | __func__, FIRMWARE_RSI9113); |
| 201 | return status; |
| 202 | } |
| 203 | |
Mike Looijmans | 5d5cd85 | 2015-07-28 07:51:01 +0200 | [diff] [blame] | 204 | /* Copy firmware into DMA-accessible memory */ |
| 205 | fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); |
| 206 | if (!fw) |
| 207 | return -ENOMEM; |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 208 | len = fw_entry->size; |
| 209 | |
| 210 | if (len % 4) |
| 211 | len += (4 - (len % 4)); |
| 212 | |
| 213 | num_blocks = (len / block_size); |
| 214 | |
| 215 | rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); |
| 216 | rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); |
| 217 | |
Mike Looijmans | 5d5cd85 | 2015-07-28 07:51:01 +0200 | [diff] [blame] | 218 | status = rsi_copy_to_card(common, fw, len, num_blocks); |
| 219 | kfree(fw); |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 220 | release_firmware(fw_entry); |
| 221 | return status; |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * rsi_process_pkt() - This Function reads rx_blocks register and figures out |
| 226 | * the size of the rx pkt. |
| 227 | * @common: Pointer to the driver private structure. |
| 228 | * |
| 229 | * Return: 0 on success, -1 on failure. |
| 230 | */ |
| 231 | static int rsi_process_pkt(struct rsi_common *common) |
| 232 | { |
| 233 | struct rsi_hw *adapter = common->priv; |
| 234 | u8 num_blks = 0; |
| 235 | u32 rcv_pkt_len = 0; |
| 236 | int status = 0; |
| 237 | |
| 238 | status = rsi_sdio_read_register(adapter, |
| 239 | SDIO_RX_NUM_BLOCKS_REG, |
| 240 | &num_blks); |
| 241 | |
| 242 | if (status) { |
| 243 | rsi_dbg(ERR_ZONE, |
| 244 | "%s: Failed to read pkt length from the card:\n", |
| 245 | __func__); |
| 246 | return status; |
| 247 | } |
| 248 | rcv_pkt_len = (num_blks * 256); |
| 249 | |
| 250 | common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL); |
| 251 | if (!common->rx_data_pkt) { |
| 252 | rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n", |
| 253 | __func__); |
Fariya Fatima | d50c761 | 2014-04-02 09:29:53 +0530 | [diff] [blame] | 254 | return -ENOMEM; |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 255 | } |
| 256 | |
| 257 | status = rsi_sdio_host_intf_read_pkt(adapter, |
| 258 | common->rx_data_pkt, |
| 259 | rcv_pkt_len); |
| 260 | if (status) { |
| 261 | rsi_dbg(ERR_ZONE, "%s: Failed to read packet from card\n", |
| 262 | __func__); |
| 263 | goto fail; |
| 264 | } |
| 265 | |
| 266 | status = rsi_read_pkt(common, rcv_pkt_len); |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 267 | |
| 268 | fail: |
| 269 | kfree(common->rx_data_pkt); |
Fariya Fatima | d50c761 | 2014-04-02 09:29:53 +0530 | [diff] [blame] | 270 | return status; |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 271 | } |
| 272 | |
| 273 | /** |
| 274 | * rsi_init_sdio_slave_regs() - This function does the actual initialization |
| 275 | * of SDBUS slave registers. |
| 276 | * @adapter: Pointer to the adapter structure. |
| 277 | * |
| 278 | * Return: status: 0 on success, -1 on failure. |
| 279 | */ |
| 280 | int rsi_init_sdio_slave_regs(struct rsi_hw *adapter) |
| 281 | { |
| 282 | struct rsi_91x_sdiodev *dev = |
| 283 | (struct rsi_91x_sdiodev *)adapter->rsi_dev; |
| 284 | u8 function = 0; |
| 285 | u8 byte; |
| 286 | int status = 0; |
| 287 | |
| 288 | if (dev->next_read_delay) { |
| 289 | byte = dev->next_read_delay; |
| 290 | status = rsi_sdio_write_register(adapter, |
| 291 | function, |
| 292 | SDIO_NXT_RD_DELAY2, |
| 293 | &byte); |
| 294 | if (status) { |
| 295 | rsi_dbg(ERR_ZONE, |
| 296 | "%s: Failed to write SDIO_NXT_RD_DELAY2\n", |
| 297 | __func__); |
| 298 | return -1; |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | if (dev->sdio_high_speed_enable) { |
| 303 | rsi_dbg(INIT_ZONE, "%s: Enabling SDIO High speed\n", __func__); |
| 304 | byte = 0x3; |
| 305 | |
| 306 | status = rsi_sdio_write_register(adapter, |
| 307 | function, |
| 308 | SDIO_REG_HIGH_SPEED, |
| 309 | &byte); |
| 310 | if (status) { |
| 311 | rsi_dbg(ERR_ZONE, |
| 312 | "%s: Failed to enable SDIO high speed\n", |
| 313 | __func__); |
| 314 | return -1; |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | /* This tells SDIO FIFO when to start read to host */ |
| 319 | rsi_dbg(INIT_ZONE, "%s: Initialzing SDIO read start level\n", __func__); |
| 320 | byte = 0x24; |
| 321 | |
| 322 | status = rsi_sdio_write_register(adapter, |
| 323 | function, |
| 324 | SDIO_READ_START_LVL, |
| 325 | &byte); |
| 326 | if (status) { |
| 327 | rsi_dbg(ERR_ZONE, |
| 328 | "%s: Failed to write SDIO_READ_START_LVL\n", __func__); |
| 329 | return -1; |
| 330 | } |
| 331 | |
| 332 | rsi_dbg(INIT_ZONE, "%s: Initialzing FIFO ctrl registers\n", __func__); |
| 333 | byte = (128 - 32); |
| 334 | |
| 335 | status = rsi_sdio_write_register(adapter, |
| 336 | function, |
| 337 | SDIO_READ_FIFO_CTL, |
| 338 | &byte); |
| 339 | if (status) { |
| 340 | rsi_dbg(ERR_ZONE, |
| 341 | "%s: Failed to write SDIO_READ_FIFO_CTL\n", __func__); |
| 342 | return -1; |
| 343 | } |
| 344 | |
| 345 | byte = 32; |
| 346 | status = rsi_sdio_write_register(adapter, |
| 347 | function, |
| 348 | SDIO_WRITE_FIFO_CTL, |
| 349 | &byte); |
| 350 | if (status) { |
| 351 | rsi_dbg(ERR_ZONE, |
| 352 | "%s: Failed to write SDIO_WRITE_FIFO_CTL\n", __func__); |
| 353 | return -1; |
| 354 | } |
| 355 | |
| 356 | return 0; |
| 357 | } |
| 358 | |
| 359 | /** |
| 360 | * rsi_interrupt_handler() - This function read and process SDIO interrupts. |
| 361 | * @adapter: Pointer to the adapter structure. |
| 362 | * |
| 363 | * Return: None. |
| 364 | */ |
| 365 | void rsi_interrupt_handler(struct rsi_hw *adapter) |
| 366 | { |
| 367 | struct rsi_common *common = adapter->priv; |
| 368 | struct rsi_91x_sdiodev *dev = |
| 369 | (struct rsi_91x_sdiodev *)adapter->rsi_dev; |
| 370 | int status; |
| 371 | enum sdio_interrupt_type isr_type; |
| 372 | u8 isr_status = 0; |
| 373 | u8 fw_status = 0; |
| 374 | |
| 375 | dev->rx_info.sdio_int_counter++; |
| 376 | |
| 377 | do { |
| 378 | mutex_lock(&common->tx_rxlock); |
| 379 | status = rsi_sdio_read_register(common->priv, |
| 380 | RSI_FN1_INT_REGISTER, |
| 381 | &isr_status); |
| 382 | if (status) { |
| 383 | rsi_dbg(ERR_ZONE, |
| 384 | "%s: Failed to Read Intr Status Register\n", |
| 385 | __func__); |
| 386 | mutex_unlock(&common->tx_rxlock); |
| 387 | return; |
| 388 | } |
| 389 | |
| 390 | if (isr_status == 0) { |
| 391 | rsi_set_event(&common->tx_thread.event); |
| 392 | dev->rx_info.sdio_intr_status_zero++; |
| 393 | mutex_unlock(&common->tx_rxlock); |
| 394 | return; |
| 395 | } |
| 396 | |
| 397 | rsi_dbg(ISR_ZONE, "%s: Intr_status = %x %d %d\n", |
| 398 | __func__, isr_status, (1 << MSDU_PKT_PENDING), |
| 399 | (1 << FW_ASSERT_IND)); |
| 400 | |
| 401 | do { |
| 402 | RSI_GET_SDIO_INTERRUPT_TYPE(isr_status, isr_type); |
| 403 | |
| 404 | switch (isr_type) { |
| 405 | case BUFFER_AVAILABLE: |
| 406 | dev->rx_info.watch_bufferfull_count = 0; |
| 407 | dev->rx_info.buffer_full = false; |
Jahnavi Meher | f75d341 | 2014-06-16 19:44:12 +0530 | [diff] [blame] | 408 | dev->rx_info.semi_buffer_full = false; |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 409 | dev->rx_info.mgmt_buffer_full = false; |
| 410 | rsi_sdio_ack_intr(common->priv, |
| 411 | (1 << PKT_BUFF_AVAILABLE)); |
Jahnavi Meher | f75d341 | 2014-06-16 19:44:12 +0530 | [diff] [blame] | 412 | rsi_set_event(&common->tx_thread.event); |
| 413 | |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 414 | rsi_dbg(ISR_ZONE, |
Jahnavi Meher | f75d341 | 2014-06-16 19:44:12 +0530 | [diff] [blame] | 415 | "%s: ==> BUFFER_AVAILABLE <==\n", |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 416 | __func__); |
Jahnavi Meher | f75d341 | 2014-06-16 19:44:12 +0530 | [diff] [blame] | 417 | dev->rx_info.buf_available_counter++; |
Fariya Fatima | dad0d04 | 2014-03-16 03:47:02 +0530 | [diff] [blame] | 418 | break; |
| 419 | |
| 420 | case FIRMWARE_ASSERT_IND: |
| 421 | rsi_dbg(ERR_ZONE, |
| 422 | "%s: ==> FIRMWARE Assert <==\n", |
| 423 | __func__); |
| 424 | status = rsi_sdio_read_register(common->priv, |
| 425 | SDIO_FW_STATUS_REG, |
| 426 | &fw_status); |
| 427 | if (status) { |
| 428 | rsi_dbg(ERR_ZONE, |
| 429 | "%s: Failed to read f/w reg\n", |
| 430 | __func__); |
| 431 | } else { |
| 432 | rsi_dbg(ERR_ZONE, |
| 433 | "%s: Firmware Status is 0x%x\n", |
| 434 | __func__ , fw_status); |
| 435 | rsi_sdio_ack_intr(common->priv, |
| 436 | (1 << FW_ASSERT_IND)); |
| 437 | } |
| 438 | |
| 439 | common->fsm_state = FSM_CARD_NOT_READY; |
| 440 | break; |
| 441 | |
| 442 | case MSDU_PACKET_PENDING: |
| 443 | rsi_dbg(ISR_ZONE, "Pkt pending interrupt\n"); |
| 444 | dev->rx_info.total_sdio_msdu_pending_intr++; |
| 445 | |
| 446 | status = rsi_process_pkt(common); |
| 447 | if (status) { |
| 448 | rsi_dbg(ERR_ZONE, |
| 449 | "%s: Failed to read pkt\n", |
| 450 | __func__); |
| 451 | mutex_unlock(&common->tx_rxlock); |
| 452 | return; |
| 453 | } |
| 454 | break; |
| 455 | default: |
| 456 | rsi_sdio_ack_intr(common->priv, isr_status); |
| 457 | dev->rx_info.total_sdio_unknown_intr++; |
| 458 | isr_status = 0; |
| 459 | rsi_dbg(ISR_ZONE, |
| 460 | "Unknown Interrupt %x\n", |
| 461 | isr_status); |
| 462 | break; |
| 463 | } |
| 464 | isr_status ^= BIT(isr_type - 1); |
| 465 | } while (isr_status); |
| 466 | mutex_unlock(&common->tx_rxlock); |
| 467 | } while (1); |
| 468 | } |
| 469 | |
| 470 | /** |
| 471 | * rsi_device_init() - This Function Initializes The HAL. |
| 472 | * @common: Pointer to the driver private structure. |
| 473 | * |
| 474 | * Return: 0 on success, -1 on failure. |
| 475 | */ |
| 476 | int rsi_sdio_device_init(struct rsi_common *common) |
| 477 | { |
| 478 | if (rsi_load_ta_instructions(common)) |
| 479 | return -1; |
| 480 | |
| 481 | if (rsi_sdio_master_access_msword(common->priv, MISC_CFG_BASE_ADDR)) { |
| 482 | rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", |
| 483 | __func__); |
| 484 | return -1; |
| 485 | } |
| 486 | rsi_dbg(INIT_ZONE, |
| 487 | "%s: Setting ms word to 0x41050000\n", __func__); |
| 488 | |
| 489 | return 0; |
| 490 | } |
| 491 | |
| 492 | /** |
| 493 | * rsi_sdio_read_buffer_status_register() - This function is used to the read |
| 494 | * buffer status register and set |
| 495 | * relevant fields in |
| 496 | * rsi_91x_sdiodev struct. |
| 497 | * @adapter: Pointer to the driver hw structure. |
| 498 | * @q_num: The Q number whose status is to be found. |
| 499 | * |
| 500 | * Return: status: -1 on failure or else queue full/stop is indicated. |
| 501 | */ |
| 502 | int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num) |
| 503 | { |
| 504 | struct rsi_common *common = adapter->priv; |
| 505 | struct rsi_91x_sdiodev *dev = |
| 506 | (struct rsi_91x_sdiodev *)adapter->rsi_dev; |
| 507 | u8 buf_status = 0; |
| 508 | int status = 0; |
| 509 | |
| 510 | status = rsi_sdio_read_register(common->priv, |
| 511 | RSI_DEVICE_BUFFER_STATUS_REGISTER, |
| 512 | &buf_status); |
| 513 | |
| 514 | if (status) { |
| 515 | rsi_dbg(ERR_ZONE, |
| 516 | "%s: Failed to read status register\n", __func__); |
| 517 | return -1; |
| 518 | } |
| 519 | |
| 520 | if (buf_status & (BIT(PKT_MGMT_BUFF_FULL))) { |
| 521 | if (!dev->rx_info.mgmt_buffer_full) |
| 522 | dev->rx_info.mgmt_buf_full_counter++; |
| 523 | dev->rx_info.mgmt_buffer_full = true; |
| 524 | } else { |
| 525 | dev->rx_info.mgmt_buffer_full = false; |
| 526 | } |
| 527 | |
| 528 | if (buf_status & (BIT(PKT_BUFF_FULL))) { |
| 529 | if (!dev->rx_info.buffer_full) |
| 530 | dev->rx_info.buf_full_counter++; |
| 531 | dev->rx_info.buffer_full = true; |
| 532 | } else { |
| 533 | dev->rx_info.buffer_full = false; |
| 534 | } |
| 535 | |
| 536 | if (buf_status & (BIT(PKT_BUFF_SEMI_FULL))) { |
| 537 | if (!dev->rx_info.semi_buffer_full) |
| 538 | dev->rx_info.buf_semi_full_counter++; |
| 539 | dev->rx_info.semi_buffer_full = true; |
| 540 | } else { |
| 541 | dev->rx_info.semi_buffer_full = false; |
| 542 | } |
| 543 | |
| 544 | if ((q_num == MGMT_SOFT_Q) && (dev->rx_info.mgmt_buffer_full)) |
| 545 | return QUEUE_FULL; |
| 546 | |
| 547 | if (dev->rx_info.buffer_full) |
| 548 | return QUEUE_FULL; |
| 549 | |
| 550 | return QUEUE_NOT_FULL; |
| 551 | } |
| 552 | |
| 553 | /** |
| 554 | * rsi_sdio_determine_event_timeout() - This Function determines the event |
| 555 | * timeout duration. |
| 556 | * @adapter: Pointer to the adapter structure. |
| 557 | * |
| 558 | * Return: timeout duration is returned. |
| 559 | */ |
| 560 | int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter) |
| 561 | { |
| 562 | struct rsi_91x_sdiodev *dev = |
| 563 | (struct rsi_91x_sdiodev *)adapter->rsi_dev; |
| 564 | |
| 565 | /* Once buffer full is seen, event timeout to occur every 2 msecs */ |
| 566 | if (dev->rx_info.buffer_full) |
| 567 | return 2; |
| 568 | |
| 569 | return EVENT_WAIT_FOREVER; |
| 570 | } |