ssinfo_t __get_stack_size( const unsigned int caps_len, const unsigned int arg_len, const unsigned int desired_stack_size){ static unsigned int PADDING = 16; const unsigned int min_allocation = SIGSTKSZ + PAGE_SIZE; const unsigned long default_allocation = ALIGN_SZ(sizeof(struct _ThreadStack)+ arg_len + sizeof(struct _XTreeHandle)*caps_len+ PADDING); unsigned int stack_estimation = default_allocation+ PAGE_SIZE + ((min_allocation > desired_stack_size)? min_allocation:desired_stack_size); if( ALIGN_PG(stack_estimation) != stack_estimation ) stack_estimation = ALIGN_PG(stack_estimation) + 2 * PAGE_SIZE; ssinfo_t ret; ret.real_size = default_allocation; //stack_estimation; ret.begin_offset = default_allocation; ret.end_offset = ret.real_size; // - 2 * PAGE_SIZE; return ret; }
phys_addr_t __init board_mem_reserve_add(char *name, size_t size) { phys_addr_t base = 0; size_t align_size = ALIGN_SZ(size, SZ_1M); if (reserved_base_end == 0) { reserved_base_end = meminfo.bank[meminfo.nr_banks - 1].start + meminfo.bank[meminfo.nr_banks - 1].size; /* Workaround for RGA driver, which may overflow on physical memory address parameter */ if (reserved_base_end > 0xA0000000) reserved_base_end = 0xA0000000; } reserved_size += align_size; base = reserved_base_end - reserved_size; pr_info("memory reserve: Memory(base:0x%x size:%dM) reserved for <%s>\n", base, align_size/SZ_1M, name); return base; }
static void btmrvl_init_adapter(struct btmrvl_private *priv) { int buf_size; skb_queue_head_init(&priv->adapter->tx_queue); priv->adapter->ps_state = PS_AWAKE; buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN); priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL); if (!priv->adapter->hw_regs_buf) { priv->adapter->hw_regs = NULL; BT_ERR("Unable to allocate buffer for hw_regs."); } else { priv->adapter->hw_regs = (u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf, BTSDIO_DMA_ALIGN); BT_DBG("hw_regs_buf=%p hw_regs=%p", priv->adapter->hw_regs_buf, priv->adapter->hw_regs); } init_waitqueue_head(&priv->adapter->cmd_wait_q); init_waitqueue_head(&priv->adapter->event_hs_wait_q); }
/** * @brief This function downloads firmware image to the card. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ int sd_download_firmware_w_helper(bt_private * priv) { struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card; const struct firmware *fw_firmware = NULL; u8 *firmware = NULL; int firmwarelen; u8 base0; u8 base1; int ret = BT_STATUS_SUCCESS; int offset; void *tmpfwbuf = NULL; int tmpfwbufsz; u8 *fwbuf; u16 len; int txlen = 0; int tx_blocks = 0; int i = 0; int tries = 0; #ifdef FW_DOWNLOAD_SPEED u32 tv1, tv2; #endif char *cur_fw_name = NULL; ENTER(); if (fw_name == NULL) /* Check revision ID */ switch (priv->adapter->chip_rev) { case SD8787_W0: case SD8787_W1: cur_fw_name = SD8787_W1_FW_NAME; break; case SD8787_A0_A1: cur_fw_name = SD8787_AX_FW_NAME; break; default: cur_fw_name = DEFAULT_FW_NAME; break; } else cur_fw_name = fw_name; if ((ret = request_firmware(&fw_firmware, cur_fw_name, priv->hotplug_device)) < 0) { PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret); goto done; } if (fw_firmware) { firmware = (u8 *) fw_firmware->data; firmwarelen = fw_firmware->size; } else { PRINTM(MSG, "No firmware image found! Terminating download\n"); ret = BT_STATUS_FAILURE; goto done; } PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen); #ifdef FW_DOWNLOAD_SPEED tv1 = get_utimeofday(); #endif #ifdef PXA3XX_DMA_ALIGN tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT); #else /* PXA3XX_DMA_ALIGN */ tmpfwbufsz = BT_UPLD_SIZE; #endif tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); if (!tmpfwbuf) { PRINTM(ERROR, "Unable to allocate buffer for firmware. Terminating download\n"); ret = BT_STATUS_FAILURE; goto done; } memset(tmpfwbuf, 0, tmpfwbufsz); #ifdef PXA3XX_DMA_ALIGN /* Ensure 8-byte aligned firmware buffer */ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, PXA3XX_DMA_ALIGNMENT); #else /* PXA3XX_DMA_ALIGN */ fwbuf = (u8 *) tmpfwbuf; #endif /* Perform firmware data transfer */ offset = 0; do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */ ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY); if (ret < 0) { PRINTM(FATAL, "FW download with helper poll status timeout @ %d\n", offset); goto done; } /* More data? */ if (offset >= firmwarelen) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE0 register read failed:" " base0=0x%04X(%d). Terminating download\n", base0, base0); ret = BT_STATUS_FAILURE; goto done; } base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE1 register read failed:" " base1=0x%04X(%d). Terminating download\n", base1, base1); ret = BT_STATUS_FAILURE; goto done; } len = (((u16) base1) << 8) | base0; if (len != 0) break; udelay(10); } if (len == 0) break; else if (len > BT_UPLD_SIZE) { PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n", offset, len); ret = BT_STATUS_FAILURE; goto done; } txlen = len; if (len & BIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { PRINTM(FATAL, "FW download failure @ %d, over max retry count\n", offset); ret = BT_STATUS_FAILURE; goto done; } PRINTM(ERROR, "FW CRC error 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 (firmwarelen - offset < txlen) txlen = firmwarelen - offset; PRINTM(INFO, "."); tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL; /* Copy payload to buffer */ memcpy(fwbuf, &firmware[offset], txlen); } /* Send data */ ret = sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf, tx_blocks * SD_BLOCK_SIZE_FW_DL); if (ret < 0) { PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i, offset); sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret); if (ret) PRINTM(ERROR, "write ioreg failed (CFG)\n"); } offset += txlen; } while (TRUE); PRINTM(INFO, "\nFW download over, size %d bytes\n", offset); ret = BT_STATUS_SUCCESS; done: #ifdef FW_DOWNLOAD_SPEED tv2 = get_utimeofday(); PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000, (tv1 % 1000000) / 1000, tv1 % 1000); PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); tv2 -= tv1; PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); #endif if (tmpfwbuf) kfree(tmpfwbuf); if (fw_firmware) release_firmware(fw_firmware); LEAVE(); return ret; }
/** * @brief Transfer firmware to card * * @param priv A Pointer to bt_private structure * @return BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no. */ static int sd_init_fw_dpc(bt_private * priv) { struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card; u8 *firmware = NULL; int firmwarelen; u8 base0; u8 base1; int ret = BT_STATUS_SUCCESS; int offset; void *tmpfwbuf = NULL; int tmpfwbufsz; u8 *fwbuf; u16 len; int txlen = 0; int tx_blocks = 0; int i = 0; int tries = 0; #ifdef FW_DOWNLOAD_SPEED u32 tv1, tv2; #endif u8 crc_buffer = 0; ENTER(); firmware = (u8 *) priv->firmware->data; firmwarelen = priv->firmware->size; PRINTM(INFO, "BT: Downloading FW image (%d bytes)\n", firmwarelen); #ifdef FW_DOWNLOAD_SPEED tv1 = get_utimeofday(); #endif tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, DMA_ALIGNMENT); tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); if (!tmpfwbuf) { PRINTM(ERROR, "BT: Unable to allocate buffer for firmware. Terminating download\n"); ret = BT_STATUS_FAILURE; goto done; } memset(tmpfwbuf, 0, tmpfwbufsz); /* Ensure 8-byte aligned firmware buffer */ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT); if (!(priv->fw_crc_check)) { /* CRC check not required, use custom header first */ firmware = fw_crc_header; firmwarelen = FW_CRC_HEADER; crc_buffer = 1; } /* Perform firmware data transfer */ offset = 0; do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */ ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY); if (ret < 0) { PRINTM(FATAL, "BT: FW download with helper poll status timeout @ %d\n", offset); goto done; } if (!crc_buffer) /* More data? */ if (offset >= firmwarelen) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE0 register read failed:" " base0=0x%04X(%d). Terminating download\n", base0, base0); ret = BT_STATUS_FAILURE; goto done; } base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE1 register read failed:" " base1=0x%04X(%d). Terminating download\n", base1, base1); ret = BT_STATUS_FAILURE; goto done; } len = (((u16) base1) << 8) | base0; if (len != 0) break; udelay(10); } if (len == 0) break; else if (len > BT_UPLD_SIZE) { PRINTM(FATAL, "BT: FW download failure @ %d, invalid length %d\n", offset, len); ret = BT_STATUS_FAILURE; goto done; } txlen = len; if (len & BIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { PRINTM(FATAL, "BT: FW download failure @ %d, over max retry count\n", offset); ret = BT_STATUS_FAILURE; goto done; } PRINTM(ERROR, "BT: FW CRC error indicated by the helper:" " len = 0x%04X, txlen = %d\n", len, txlen); len &= ~BIT(0); PRINTM(ERROR, "BT: retry: %d, offset %d\n", i, offset); DBG_HEXDUMP(ERROR, "BT: FW block:", fwbuf, len); /* Setting this to 0 to resend from same offset */ txlen = 0; } else { i = 0; /* Set blocksize to transfer - checking for last block */ if (firmwarelen - offset < txlen) txlen = firmwarelen - offset; PRINTM(INFO, "."); tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL; /* Copy payload to buffer */ memcpy(fwbuf, &firmware[offset], txlen); } /* Send data */ ret = sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf, tx_blocks * SD_BLOCK_SIZE_FW_DL); if (ret < 0) { PRINTM(ERROR, "BT: FW download, write iomem (%d) failed @ %d\n", i, offset); sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret); if (ret) PRINTM(ERROR, "write ioreg failed (CFG)\n"); } offset += txlen; if (crc_buffer) { if (offset >= FW_CRC_HEADER) { /* Custom header download complete, restore original FW */ offset = 0; firmware = (u8 *) priv->firmware->data; firmwarelen = priv->firmware->size; crc_buffer = 0; } } } while (TRUE); PRINTM(INFO, "\nBT: FW download over, size %d bytes\n", offset); ret = BT_STATUS_SUCCESS; done: #ifdef FW_DOWNLOAD_SPEED tv2 = get_utimeofday(); PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000, (tv1 % 1000000) / 1000, tv1 % 1000); PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); tv2 -= tv1; PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); #endif if (tmpfwbuf) kfree(tmpfwbuf); LEAVE(); return ret; }
/** * @brief This function downloads FW blocks to device * * @param pmadapter A pointer to mlan_adapter * @param pmfw A pointer to firmware image * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status wlan_prog_fw_w_helper(IN pmlan_adapter pmadapter, IN pmlan_fw_image pmfw) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_callbacks pcb = &pmadapter->callbacks; t_u8 *firmware = pmfw->pfw_buf; t_u32 firmwarelen = pmfw->fw_len; t_u32 offset = 0; t_u32 base0, base1; t_void *tmpfwbuf = MNULL; t_u32 tmpfwbufsz; t_u8 *fwbuf; mlan_buffer mbuf; t_u16 len = 0; t_u32 txlen = 0, tx_blocks = 0, tries = 0; t_u32 i = 0; t_u8 crc_buffer = 0; t_u8 *header_crc_fw; t_u8 header_crc_fw_len = 0; header_crc_fw = fw_crc_header_rb; header_crc_fw_len = FW_CRC_HEADER_RB; ENTER(); if (!firmware && !pcb->moal_get_fw_data) { PRINTM(MMSG, "No firmware image found! Terminating download\n"); LEAVE(); return MLAN_STATUS_FAILURE; } PRINTM(MINFO, "WLAN: Downloading FW image (%d bytes)\n", firmwarelen); tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, DMA_ALIGNMENT); ret = pcb->moal_malloc(pmadapter->pmoal_handle, tmpfwbufsz, MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **) & tmpfwbuf); if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) { PRINTM(MERROR, "Unable to allocate buffer for firmware. Terminating download\n"); ret = MLAN_STATUS_FAILURE; goto done; } memset(pmadapter, tmpfwbuf, 0, tmpfwbufsz); /* Ensure 8-byte aligned firmware buffer */ fwbuf = (t_u8 *) ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT); if (!pmadapter->init_para.fw_crc_check) { /* CRC check not required, use custom header first */ firmware = header_crc_fw; firmwarelen = header_crc_fw_len; crc_buffer = 1; } /* Perform firmware data transfer */ do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */ ret = wlan_sdio_poll_card_status(pmadapter, CARD_IO_READY | DN_LD_CARD_RDY); if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MFATAL, "WLAN: FW download with helper poll status timeout @ %d\n", offset); goto done; } if (!crc_buffer) /* More data? */ if (firmwarelen && offset >= firmwarelen) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { ret = pcb->moal_read_reg(pmadapter->pmoal_handle, READ_BASE_0_REG, &base0); if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "Dev BASE0 register read failed:" " base0=0x%04X(%d). Terminating download\n", base0, base0); goto done; } ret = pcb->moal_read_reg(pmadapter->pmoal_handle, READ_BASE_1_REG, &base1); if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "Dev BASE1 register read failed:" " base1=0x%04X(%d). Terminating download\n", base1, base1); goto done; } len = (t_u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); if (len) break; wlan_udelay(pmadapter, 10); } if (!len) break; else if (len > WLAN_UPLD_SIZE) { PRINTM(MFATAL, "WLAN: FW download failure @ %d, invalid length %d\n", offset, len); ret = MLAN_STATUS_FAILURE; goto done; } txlen = len; if (len & MBIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { PRINTM(MFATAL, "WLAN: FW download failure @ %d, over max retry count\n", offset); ret = MLAN_STATUS_FAILURE; goto done; } PRINTM(MERROR, "WLAN: FW CRC error indicated by the helper:" " len = 0x%04X, txlen = %d\n", len, txlen); len &= ~MBIT(0); PRINTM(MERROR, "WLAN: retry: %d, offset %d\n", i, offset); DBG_HEXDUMP(MERROR, "WLAN: FW block:", mbuf.pbuf, len); /* Setting this to 0 to resend from same offset */ txlen = 0; } else { i = 0; /* Set blocksize to transfer - checking for last block */ if (firmwarelen && firmwarelen - offset < txlen) { txlen = firmwarelen - offset; } PRINTM(MINFO, "."); tx_blocks = (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD - 1) / MLAN_SDIO_BLOCK_SIZE_FW_DNLD; /* Copy payload to buffer */ if (firmware) memmove(pmadapter, fwbuf, &firmware[offset], txlen); else pcb->moal_get_fw_data(pmadapter->pmoal_handle, offset, txlen, fwbuf); } /* Send data */ memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer)); mbuf.pbuf = (t_u8 *) fwbuf; mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD; ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf, pmadapter->ioport, 0); if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "WLAN: FW download, write iomem (%d) failed @ %d\n", i, offset); if (pcb-> moal_write_reg(pmadapter->pmoal_handle, HOST_TO_CARD_EVENT_REG, HOST_TERM_CMD53) != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "write CFG reg failed\n"); } ret = MLAN_STATUS_FAILURE; goto done; } offset += txlen; if (crc_buffer && offset >= header_crc_fw_len) { /* Custom header download complete, restore original FW */ offset = 0; firmware = pmfw->pfw_buf; firmwarelen = pmfw->fw_len; crc_buffer = 0; } } while (MTRUE); PRINTM(MMSG, "Wlan: FW download over, firmwarelen=%d downloaded %d\n", firmwarelen, offset); ret = MLAN_STATUS_SUCCESS; done: if (tmpfwbuf) pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) tmpfwbuf); LEAVE(); return ret; }