/** * @brief This function checks the conditions and sends packet to device * * @param priv A pointer to mlan_private structure * @param pmbuf A pointer to the mlan_buffer for process * @param tx_param A pointer to mlan_tx_param structure * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure */ mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf, mlan_tx_param * tx_param) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_adapter pmadapter = priv->adapter; t_u8 *head_ptr = MNULL; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif #ifdef STA_SUPPORT TxPD *plocal_tx_pd = MNULL; #endif ENTER(); head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf); if (!head_ptr) { pmbuf->status_code = MLAN_ERROR_PKT_INVALID; ret = MLAN_STATUS_FAILURE; goto done; } #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN); #endif ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param); done: switch (ret) { case MLAN_STATUS_RESOURCE: #ifdef STA_SUPPORT if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) { pmadapter->tx_lock_flag = MFALSE; plocal_tx_pd->flags = 0; } #endif PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n"); break; case MLAN_STATUS_FAILURE: pmadapter->data_sent = MFALSE; PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret); pmadapter->dbg.num_tx_host_to_card_failure++; pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL; wlan_write_data_complete(pmadapter, pmbuf, ret); break; case MLAN_STATUS_PENDING: DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN, MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN)); break; case MLAN_STATUS_SUCCESS: DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN, MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN)); wlan_write_data_complete(pmadapter, pmbuf, ret); break; default: break; } if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) { PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec); } LEAVE(); return ret; }
/** * @brief Aggregate multiple packets into one single AMSDU packet * * @param priv A pointer to mlan_private structure * @param pra_list Pointer to the RA List table containing the pointers * to packets. * @param headroom Any interface specific headroom that may be need. TxPD * will be formed leaving this headroom. * @param ptrindex Pointer index * * @return Final packet size or MLAN_STATUS_FAILURE */ int wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list, int headroom, int ptrindex) { int pkt_size = 0; pmlan_adapter pmadapter = priv->adapter; mlan_buffer *pmbuf_aggr, *pmbuf_src; t_u8 *data; int pad = 0; mlan_status ret = MLAN_STATUS_SUCCESS; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif mlan_tx_param tx_param; #ifdef STA_SUPPORT TxPD *ptx_pd = MNULL; #endif t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size); ENTER(); PRINTM(MDAT_D, "Handling Aggr packet\n"); pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); if (pmbuf_src) { pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter, pmadapter->tx_buf_size, 0, MOAL_MALLOC_BUFFER); if (!pmbuf_aggr) { PRINTM(MERROR, "Error allocating mlan_buffer\n"); pmadapter->callbacks.moal_spin_unlock(pmadapter-> pmoal_handle, priv->wmm. ra_list_spinlock); LEAVE(); return MLAN_STATUS_FAILURE; } data = pmbuf_aggr->pbuf + headroom; pmbuf_aggr->bss_index = pmbuf_src->bss_index; pmbuf_aggr->buf_type = pmbuf_src->buf_type; pmbuf_aggr->priority = pmbuf_src->priority; pmbuf_aggr->pbuf = data; pmbuf_aggr->data_offset = 0; pmbuf_aggr->in_ts_sec = pmbuf_src->in_ts_sec; pmbuf_aggr->in_ts_usec = pmbuf_src->in_ts_usec; if (pmbuf_src->flags & MLAN_BUF_FLAG_TDLS) pmbuf_aggr->flags |= MLAN_BUF_FLAG_TDLS; /* Form AMSDU */ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr); pkt_size = sizeof(TxPD); #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) ptx_pd = (TxPD *) pmbuf_aggr->pbuf; #endif } else { pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); goto exit; } while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN) + headroom) <= max_amsdu_size)) { pmbuf_src = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); pra_list->total_pkts--; /* decrement for every PDU taken from the list */ priv->wmm.pkts_queued[ptrindex]--; util_scalar_decrement(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); if (pmbuf_src->flags & MLAN_BUF_FLAG_TCP_ACK) pmadapter->callbacks.moal_tcp_ack_tx_ind(pmadapter-> pmoal_handle, pmbuf_src); pkt_size += wlan_11n_form_amsdu_pkt(pmadapter, (data + pkt_size), pmbuf_src->pbuf + pmbuf_src->data_offset, pmbuf_src->data_len, &pad); DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src, sizeof(mlan_buffer)); wlan_write_data_complete(pmadapter, pmbuf_src, MLAN_STATUS_SUCCESS); pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) { pmadapter->callbacks.moal_spin_unlock(pmadapter-> pmoal_handle, priv->wmm. ra_list_spinlock); LEAVE(); return MLAN_STATUS_FAILURE; } pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); } pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); /* Last AMSDU packet does not need padding */ pkt_size -= pad; pmbuf_aggr->data_len = pkt_size; wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr); pmbuf_aggr->data_len += headroom; pmbuf_aggr->pbuf = data - headroom; tx_param.next_pkt_len = ((pmbuf_src) ? pmbuf_src->data_len + sizeof(TxPD) : 0); ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf_aggr, &tx_param); switch (ret) { case MLAN_STATUS_RESOURCE: pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) { pmadapter->callbacks.moal_spin_unlock(pmadapter-> pmoal_handle, priv->wmm. ra_list_spinlock); pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID; wlan_write_data_complete(pmadapter, pmbuf_aggr, MLAN_STATUS_FAILURE); LEAVE(); return MLAN_STATUS_FAILURE; } #ifdef STA_SUPPORT /* reset tx_lock_flag */ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) { pmadapter->tx_lock_flag = MFALSE; ptx_pd->flags = 0; } #endif util_enqueue_list_head(pmadapter->pmoal_handle, &pra_list->buf_head, (pmlan_linked_list) pmbuf_aggr, MNULL, MNULL); pra_list->total_pkts++; /* add back only one: aggregated packet is requeued as one */ priv->wmm.pkts_queued[ptrindex]++; util_scalar_increment(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT; pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n"); pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID; break; case MLAN_STATUS_FAILURE: pmadapter->data_sent = MFALSE; PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret); pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL; pmadapter->dbg.num_tx_host_to_card_failure++; wlan_write_data_complete(pmadapter, pmbuf_aggr, ret); goto exit; case MLAN_STATUS_PENDING: break; case MLAN_STATUS_SUCCESS: wlan_write_data_complete(pmadapter, pmbuf_aggr, ret); break; default: break; } if (ret != MLAN_STATUS_RESOURCE) { pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) { priv->wmm.packets_out[ptrindex]++; priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; } pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur-> pnext; pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm. ra_list_spinlock); } PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec); exit: LEAVE(); return pkt_size + headroom; }
/** * @brief This function sends sleep confirm command to firmware. * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_dnld_sleep_confirm_cmd(mlan_adapter * pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; static t_u32 i = 0; t_u16 cmd_len = 0; HostCmd_DS_802_11_PS_MODE_ENH *pps_mode = MNULL; opt_sleep_confirm_buffer *sleep_cfm_buf = (opt_sleep_confirm_buffer *) (pmadapter->psleep_cfm->pbuf + pmadapter->psleep_cfm->data_offset); ENTER(); if ((wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY))->bss_type == MLAN_BSS_TYPE_STA) { cmd_len = sizeof(HostCmd_DS_COMMAND); pps_mode = &sleep_cfm_buf->ps_cfm_sleep.params.psmode_enh; sleep_cfm_buf->ps_cfm_sleep.seq_num = wlan_cpu_to_le16(++pmadapter->seq_num); pps_mode->params.sleep_cfm.resp_ctrl = wlan_cpu_to_le16(RESP_NEEDED); DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep, cmd_len); } /* Send sleep confirm command to firmware */ pmadapter->psleep_cfm->data_len = cmd_len + INTF_HEADER_LEN; ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pmadapter->psleep_cfm, MNULL); if (ret == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "SLEEP_CFM: failed\n"); pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; goto done; } else { if ((wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY))->bss_type == MLAN_BSS_TYPE_STA) { if (!pps_mode->params.sleep_cfm.resp_ctrl) { /* Response is not needed for sleep confirm command */ pmadapter->ps_state = PS_STATE_SLEEP; } else { pmadapter->ps_state = PS_STATE_SLEEP_CFM; } if (pps_mode->params.sleep_cfm.resp_ctrl != RESP_NEEDED && (pmadapter->is_hs_configured && !pmadapter->sleep_period.period)) { pmadapter->pm_wakeup_card_req = MTRUE; wlan_host_sleep_activated_event(wlan_get_priv (pmadapter, MLAN_BSS_TYPE_STA), MTRUE); } } #define NUM_SC_PER_LINE 16 if (++i % NUM_SC_PER_LINE == 0) PRINTM(MEVENT, "+\n"); else PRINTM(MEVENT, "+"); } done: LEAVE(); return ret; }
/** * @brief This function tells firmware to send a NULL data packet. * * @param priv A pointer to mlan_private structure * @param flags Transmit Pkt Flags * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure */ mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags) { pmlan_adapter pmadapter = priv->adapter; TxPD *ptx_pd; /* sizeof(TxPD) + Interface specific header */ #define NULL_PACKET_HDR 256 t_u32 data_len = NULL_PACKET_HDR; pmlan_buffer pmbuf = MNULL; t_u8 *ptr; mlan_status ret = MLAN_STATUS_SUCCESS; #ifdef DEBUG_LEVEL1 t_u32 sec, usec; #endif ENTER(); if (pmadapter->surprise_removed == MTRUE) { ret = MLAN_STATUS_FAILURE; goto done; } if (priv->media_connected == MFALSE) { ret = MLAN_STATUS_FAILURE; goto done; } if (pmadapter->data_sent == MTRUE) { ret = MLAN_STATUS_FAILURE; goto done; } pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0, MOAL_MALLOC_BUFFER); if (!pmbuf) { ret = MLAN_STATUS_FAILURE; goto done; } memset(pmadapter, pmbuf->pbuf, 0, data_len); pmbuf->bss_index = priv->bss_index; pmbuf->buf_type = MLAN_BUF_TYPE_DATA; ptr = pmbuf->pbuf + pmbuf->data_offset; pmbuf->data_len = sizeof(TxPD) + INTF_HEADER_LEN; ptx_pd = (TxPD *) (ptr + INTF_HEADER_LEN); ptx_pd->tx_control = priv->pkt_tx_ctrl; ptx_pd->flags = flags; ptx_pd->priority = WMM_HIGHEST_PRIORITY; ptx_pd->tx_pkt_offset = sizeof(TxPD); /* Set the BSS number to TxPD */ ptx_pd->bss_num = GET_BSS_NUM(priv); ptx_pd->bss_type = priv->bss_type; endian_convert_TxPD(ptx_pd); ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, MNULL); switch (ret) { case MLAN_STATUS_RESOURCE: pmadapter->data_sent = MTRUE; /* Fall through FAILURE handling */ case MLAN_STATUS_FAILURE: wlan_free_mlan_buffer(pmadapter, pmbuf); PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n"); pmadapter->dbg.num_tx_host_to_card_failure++; goto done; case MLAN_STATUS_SUCCESS: wlan_free_mlan_buffer(pmadapter, pmbuf); PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n"); pmadapter->tx_lock_flag = MTRUE; break; case MLAN_STATUS_PENDING: break; default: break; } PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec); DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN); done: LEAVE(); return ret; }
/** * @brief This function downloads a command to firmware. * * @param pmpriv A pointer to mlan_private structure * @param pcmd_node A pointer to cmd_ctrl_node structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status wlan_dnld_cmd_to_fw(IN mlan_private * pmpriv, IN cmd_ctrl_node * pcmd_node) { mlan_adapter *pmadapter = pmpriv->adapter; mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks; mlan_status ret = MLAN_STATUS_SUCCESS; HostCmd_DS_COMMAND *pcmd; mlan_ioctl_req *pioctl_buf = MNULL; t_u16 cmd_code; t_u16 cmd_size; t_u32 sec, usec; ENTER(); if (!pmadapter || !pcmd_node) { ret = MLAN_STATUS_FAILURE; goto done; } pcmd = (HostCmd_DS_COMMAND *) (pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); if (pcmd_node->pioctl_buf != MNULL) pioctl_buf = (mlan_ioctl_req *) pcmd_node->pioctl_buf; /* Sanity test */ if (pcmd == MNULL || pcmd->size == 0) { PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, " "Not sending\n"); if (pioctl_buf != MNULL) pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL, wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); ret = MLAN_STATUS_FAILURE; goto done; } /* Set command sequence number */ pmadapter->seq_num++; pcmd->seq_num = wlan_cpu_to_le16(pmadapter->seq_num); wlan_request_cmd_lock(pmadapter); pmadapter->curr_cmd = pcmd_node; wlan_release_cmd_lock(pmadapter); cmd_code = wlan_le16_to_cpu(pcmd->command); cmd_size = wlan_le16_to_cpu(pcmd->size); /* Set BSS_NO_BITS to HostCmd */ cmd_code = HostCmd_SET_BSS_NO(cmd_code, pcmd_node->priv->bss_num); pcmd->command = wlan_cpu_to_le16(cmd_code); pcmd_node->cmdbuf->data_len = cmd_size; pmadapter->callbacks.moal_get_system_time(&sec, &usec); PRINTM(MCMND, "DNLD_CMD (%lu.%lu): 0x%x, act 0x%x, len %d, seqno %d\n", sec, usec, cmd_code, wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)), cmd_size, wlan_le16_to_cpu(pcmd->seq_num)); DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *) pcmd, cmd_size); /* Send the command to lower layer */ pcmd_node->cmdbuf->data_offset -= INTF_HEADER_LEN; pcmd_node->cmdbuf->data_len += INTF_HEADER_LEN; /* Extra header for SDIO is added here */ ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_CMD, pcmd_node->cmdbuf, MNULL); if (ret == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n"); if (pioctl_buf != MNULL) pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL, wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd); wlan_request_cmd_lock(pmadapter); pmadapter->curr_cmd = MNULL; wlan_release_cmd_lock(pmadapter); pmadapter->dbg.num_cmd_host_to_card_failure++; ret = MLAN_STATUS_FAILURE; goto done; } /* Save the last command id and action to debug log */ pmadapter->dbg.last_cmd_index = (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code; pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] = wlan_le16_to_cpu(*(t_u16 *) ((t_u8 *) pcmd + S_DS_GEN)); /* Clear BSS_NO_BITS from HostCmd */ cmd_code &= HostCmd_CMD_ID_MASK; /* Setup the timer after transmit command */ pcb->moal_start_timer(pmadapter->pmlan_cmd_timer, MFALSE, MRVDRV_TIMER_10S); pmadapter->cmd_timer_is_set = MTRUE; ret = MLAN_STATUS_SUCCESS; done: LEAVE(); return ret; }