static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, u8 *payload, u32 pkt_len, u32 port) { u32 i = 0; int ret; do { ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); if (ret) { i++; dev_err(adapter->dev, "host_to_card, write iomem" " (%d) failed: %d\n", i, ret); if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) dev_err(adapter->dev, "write CFG reg failed\n"); ret = -1; if (i > MAX_WRITE_IOMEM_RETRY) return ret; } } while (ret == -1); return ret; }
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_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { int ret = 0; u8 *firmware = fw->fw_buf, *recv_buff; u32 retries = USB8XXX_FW_MAX_RETRY, dlen; u32 fw_seqnum = 0, tlen = 0, dnld_cmd = 0; struct fw_data *fwdata; struct fw_sync_header sync_fw; u8 check_winner = 1; if (!firmware) { dev_err(adapter->dev, "No firmware image found! Terminating download\n"); ret = -1; goto fw_exit; } /* Allocate memory for transmit */ fwdata = kzalloc(FW_DNLD_TX_BUF_SIZE, GFP_KERNEL); if (!fwdata) goto fw_exit; /* Allocate memory for receive */ recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL); if (!recv_buff) goto cleanup; do { /* Send pseudo data to check winner status first */ if (check_winner) { memset(&fwdata->fw_hdr, 0, sizeof(struct fw_header)); dlen = 0; } else { /* copy the header of the fw_data to get the length */ memcpy(&fwdata->fw_hdr, &firmware[tlen], sizeof(struct fw_header)); dlen = le32_to_cpu(fwdata->fw_hdr.data_len); dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd); tlen += sizeof(struct fw_header); memcpy(fwdata->data, &firmware[tlen], dlen); fwdata->seq_num = cpu_to_le32(fw_seqnum); tlen += dlen; } /* If the send/receive fails or CRC occurs then retry */ while (retries--) { u8 *buf = (u8 *)fwdata; u32 len = FW_DATA_XMIT_SIZE; /* send the firmware block */ ret = mwifiex_write_data_sync(adapter, buf, &len, MWIFIEX_USB_EP_CMD_EVENT, MWIFIEX_USB_TIMEOUT); if (ret) { dev_err(adapter->dev, "write_data_sync: failed: %d\n", ret); continue; } buf = recv_buff; len = FW_DNLD_RX_BUF_SIZE; /* Receive the firmware block response */ ret = mwifiex_read_data_sync(adapter, buf, &len, MWIFIEX_USB_EP_CMD_EVENT, MWIFIEX_USB_TIMEOUT); if (ret) { dev_err(adapter->dev, "read_data_sync: failed: %d\n", ret); continue; } memcpy(&sync_fw, recv_buff, sizeof(struct fw_sync_header)); /* check 1st firmware block resp for highest bit set */ if (check_winner) { if (le32_to_cpu(sync_fw.cmd) & 0x80000000) { dev_warn(adapter->dev, "USB is not the winner %#x\n", sync_fw.cmd); /* returning success */ ret = 0; goto cleanup; } dev_dbg(adapter->dev, "USB is the winner, start to download FW\n"); check_winner = 0; break; } /* check the firmware block response for CRC errors */ if (sync_fw.cmd) { dev_err(adapter->dev, "FW received block with CRC %#x\n", sync_fw.cmd); ret = -1; continue; } retries = USB8XXX_FW_MAX_RETRY; break; } fw_seqnum++; } while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries); cleanup: dev_dbg(adapter->dev, "%s: %d bytes downloaded\n", __func__, tlen); kfree(recv_buff); kfree(fwdata); if (retries) ret = 0; fw_exit: return ret; }
/* * 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; }