/* * This function checks the firmware status in card. * * The winner interface is also determined by this function. */ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) { int ret = 0; u16 firmware_stat; u32 tries; u32 winner_status; /* Wait for firmware initialization event */ for (tries = 0; tries < poll_num; tries++) { ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); if (ret) continue; if (firmware_stat == FIRMWARE_READY_SDIO) { ret = 0; break; } else { mdelay(100); ret = -1; } } if (ret) { if (mwifiex_read_reg (adapter, CARD_FW_STATUS0_REG, &winner_status)) winner_status = 0; if (winner_status) adapter->winner = 0; else adapter->winner = 1; } return ret; }
/* * This function initializes the SDIO driver. * * The following initializations steps are followed - * - Read the Host interrupt status register to acknowledge * the first interrupt got from bootloader * - Disable host interrupt mask register * - Get SDIO port * - Initialize SDIO variables in card * - Allocate MP registers * - Allocate MPA Tx and Rx buffers */ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; int ret; u32 sdio_ireg; /* * Read the HOST_INT_STATUS_REG for ACK the first interrupt got * from the bootloader. If we don't do this we get a interrupt * as soon as we register the irq. */ mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); /* Disable host interrupt mask register for SDIO */ mwifiex_sdio_disable_host_int(adapter); /* Get SDIO ioport */ mwifiex_init_sdio_ioport(adapter); /* Initialize SDIO variables in card */ card->mp_rd_bitmap = 0; card->mp_wr_bitmap = 0; card->curr_rd_port = 1; card->curr_wr_port = 1; card->mp_data_port_mask = DATA_PORT_MASK; card->mpa_tx.buf_len = 0; card->mpa_tx.pkt_cnt = 0; card->mpa_tx.start_port = 0; card->mpa_tx.enabled = 0; card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; card->mpa_rx.buf_len = 0; card->mpa_rx.pkt_cnt = 0; card->mpa_rx.start_port = 0; card->mpa_rx.enabled = 0; card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; /* Allocate buffers for SDIO MP-A */ card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); if (!card->mp_regs) { dev_err(adapter->dev, "failed to alloc mp_regs\n"); return -ENOMEM; } ret = mwifiex_alloc_sdio_mpa_buffers(adapter, SDIO_MP_TX_AGGR_DEF_BUF_SIZE, SDIO_MP_RX_AGGR_DEF_BUF_SIZE); if (ret) { dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); kfree(card->mp_regs); return -1; } return ret; }
static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; int ret; u32 sdio_ireg; mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); mwifiex_sdio_disable_host_int(adapter); mwifiex_init_sdio_ioport(adapter); card->mp_rd_bitmap = 0; card->mp_wr_bitmap = 0; card->curr_rd_port = 1; card->curr_wr_port = 1; card->mp_data_port_mask = DATA_PORT_MASK; card->mpa_tx.buf_len = 0; card->mpa_tx.pkt_cnt = 0; card->mpa_tx.start_port = 0; card->mpa_tx.enabled = 1; card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; card->mpa_rx.buf_len = 0; card->mpa_rx.pkt_cnt = 0; card->mpa_rx.start_port = 0; card->mpa_rx.enabled = 1; card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); if (!card->mp_regs) { dev_err(adapter->dev, "failed to alloc mp_regs\n"); return -ENOMEM; } ret = mwifiex_alloc_sdio_mpa_buffers(adapter, SDIO_MP_TX_AGGR_DEF_BUF_SIZE, SDIO_MP_RX_AGGR_DEF_BUF_SIZE); if (ret) { dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); kfree(card->mp_regs); return -1; } return ret; }
static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) { u32 reg; adapter->ioport = 0; if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) adapter->ioport |= (reg & 0xff); else return -1; if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) adapter->ioport |= ((reg & 0xff) << 8); else return -1; if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) adapter->ioport |= ((reg & 0xff) << 16); else return -1; pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) mwifiex_write_reg(adapter, HOST_INT_RSR_REG, reg | SDIO_INT_MASK); else return -1; if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, reg | AUTO_RE_ENABLE_INT); else return -1; return 0; }
/* * This function initializes the IO ports. * * The following operations are performed - * - Read the IO ports (0, 1 and 2) * - Set host interrupt Reset-To-Read to clear * - Set auto re-enable interrupt */ static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) { u32 reg; adapter->ioport = 0; /* Read the IO port */ if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) adapter->ioport |= (reg & 0xff); else return -1; if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) adapter->ioport |= ((reg & 0xff) << 8); else return -1; if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) adapter->ioport |= ((reg & 0xff) << 16); else return -1; pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); /* Set Host interrupt reset to read to clear */ if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) mwifiex_write_reg(adapter, HOST_INT_RSR_REG, reg | SDIO_INT_MASK); else return -1; /* Dnld/Upld ready set to auto reset */ if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, reg | AUTO_RE_ENABLE_INT); else return -1; return 0; }
/* * This function disables the host interrupt. * * The host interrupt mask is read, the disable bit is reset and * written back to the card host interrupt mask register. */ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) { u32 host_int_mask; if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) return -1; host_int_mask &= ~HOST_INT_DISABLE; if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { dev_err(adapter->dev, "disable host interrupt failed\n"); return -1; } return 0; }
/* * This function disables the host interrupt. * * The host interrupt mask is read, the disable bit is reset and * written back to the card host interrupt mask register. */ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) { u32 host_int_mask; /* Read back the host_int_mask register */ if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) return -1; /* Update with the mask and write back to the register */ host_int_mask &= ~HOST_INT_DISABLE; if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { dev_err(adapter->dev, "disable host interrupt failed\n"); return -1; } return 0; }
static int mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) { u32 tries; u32 cs; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) break; else if ((cs & bits) == bits) return 0; usleep_range(10, 20); } dev_err(adapter->dev, "poll card status failed, tries = %d\n", tries); return -1; }
static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { int ret; u8 *firmware = fw->fw_buf; u32 firmware_len = fw->fw_len; u32 offset = 0; u32 base0, base1; u8 *fwbuf; u16 len = 0; u32 txlen, tx_blocks = 0, tries; u32 i = 0; if (!firmware_len) { dev_err(adapter->dev, "firmware image not found! Terminating download\n"); return -1; } dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", firmware_len); fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); if (!fwbuf) { dev_err(adapter->dev, "unable to alloc buffer for FW. Terminating dnld\n"); return -ENOMEM; } do { ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | DN_LD_CARD_RDY); if (ret) { dev_err(adapter->dev, "FW download with helper:" " poll status timeout @ %d\n", offset); goto done; } if (offset >= firmware_len) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, &base0); if (ret) { dev_err(adapter->dev, "dev BASE0 register read failed: " "base0=%#04X(%d). Terminating dnld\n", base0, base0); goto done; } ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, &base1); if (ret) { dev_err(adapter->dev, "dev BASE1 register read failed: " "base1=%#04X(%d). Terminating dnld\n", base1, base1); goto done; } len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); if (len) break; usleep_range(10, 20); } if (!len) { break; } else if (len > MWIFIEX_UPLD_SIZE) { dev_err(adapter->dev, "FW dnld failed @ %d, invalid length %d\n", offset, len); ret = -1; goto done; } txlen = len; if (len & BIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { dev_err(adapter->dev, "FW dnld failed @ %d, over max retry\n", offset); ret = -1; goto done; } dev_err(adapter->dev, "CRC indicated by the helper:" " len = 0x%04X, txlen = %d\n", len, txlen); len &= ~BIT(0); txlen = 0; } else { i = 0; if (firmware_len - offset < txlen) txlen = firmware_len - offset; tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - 1) / MWIFIEX_SDIO_BLOCK_SIZE; memmove(fwbuf, &firmware[offset], txlen); } ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * MWIFIEX_SDIO_BLOCK_SIZE, adapter->ioport); if (ret) { dev_err(adapter->dev, "FW download, write iomem (%d) failed @ %d\n", i, offset); if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) dev_err(adapter->dev, "write CFG reg failed\n"); ret = -1; goto done; } offset += txlen; } while (true); dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", offset); ret = 0; done: kfree(fwbuf); return ret; }
static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; int ret = 0; u8 sdio_ireg; struct sk_buff *skb; u8 port = CTRL_PORT; u32 len_reg_l, len_reg_u; u32 rx_blocks; u16 rx_len; unsigned long flags; spin_lock_irqsave(&adapter->int_lock, flags); sdio_ireg = adapter->int_status; adapter->int_status = 0; spin_unlock_irqrestore(&adapter->int_lock, flags); if (!sdio_ireg) return ret; if (sdio_ireg & DN_LD_HOST_INT_STATUS) { card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", card->mp_wr_bitmap); if (adapter->data_sent && (card->mp_wr_bitmap & card->mp_data_port_mask)) { dev_dbg(adapter->dev, "info: <--- Tx DONE Interrupt --->\n"); adapter->data_sent = false; } } if (adapter->cmd_sent) { card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; if (card->mp_wr_bitmap & CTRL_PORT_MASK) adapter->cmd_sent = false; } dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", adapter->cmd_sent, adapter->data_sent); if (sdio_ireg & UP_LD_HOST_INT_STATUS) { card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", card->mp_rd_bitmap); while (true) { ret = mwifiex_get_rd_port(adapter, &port); if (ret) { dev_dbg(adapter->dev, "info: no more rd_port available\n"); break; } len_reg_l = RD_LEN_P0_L + (port << 1); len_reg_u = RD_LEN_P0_U + (port << 1); rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; rx_len |= (u16) card->mp_regs[len_reg_l]; dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", port, rx_len); rx_blocks = (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - 1) / MWIFIEX_SDIO_BLOCK_SIZE; if (rx_len <= INTF_HEADER_LEN || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > MWIFIEX_RX_DATA_BUF_SIZE) { dev_err(adapter->dev, "invalid rx_len=%d\n", rx_len); return -1; } rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); skb = dev_alloc_skb(rx_len); if (!skb) { dev_err(adapter->dev, "%s: failed to alloc skb", __func__); return -1; } skb_put(skb, rx_len); dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", rx_len, skb->len); if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, port)) { u32 cr = 0; dev_err(adapter->dev, "card_to_host_mpa failed:" " int status=%#x\n", sdio_ireg); if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) dev_err(adapter->dev, "read CFG reg failed\n"); dev_dbg(adapter->dev, "info: CFG reg val = %d\n", cr); if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04))) dev_err(adapter->dev, "write CFG reg failed\n"); dev_dbg(adapter->dev, "info: write success\n"); if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) dev_err(adapter->dev, "read CFG reg failed\n"); dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr); return -1; } } } return 0; }
/* * This function downloads the firmware to the card. * * Firmware is downloaded to the card in blocks. Every block download * is tested for CRC errors, and retried a number of times before * returning failure. */ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { int ret; u8 *firmware = fw->fw_buf; u32 firmware_len = fw->fw_len; u32 offset = 0; u32 base0, base1; u8 *fwbuf; u16 len = 0; u32 txlen, tx_blocks = 0, tries; u32 i = 0; if (!firmware_len) { dev_err(adapter->dev, "firmware image not found!" " Terminating download\n"); return -1; } dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", firmware_len); /* Assume that the allocated buffer is 8-byte aligned */ fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); if (!fwbuf) { dev_err(adapter->dev, "unable to alloc buffer for firmware." " Terminating download\n"); return -ENOMEM; } /* Perform firmware data transfer */ do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */ ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | DN_LD_CARD_RDY); if (ret) { dev_err(adapter->dev, "FW download with helper:" " poll status timeout @ %d\n", offset); goto done; } /* More data? */ if (offset >= firmware_len) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, &base0); if (ret) { dev_err(adapter->dev, "dev BASE0 register read" " failed: base0=0x%04X(%d). Terminating " "download\n", base0, base0); goto done; } ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, &base1); if (ret) { dev_err(adapter->dev, "dev BASE1 register read" " failed: base1=0x%04X(%d). Terminating " "download\n", base1, base1); goto done; } len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); if (len) break; udelay(10); } if (!len) { break; } else if (len > MWIFIEX_UPLD_SIZE) { dev_err(adapter->dev, "FW download failed @ %d," " invalid length %d\n", offset, len); ret = -1; goto done; } txlen = len; if (len & BIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { dev_err(adapter->dev, "FW download failed @" " %d, over max retry count\n", offset); ret = -1; goto done; } dev_err(adapter->dev, "CRC indicated by the helper:" " len = 0x%04X, txlen = %d\n", len, txlen); len &= ~BIT(0); /* Setting this to 0 to resend from same offset */ txlen = 0; } else { i = 0; /* Set blocksize to transfer - checking for last block */ if (firmware_len - offset < txlen) txlen = firmware_len - offset; tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - 1) / MWIFIEX_SDIO_BLOCK_SIZE; /* Copy payload to buffer */ memmove(fwbuf, &firmware[offset], txlen); } ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * MWIFIEX_SDIO_BLOCK_SIZE, adapter->ioport); if (ret) { dev_err(adapter->dev, "FW download, write iomem (%d)" " failed @ %d\n", i, offset); if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) dev_err(adapter->dev, "write CFG reg failed\n"); ret = -1; goto done; } offset += txlen; } while (true); dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", offset); ret = 0; done: kfree(fwbuf); return ret; }
static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; u32 wrptr, rd_index; int ret = 0; struct sk_buff *skb_tmp = NULL; if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { dev_err(adapter->dev, "RECV DATA: failed to read REG_TXBD_RDPTR\n"); ret = -1; goto done; } while (((wrptr & MWIFIEX_RXBD_MASK) != (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { struct sk_buff *skb_data; u16 rx_len; rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; skb_data = card->rx_buf_list[rd_index]; rx_len = *((u16 *)skb_data->data); dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); skb_tmp = dev_alloc_skb(rx_len); if (!skb_tmp) { dev_dbg(adapter->dev, "info: Failed to alloc skb for RX\n"); ret = -EBUSY; goto done; } skb_put(skb_tmp, rx_len); memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len); if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == MWIFIEX_MAX_TXRX_BD) { card->rxbd_rdptr = ((card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ MWIFIEX_BD_FLAG_ROLLOVER_IND); } dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n", card->rxbd_rdptr, wrptr); if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, card->rxbd_rdptr)) { dev_err(adapter->dev, "RECV DATA: failed to write REG_RXBD_RDPTR\n"); ret = -1; goto done; } if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { dev_err(adapter->dev, "RECV DATA: failed to read REG_TXBD_RDPTR\n"); ret = -1; goto done; } dev_dbg(adapter->dev, "info: RECV DATA: Rcvd packet from fw successfully\n"); mwifiex_handle_rx_packet(adapter, skb_tmp); } done: if (ret && skb_tmp) dev_kfree_skb_any(skb_tmp); return ret; }
static int mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; u32 wrindx, rdptr; phys_addr_t *buf_pa; __le16 *tmp; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { dev_err(adapter->dev, "SEND DATA: failed to read REG_TXBD_RDPTR\n"); return -1; } wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr, card->txbd_wrptr); if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != (rdptr & MWIFIEX_TXBD_MASK)) || ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { struct sk_buff *skb_data; u8 *payload; adapter->data_sent = true; skb_data = card->tx_buf_list[wrindx]; memcpy(skb_data->data, skb->data, skb->len); payload = skb_data->data; tmp = (__le16 *)&payload[0]; *tmp = cpu_to_le16((u16)skb->len); tmp = (__le16 *)&payload[2]; *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA); skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len); skb_trim(skb_data, skb->len); buf_pa = MWIFIEX_SKB_PACB(skb_data); card->txbd_ring[wrindx]->paddr = *buf_pa; card->txbd_ring[wrindx]->len = (u16)skb_data->len; card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | MWIFIEX_BD_FLAG_LAST_DESC; if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) == MWIFIEX_MAX_TXRX_BD) card->txbd_wrptr = ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ MWIFIEX_BD_FLAG_ROLLOVER_IND); if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR, card->txbd_wrptr)) { dev_err(adapter->dev, "SEND DATA: failed to write REG_TXBD_WRPTR\n"); return 0; } if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, CPU_INTR_DNLD_RDY)) { dev_err(adapter->dev, "SEND DATA: failed to assert door-bell intr\n"); return -1; } dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: " "%#x> and sent packet to firmware successfully\n", rdptr, card->txbd_wrptr); } else { dev_dbg(adapter->dev, "info: TX Ring full, can't send packets to fw\n"); adapter->data_sent = true; if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, CPU_INTR_DNLD_RDY)) dev_err(adapter->dev, "SEND DATA: failed to assert door-bell intr\n"); return -EBUSY; } return 0; }