/** * @brief This function handles the major job in WLAN driver. * it handles the event generated by firmware, rx data received * from firmware and tx data sent from kernel. * * @param data A pointer to wlan_thread structure * @return WLAN_STATUS_SUCCESS */ static int wlan_service_main_thread(void *data) { wlan_thread *thread = data; wlan_private *priv = thread->priv; wlan_adapter *Adapter = priv->adapter; wait_queue_t wait; u8 ireg = 0; unsigned long driver_flags; OS_INTERRUPT_SAVE_AREA; ENTER(); wlan_activate_thread(thread); init_waitqueue_entry(&wait, current); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) current->flags |= PF_NOFREEZE; #endif wlan_meas_init(priv); PRINTM(INFO, "11H: init 11H\n"); wlan_11h_init(priv); wmm_init(priv); for (;;) { #define MAX_MAIN_THREAD_LOOPS (10000) if (++Adapter->main_thread_loops > MAX_MAIN_THREAD_LOOPS) { panic("main-thread dead loop detected: %u\n" "IntCnt=%d\n" "Adapter->HisRegCpy=%#x\n" "CurCmd=%p CmdPending=%s\n" "Connect=%s\n" "cmd_sent=%s\n" "data_sent=%s\n" "IsDeepSleep=%d\n" "PSMode=%d PSState=%d\n" "WakeupDevReq=%d\n" "HS_Activated=%d\n" "WakeupTries=%d\n", Adapter->main_thread_loops, Adapter->IntCounter, Adapter->HisRegCpy, Adapter->CurCmd, list_empty(&Adapter->CmdPendingQ) ? "N" : "Y", (Adapter->MediaConnectStatus == WlanMediaStateConnected) ? "Y" : "N", (priv->wlan_dev.cmd_sent) ? "TRUE" : "FALSE", (priv->wlan_dev.data_sent) ? "TRUE" : "FALSE", Adapter->IsDeepSleep, Adapter->PSMode, Adapter->PSState, Adapter->bWakeupDevRequired, Adapter->HS_Activated, Adapter->WakeupTries); } add_wait_queue(&thread->waitQ, &wait); OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE); TX_DISABLE; if ((Adapter->WakeupTries) || (Adapter->PSState == PS_STATE_SLEEP && !Adapter->bWakeupDevRequired) || (!Adapter->IntCounter && Adapter->PSState == PS_STATE_PRE_SLEEP) || (!Adapter->IntCounter && (priv->wlan_dev.data_sent || Adapter->TxLockFlag || wmm_lists_empty(priv) || wmm_is_queue_stopped(priv)) && (priv->wlan_dev.cmd_sent || Adapter->CurCmd || list_empty(&Adapter->CmdPendingQ)) ) ) { PRINTM(INFO, "main-thread sleeping... " "HS_Act=%s WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n", (Adapter->HS_Activated) ? "Y" : "N", (Adapter->bWakeupDevRequired) ? "Y" : "N", (Adapter->MediaConnectStatus) ? "Y" : "N", Adapter->PSMode, Adapter->PSState); TX_RESTORE; Adapter->main_thread_loops = 0; schedule(); PRINTM(INFO, "main-thread waking up: IntCnt=%d " "CurCmd=%s CmdPending=%s\n" " Connect=%s " "cmd_sent=%s data_sent=%s\n", Adapter->IntCounter, (Adapter->CurCmd) ? "Y" : "N", list_empty(&Adapter->CmdPendingQ) ? "N" : "Y", (Adapter->MediaConnectStatus) ? "Y" : "N", (priv->wlan_dev.cmd_sent) ? "TRUE" : "FALSE", (priv->wlan_dev.data_sent) ? "TRUE" : "FALSE"); } else { TX_RESTORE; } OS_SET_THREAD_STATE(TASK_RUNNING); remove_wait_queue(&thread->waitQ, &wait); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if ((thread->state == WLAN_THREAD_STOPPED) || Adapter->SurpriseRemoved) #else if (kthread_should_stop() || Adapter->SurpriseRemoved) #endif { PRINTM(INFO, "main-thread: break from main thread: " "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved); break; } if (Adapter->IntCounter) { OS_INT_DISABLE(priv, driver_flags); Adapter->IntCounter = 0; OS_INT_RESTORE(priv, driver_flags); if (sbi_get_int_status(priv, &ireg)) { PRINTM(ERROR, "main-thread: reading HOST_INT_STATUS_REG failed\n"); continue; } /* If we have a valid interrupt then we have something to do, so we are not running in a dead loop */ if (ireg) Adapter->main_thread_loops = 0; OS_INT_DISABLE(priv, driver_flags); Adapter->HisRegCpy |= ireg; OS_INT_RESTORE(priv, driver_flags); PRINTM(INTR, "INT: status = 0x%x\n", Adapter->HisRegCpy); } else if (Adapter->bWakeupDevRequired) { Adapter->WakeupTries++; PRINTM(CMND, "Wakeup device... WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d @ %lu\n", (Adapter->bWakeupDevRequired) ? "Y" : "N", (priv->adapter->MediaConnectStatus) ? "Y" : "N", priv->adapter->PSMode, priv->adapter->PSState, os_time_get()); /* Wake up device */ if (sbi_exit_deep_sleep(priv)) PRINTM(MSG, "main-thread: wakeup device failed\n"); continue; } /* Command response? */ if (Adapter->HisRegCpy & HIS_CmdUpLdRdy) { OS_INT_DISABLE(priv, driver_flags); Adapter->HisRegCpy &= ~HIS_CmdUpLdRdy; OS_INT_RESTORE(priv, driver_flags); wlan_process_cmdresp(priv); } /* Any Card Event */ if (Adapter->HisRegCpy & HIS_CardEvent) { OS_INT_DISABLE(priv, driver_flags); Adapter->HisRegCpy &= ~HIS_CardEvent; OS_INT_RESTORE(priv, driver_flags); wlan_process_event(priv); } /* Check if we need to confirm Sleep Request received previously */ if (Adapter->PSState == PS_STATE_PRE_SLEEP) { if (!priv->wlan_dev.cmd_sent && !Adapter->CurCmd) { ASSERT(Adapter->MediaConnectStatus == WlanMediaStateConnected); wlan_ps_cond_check(priv, (u16) Adapter->PSMode); } } /* The PS state is changed during processing of Sleep Request event above */ if ((Adapter->PSState == PS_STATE_SLEEP) || (Adapter->PSState == PS_STATE_PRE_SLEEP)) continue; if (Adapter->IsDeepSleep) continue; /* The HS_Activated flag is changed during processing of HS_Activate command resp */ /* We cannot send command or data if HS_Activated and WakeupDevRequired are TRUE */ if (Adapter->HS_Activated && Adapter->bWakeupDevRequired) { PRINTM(INFO, "main-thread: cannot send command or data, " "HS_Activated=%d\n", Adapter->HS_Activated); continue; } /* Execute the next command */ if (!priv->wlan_dev.cmd_sent && !Adapter->CurCmd) wlan_exec_next_cmd(priv); if (!priv->wlan_dev.data_sent && !wmm_lists_empty(priv) && !wmm_is_queue_stopped(priv)) { if ((Adapter->PSState == PS_STATE_FULL_POWER) || (Adapter->sleep_period.period == 0) || (Adapter->TxLockFlag == FALSE)) wmm_process_tx(priv); } } wlan_deactivate_thread(thread); LEAVE(); return WLAN_STATUS_SUCCESS; }
/** * @brief The main process * * @param pmlan_adapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status mlan_main_process(IN t_void * pmlan_adapter) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; pmlan_callbacks pcb; ENTER(); MASSERT(pmlan_adapter); pcb = &pmadapter->callbacks; pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); /* Check if already processing */ if (pmadapter->mlan_processing) { pmadapter->more_task_flag = MTRUE; pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); goto exit_main_proc; } else { pmadapter->mlan_processing = MTRUE; pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); } process_start: do { pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); pmadapter->more_task_flag = MFALSE; pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); /* Is MLAN shutting down or not ready? */ if ((pmadapter->hw_status == WlanHardwareStatusClosing) || (pmadapter->hw_status == WlanHardwareStatusNotReady)) break; if (util_scalar_read (pmadapter->pmoal_handle, &pmadapter->rx_pkts_queued, pmadapter->callbacks.moal_spin_lock, pmadapter->callbacks.moal_spin_unlock) > HIGH_RX_PENDING) { PRINTM(MEVENT, "Pause\n"); pmadapter->delay_task_flag = MTRUE; break; } /* Handle pending SDIO interrupts if any */ if (pmadapter->sdio_ireg) { if (pmadapter->hs_activated == MTRUE) wlan_process_hs_config(pmadapter); wlan_process_int_status(pmadapter); if (pmadapter->data_received && pmadapter->rx_work_flag) wlan_recv_event(wlan_get_priv (pmadapter, MLAN_BSS_ROLE_ANY), MLAN_EVENT_ID_DRV_DEFER_RX_WORK, MNULL); } /* Need to wake up the card ? */ if ((pmadapter->ps_state == PS_STATE_SLEEP) && (pmadapter->pm_wakeup_card_req && !pmadapter->pm_wakeup_fw_try) && (util_peek_list (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, pcb->moal_spin_lock, pcb->moal_spin_unlock) || !wlan_bypass_tx_list_empty(pmadapter) || !wlan_wmm_lists_empty(pmadapter) )) { wlan_pm_wakeup_card(pmadapter); pmadapter->pm_wakeup_fw_try = MTRUE; continue; } if (IS_CARD_RX_RCVD(pmadapter)) { pmadapter->data_received = MFALSE; if (pmadapter->hs_activated == MTRUE) { pmadapter->is_hs_configured = MFALSE; wlan_host_sleep_activated_event(wlan_get_priv (pmadapter, MLAN_BSS_ROLE_ANY), MFALSE); } pmadapter->pm_wakeup_fw_try = MFALSE; if (pmadapter->ps_state == PS_STATE_SLEEP) pmadapter->ps_state = PS_STATE_AWAKE; } else { /* We have tried to wakeup the card already */ if (pmadapter->pm_wakeup_fw_try) break; if (pmadapter->ps_state != PS_STATE_AWAKE || (pmadapter->tx_lock_flag == MTRUE)) break; if (pmadapter->scan_processing || pmadapter->data_sent || (wlan_bypass_tx_list_empty(pmadapter) && wlan_wmm_lists_empty(pmadapter)) || wlan_11h_radar_detected_tx_blocked(pmadapter) ) { if (pmadapter->cmd_sent || pmadapter->curr_cmd || (!util_peek_list (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, pcb->moal_spin_lock, pcb->moal_spin_unlock))) { break; } } } /* Check for Cmd Resp */ if (pmadapter->cmd_resp_received) { pmadapter->cmd_resp_received = MFALSE; wlan_process_cmdresp(pmadapter); /* call moal back when init_fw is done */ if (pmadapter->hw_status == WlanHardwareStatusInitdone) { pmadapter->hw_status = WlanHardwareStatusReady; wlan_init_fw_complete(pmadapter); } } /* Check for event */ if (pmadapter->event_received) { pmadapter->event_received = MFALSE; wlan_process_event(pmadapter); } /* Check if we need to confirm Sleep Request received previously */ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) { if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) { wlan_check_ps_cond(pmadapter); } } /* * The ps_state may have been changed during processing of * Sleep Request event. */ if ((pmadapter->ps_state == PS_STATE_SLEEP) || (pmadapter->ps_state == PS_STATE_PRE_SLEEP) || (pmadapter->ps_state == PS_STATE_SLEEP_CFM) || (pmadapter->tx_lock_flag == MTRUE) ) continue; if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) { if (wlan_exec_next_cmd(pmadapter) == MLAN_STATUS_FAILURE) { ret = MLAN_STATUS_FAILURE; break; } } if (!pmadapter->scan_processing && !pmadapter->data_sent && !wlan_11h_radar_detected_tx_blocked(pmadapter) && !wlan_bypass_tx_list_empty(pmadapter)) { PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n"); wlan_process_bypass_tx(pmadapter); if (pmadapter->hs_activated == MTRUE) { pmadapter->is_hs_configured = MFALSE; wlan_host_sleep_activated_event(wlan_get_priv (pmadapter, MLAN_BSS_ROLE_ANY), MFALSE); } } if (!pmadapter->scan_processing && !pmadapter->data_sent && !wlan_wmm_lists_empty(pmadapter) && !wlan_11h_radar_detected_tx_blocked(pmadapter) ) { wlan_wmm_process_tx(pmadapter); if (pmadapter->hs_activated == MTRUE) { pmadapter->is_hs_configured = MFALSE; wlan_host_sleep_activated_event(wlan_get_priv (pmadapter, MLAN_BSS_ROLE_ANY), MFALSE); } } #ifdef STA_SUPPORT if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent && !pmadapter->curr_cmd && !IS_COMMAND_PENDING(pmadapter) && wlan_bypass_tx_list_empty(pmadapter) && wlan_wmm_lists_empty(pmadapter)) { if (wlan_send_null_packet (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA), MRVDRV_TxPD_POWER_MGMT_NULL_PACKET | MRVDRV_TxPD_POWER_MGMT_LAST_PACKET) == MLAN_STATUS_SUCCESS) { pmadapter->delay_null_pkt = MFALSE; } break; } #endif } while (MTRUE); pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); if (pmadapter->more_task_flag == MTRUE) { pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); goto process_start; } pmadapter->mlan_processing = MFALSE; pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); exit_main_proc: if (pmadapter->hw_status == WlanHardwareStatusClosing) mlan_shutdown_fw(pmadapter); LEAVE(); return ret; }