static void sdio_tput_test_write(struct rda5890_private *priv, int iter, int len) { unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf_1 = (char *)addr; char *buf_2 = (char *)addr + PAGE_SIZE/2; char cmd[SDIO_TEST_CMD_LEN]; int i; int ret; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "%s, iter = %d, len = %d\n", __func__, iter, len); for (i=0; i<len; i++) { buf_1[i] = len - i - 1; buf_2[i] = i; } (*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC; (*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_H2C_START; (*(volatile unsigned long *)(cmd + 8)) = iter; (*(volatile unsigned long *)(cmd + 12)) = len; ret = priv->hw_host_to_card(priv, cmd, len,SDIO_TEST_CMD_LEN); if (ret) { RDA5890_ERRP("START cmd send fail, ret = %d\n", ret); goto out; } send_time_start = jiffies; for (i=0;i<iter;i++) { if (!(i & 1)) ret = priv->hw_host_to_card(priv, buf_1, len, DATA_REQUEST_PACKET); else ret = priv->hw_host_to_card(priv, buf_2, len, DATA_REQUEST_PACKET); if (ret) { RDA5890_ERRP("packet %d send fail, ret = %d\n", i, ret); goto out; } } send_time_end = jiffies; (*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC; (*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_H2C_STOP; (*(volatile unsigned long *)(cmd + 8)) = iter; (*(volatile unsigned long *)(cmd + 12)) = len; ret = priv->hw_host_to_card(priv, cmd, len, SDIO_TEST_CMD_LEN); if (ret) { RDA5890_ERRP("START cmd send fail, ret = %d\n", ret); goto out; } out: free_page(addr); }
static int if_sdio_wakeup_card(struct if_sdio_card *card) { struct rda5890_private *priv = card->priv; int ret = 0; #ifdef WIFI_TEST_MODE if(rda_5990_wifi_in_test_mode()) return 0; #endif #ifdef WIFI_CLOCK_ALWAYS_ON export_msdc_clk_always_on(); #endif ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_TO_DEV,1); if (ret) { RDA5890_ERRP("if_sdio_wakeup_card write FUN1_INT_TO_DEV reg fail\n"); goto out; } atomic_set(&priv->sleep_flag, 0); RDA5890_DBGLAP(RDA5890_DA_PM, RDA5890_DL_CRIT, "wake up \n"); // wait 15ms, hardware need 13ms to wakeup rda5890_shedule_timeout(8); out: return ret; }
void if_sdio_sleep_worker(struct work_struct *work) { struct if_sdio_card *card = NULL; int ret = 0; struct rda5890_private *priv = NULL; card = container_of(work, struct if_sdio_card, sleep_work.work); if(card) priv = card->priv; else goto out; if(!priv) goto out; RDA5890_DBGLAP(RDA5890_DA_PM, RDA5890_DL_CRIT, "Sleep\n"); /* clear IF_SDIO_FUN1_INT_PEND, this allow device to sleep */ ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, IF_SDIO_HOST_TX_FLAG); if (ret) { RDA5890_ERRP("clear IF_SDIO_HOST_TX_FLAG failed\n"); } atomic_inc(&card->priv->sleep_flag); out: atomic_set(&card->sleep_work_is_active, 0); #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeUnlock(); #endif return; }
u32 rda_hif_sdio_irq(MTK_WCN_HIF_SDIO_CLTCTX cltCtx) { int ret = 0; struct if_sdio_card *card; struct rda5890_private *priv; u8 status; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s >>>\n", __func__); if(!gCard) { return -EIO; } card = gCard; priv = card->priv; ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_STAT, &status); if (ret) goto out; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB, "if_sdio_interrupt, status = 0x%02x\n", status); if (status & IF_SDIO_INT_AHB2SDIO) if_sdio_card_to_host(card); if (status & IF_SDIO_INT_ERROR) { ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND ,IF_SDIO_INT_ERROR); if (ret) { RDA5890_ERRP("write FUN1_INT_STAT reg fail\n"); goto out; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "%s, INT_ERROR\n", __func__); } #ifdef WIFI_CLOCK_ALWAYS_ON export_msdc_clk_always_on_off(); #endif out: RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s <<< ret=%d \n", __func__, ret); return ret; }
static void sdio_tput_test_read(struct rda5890_private *priv, int iter, int len) { char cmd[SDIO_TEST_CMD_LEN]; int ret; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "%s, iter = %d, len = %d\n", __func__, iter, len); (*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC; (*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_C2H_START; (*(volatile unsigned long *)(cmd + 8)) = iter; (*(volatile unsigned long *)(cmd + 12)) = len; ret = priv->hw_host_to_card(priv, cmd, len ,SDIO_TEST_CMD_LEN); if (ret) { RDA5890_ERRP("START cmd send fail, ret = %d\n", ret); } }
int if_sdio_card_to_host(struct if_sdio_card *card) { int ret = 0; struct rda5890_private *priv = card->priv; u8 size_l = 0, size_h = 0; u16 size, chunk; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s <<< \n", __func__); ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_AHB2SDIO_PKTLEN_L, &size_l); if (ret) { RDA5890_ERRP("read PKTLEN_L reg fail\n"); goto out; } else RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_L reg size_l:%d \n", size_l); ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_AHB2SDIO_PKTLEN_H, &size_h); if (ret) { RDA5890_ERRP("read PKTLEN_H reg fail\n"); goto out; } else RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_H reg size_h:%d\n",size_h); size = (size_l | ((size_h & 0x7f) << 8)) * 4; if (size < 4) { RDA5890_ERRP("invalid packet size (%d bytes) from firmware\n", size); ret = -EINVAL; goto out; } /* alignment is handled on firmside */ //chunk = sdio_align_size(card->func, size); chunk = size; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "if_sdio_card_to_host, size = %d, aligned size = %d\n", size, chunk); /* TODO: handle multiple packets here */ ret = mtk_wcn_hif_sdio_read_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_RD, (u32)card->buffer, chunk); if (ret) { RDA5890_ERRP("sdio_readsb fail, ret = %d, size = %d, aligned size = %d\n", ret, size, chunk); goto out; } #if 1 if(priv->version == 7) { mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, 0x20); if(ret) { RDA5890_ERRP("clear SDIO Tx Complete flag failed\n"); goto out; } } #endif RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB, "if_sdio_card_to_host, read done\n"); if(ret) { RDA5890_ERRP("clear SDIO Tx Complete flag failed\n"); goto out; } if (sdio_test_flag) { rda5890_sdio_test_card_to_host(card->buffer, chunk); goto out; } /* TODO: this chunk size need to be handled here */ rda5890_card_to_host(priv, card->buffer, chunk); out: RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_card_to_host >>>\n"); return ret; }
u32 rda_hif_sdio_probe(MTK_WCN_HIF_SDIO_CLTCTX cltCtx, MTK_WCN_HIF_SDIO_FUNCINFO* funcInfo) { struct if_sdio_card *card = NULL; struct rda5890_private *priv = NULL; struct if_sdio_packet *packet = NULL; int ret = -1; unsigned long flags; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s >>>\n", __func__); printk(KERN_INFO "20120905 RDA5890: SDIO card attached func num %d block size %d \n", funcInfo->func_num, funcInfo->blk_sz); if(gCard) { RDA5890_ERRP("rda5890 sdio has probed \n"); return 0; } card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL); if (!card) { RDA5890_ERRP("kzalloc fail\n"); return -ENOMEM; } card->func = NULL; spin_lock_init(&card->lock); atomic_set(&card->wid_complete_flag, 0); INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); card->work_thread = create_singlethread_workqueue("rda5890_if_sdio_worker"); #ifdef WIFI_POWER_MANAGER atomic_set(&card->sleep_work_is_active, 0); INIT_DELAYED_WORK(&card->sleep_work, if_sdio_sleep_worker); #endif #ifdef WIFI_UNLOCK_SYSTEM atomic_set(&wake_lock_counter, 0); wake_lock_init(&sleep_worker_wake_lock, WAKE_LOCK_SUSPEND, "RDA_sleep_worker_wake_lock"); #endif priv = rda5890_add_card(card); if (!priv) { RDA5890_ERRP("rda5890_add_card fail\n"); ret = -ENOMEM; goto remove_card; } rda5890_debugfs_init_one(priv); card->priv = priv; priv->card = card; priv->hw_host_to_card = if_sdio_host_to_card; priv->cltCtx = cltCtx; priv->version = rda_wlan_version(); priv->version &= 0x1f; if(priv->version != 4 && priv->version != 7 && priv->version != 5) { RDA5890_ERRP("no correct version exit wlan initiate \n"); goto remove_card; } /* * Enable interrupts now that everything is set up */ printk(KERN_INFO " mtk_wcn_hif_sdio_writeb IF_SDIO_FUN1_INT_MASK \n"); ret = mtk_wcn_hif_sdio_writeb(cltCtx, IF_SDIO_FUN1_INT_MASK, 0x07); if (ret) { RDA5890_ERRP("enable func interrupt fail\n"); goto remove_card; } #ifdef WIFI_TEST_MODE if(!rda_5990_wifi_in_test_mode()) { #endif ret = rda5890_sdio_init(priv); if(ret < 0) goto remove_card; gCard = card; ret=rda5890_disable_self_cts(priv); if(ret < 0) goto remove_card; ret=rda5890_disable_block_bt(priv); if(ret < 0) goto remove_card; ret = rda5890_set_scan_timeout(priv); if (ret) { RDA5890_ERRP("rda5890_set_scan_timeout fail, ret = %d\n", ret); goto remove_card; } ret= rda5890_set_listen_interval(priv, WIFI_LISTEN_INTERVAL); if(ret < 0) goto remove_card; ret = rda5890_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD); if(ret < 0) goto remove_card; ret = rda5890_init_pm(priv); if(ret < 0) goto remove_card; #ifdef WIFI_TEST_MODE } else { ret = rda5890_set_test_mode(priv); if(ret < 0) goto remove_card; gCard = card; } #endif #ifdef WIFI_SELECT_CHANNEL // Add for choose operation band, 3rd parameter indicate which band will be used. // 0/1: channel1-11, 2:channel1-13, 3:channel1-14, other values: channel1-13 #ifdef CHANNEL_11 if (rda5890_generic_set_uchar(priv, 0x0047, 1) < 0) #elif defined CHANNEL_14 if (rda5890_generic_set_uchar(priv, 0x0047, 3) < 0) #else /* CHANNEL_13 && others */ if (rda5890_generic_set_uchar(priv, 0x0047, 2) < 0) #endif { RDA5890_ERRP("set op_band failed!\n"); goto remove_card; } else { #ifdef CHANNEL_11 channel_nums = 11; #elif defined CHANNEL_12 channel_nums = 12; #elif defined CHANNEL_14 channel_nums = 14; #else /* CHANNEL_13 && others */ channel_nums = 13; #endif } #endif if (sdio_test_flag) { unsigned char mac_addr[6]; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "SDIO TESTING MODE\n"); ret = rda5890_get_mac_addr(priv, mac_addr); printk(KERN_INFO "Test rda5890_get_mac_addr %x:%x:%x:%x:%x:%x", mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]); goto done; } ret = rda5890_start_card(priv); if (ret) { RDA5890_ERRP("rda5890_start_card fail, ret = %d\n", ret); goto remove_card; } done: printk(KERN_INFO "RDA5890: SDIO card started\n"); out: RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s ret:%d <<<\n", __func__, ret); return ret; remove_card: if (atomic_read(&card->wid_complete_flag) && priv) { complete(&priv->wid_done); printk(KERN_INFO "*****RDA5890: probe send wid complete\n"); } flush_work(&card->packet_worker); cancel_work_sync(&card->packet_worker); #ifdef WIFI_POWER_MANAGER cancel_delayed_work(&card->sleep_work); #endif destroy_workqueue(card->work_thread); if(priv) rda5890_remove_card(priv); while (card->packets) { packet = card->packets; card->packets = card->packets->next; kfree(packet); } kfree(card); gCard = NULL; goto out; }
static void if_sdio_host_to_card_worker(struct work_struct *work) { struct if_sdio_card *card = NULL; struct rda5890_private *priv = NULL; struct if_sdio_packet *packet = NULL; int ret; unsigned long flags; u16 size; u32 retries = 500; u8 size_l, size_h, write_status = 0; #define SDIO_HOST_WRITE_BATCH_SIZE 512 u16 bytes_left, offset, batch; card = container_of(work, struct if_sdio_card, packet_worker); priv = card->priv; //mask_all_sdio_irq(priv->cltCtx); #ifdef WIFI_POWER_MANAGER if(is_sdio_init_complete()) { if(atomic_read(&card->sleep_work_is_active)) { cancel_delayed_work(&card->sleep_work); #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeUnlock(); #endif atomic_set(&card->sleep_work_is_active, 0); } } #endif while (1) { retries = 500; spin_lock_irqsave(&card->lock, flags); packet = card->packets; if (packet) card->packets = packet->next; spin_unlock_irqrestore(&card->lock, flags); if (!packet) break; #ifdef WIFI_POWER_MANAGER if (atomic_read(&priv->sleep_flag)) { /* Deivce maybe sleep, wakeup it. */ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "Wakeup\n"); ret = if_sdio_wakeup_card(card); if (ret) { RDA5890_ERRP("wakeup card fail\n"); goto out; } } #endif while(retries && is_sdio_patch_complete()) //check write flow ctrl { ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, &write_status); if(ret) { RDA5890_ERRP("read IF_SDIO_FUN1_INT_PEND failed\n"); goto release; } if((write_status & IF_SDIO_INT_RXCMPL) == 0) { //RDA5890_ERRP("**** sdio is busy retry next time \n "); retries --; schedule(); } else { ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_RXCMPL); if(ret) { RDA5890_ERRP("write IF_SDIO_FUN1_INT_PEND failed\n"); goto release; } break; } } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_host_to_card_worker, send one packet, size = %d\n", packet->nb); /* write length */ size = packet->nb/4; size_l = (u8)(size & 0xff); size_h = (u8)((size >> 8) & 0x7f); size_h |= 0x80; ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_L, size_l); if (ret) { RDA5890_ERRP("write PKTLEN_L reg fail\n"); goto release; } ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_H, size_h); if (ret) { RDA5890_ERRP("write PKTLEN_H reg fail\n"); goto release; } /* write data */ bytes_left = packet->nb; offset = 0; while(bytes_left) { batch = (bytes_left < SDIO_HOST_WRITE_BATCH_SIZE)? bytes_left:SDIO_HOST_WRITE_BATCH_SIZE; ret = mtk_wcn_hif_sdio_write_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_WR, packet->buffer + offset, batch); if (ret) { RDA5890_ERRP("sdio_writesb fail, ret = %d\n", ret); goto release; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "write batch %d, offset = %d\n", batch, offset); offset += batch; bytes_left -= batch; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_host_to_card_worker, send one packet done\n"); release: kfree(packet); packet = NULL; } out: if(is_sdio_init_complete()) //init complete should start sleep_work { #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeLock(); #endif #ifdef WIFI_POWER_MANAGER #ifdef WIFI_TEST_MODE if(rda_5990_wifi_in_test_mode()) return; #endif //end WIFI_TEST_MODE atomic_set(&card->sleep_work_is_active, 1); queue_delayed_work(priv->work_thread, &card->sleep_work, rda5890_assoc_in_progress ? 30 * HZ : HZ/5); // 100ms //queue_delayed_work(priv->work_thread, &card->sleep_work, HZ/5); // 100ms #endif } }
void rda5890_sdio_test_card_to_host(char *buf, unsigned short len) { int i; int cmd, cmd_iter, cmd_len; int time_ms; static int recv_pattern = 0; static int recv_tput_flag = 0; static int recv_pkts = 0; static int recv_bytes = 0; //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, // "SDIO TEST Card to Host, len = %d\n", len); if (debug_read_flag) { RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "DEBUG RX, len = %d\n", len); dump_buf(buf, len); } if ((*(volatile unsigned long *)buf == SDIO_TEST_CMD_MAGIC) && len == SDIO_TEST_CMD_LEN) { cmd = (int)(*(volatile unsigned long *)(buf + 4)); cmd_iter = (int)(*(volatile unsigned long *)(buf + 8)); cmd_len = (int)(*(volatile unsigned long *)(buf + 12)); //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, // "SDIO TEST CMD: cmd = %d, iter = %d, len = %d\n", // cmd, cmd_iter, cmd_len); switch (cmd) { case SDIO_TEST_CMD_TYPE_H2C_STATUS: RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "H2C STATUS CMD \n"); time_ms = jiffies_to_msecs(send_time_end - send_time_start); RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "SDIO H2C STATUS: pkts = %d, bytes = %d, time = %d ms\n", cmd_iter, cmd_len, time_ms); break; case SDIO_TEST_CMD_TYPE_C2H_PILOT: //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, // "C2H PILOT CMD \n"); recv_pattern = 0; recv_tput_flag = 1; recv_pkts = 0; recv_bytes = 0; recv_time_start = jiffies; break; case SDIO_TEST_CMD_TYPE_C2H_END: //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, // "C2H END CMD \n"); recv_time_end = jiffies; recv_tput_flag = 0; time_ms = jiffies_to_msecs(recv_time_end - recv_time_start); RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "SDIO C2H STATUS: pkts = %d, bytes = %d, time = %d ms\n", recv_pkts, recv_bytes, time_ms); break; case SDIO_TEST_CMD_TYPE_H2C_START: case SDIO_TEST_CMD_TYPE_H2C_STOP: case SDIO_TEST_CMD_TYPE_C2H_START: default: RDA5890_ERRP("SDIO TEST CMD: Invalid cmd %d\n", cmd); break; } return; } for (i=0;i<len;i++) { if (recv_pattern == 0) { if (buf[i] != (char)(i)) { RDA5890_ERRP("data[%d] error, 0x%02x, should be 0x%02x, len = %d\n", i, buf[i], (char)(i), len); break; } } else { if (buf[i] != (char)(len - i - 1)) { RDA5890_ERRP("data[%d] error, 0x%02x, should be 0x%02x, len = %d\n", i, buf[i], (char)(len - i - 1), len); break; } } } if (recv_tput_flag) recv_pattern = !recv_pattern; if (recv_tput_flag && i==len) { recv_pkts ++; recv_bytes += len; } }