/* This table inverses the tos_to_tid operation to get a priority * which is in sequential order, and can be compared. * Use this to compare the priority of two different TIDs.
*/ const u8 tos_to_tid_inv[] = {
0x02, /* from tos_to_tid[2] = 0 */
0x00, /* from tos_to_tid[0] = 1 */
0x01, /* from tos_to_tid[1] = 2 */
0x03,
0x04,
0x05,
0x06,
0x07
};
/* * This function debug prints the priority parameters for a WMM AC.
*/ staticvoid
mwifiex_wmm_ac_debug_print(conststruct ieee_types_wmm_ac_parameters *ac_param)
{ constchar *ac_str[] = { "BK", "BE", "VI", "VO" };
/* * This function allocates a route address list. * * The function also initializes the list with the provided RA.
*/ staticstruct mwifiex_ra_list_tbl *
mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, const u8 *ra)
{ struct mwifiex_ra_list_tbl *ra_list;
ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); if (!ra_list) return NULL;
/* This function returns random no between 16 and 32 to be used as threshold * for no of packets after which BA setup is initiated.
*/ static u8 mwifiex_get_random_ba_threshold(void)
{
u64 ns; /* setup ba_packet_threshold here random number between * [BA_SETUP_PACKET_OFFSET, * BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1]
*/
ns = ktime_get_ns();
ns += (ns >> 32) + (ns >> 16);
/* * This function allocates and adds a RA list for all TIDs * with the given RA.
*/ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
{ int i; struct mwifiex_ra_list_tbl *ra_list; struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_sta_node *node;
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
mwifiex_dbg(adapter, INFO, "info: created ra_list %p\n", ra_list);
/* Bubble sort */ for (i = 0; i < num_ac; i++) { for (j = 1; j < num_ac - i; j++) { if (tmp[j - 1] > tmp[j]) {
swap(tmp[j - 1], tmp[j]);
swap(priv->wmm.queue_priority[j - 1],
priv->wmm.queue_priority[j]);
} elseif (tmp[j - 1] == tmp[j]) { if (priv->wmm.queue_priority[j - 1]
< priv->wmm.queue_priority[j])
swap(priv->wmm.queue_priority[j - 1],
priv->wmm.queue_priority[j]);
}
}
}
mwifiex_wmm_queue_priorities_tid(priv);
}
/* * This function evaluates whether or not an AC is to be downgraded. * * In case the AC is not enabled, the highest AC is returned that is * enabled and does not require admission control.
*/ staticenum mwifiex_wmm_ac_e
mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv, enum mwifiex_wmm_ac_e eval_ac)
{ int down_ac; enum mwifiex_wmm_ac_e ret_ac; struct mwifiex_wmm_ac_status *ac_status;
ac_status = &priv->wmm.ac_status[eval_ac];
if (!ac_status->disabled) /* Okay to use this AC, its enabled */ return eval_ac;
/* Setup a default return value of the lowest priority */
ret_ac = WMM_AC_BK;
/* * Find the highest AC that is enabled and does not require * admission control. The spec disallows downgrading to an AC, * which is enabled due to a completed admission control. * Unadmitted traffic is not to be sent on an AC with admitted * traffic.
*/ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
ac_status = &priv->wmm.ac_status[down_ac];
if (!ac_status->disabled && !ac_status->flow_required) /* AC is enabled and does not require admission
control */
ret_ac = (enum mwifiex_wmm_ac_e) down_ac;
}
return ret_ac;
}
/* * This function downgrades WMM priority queue.
*/ void
mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
{ int ac_val;
mwifiex_dbg(priv->adapter, INFO, "info: WMM: AC Priorities:\t" "BK(0), BE(1), VI(2), VO(3)\n");
if (!priv->wmm_enabled) { /* WMM is not enabled, default priorities */ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++)
priv->wmm.ac_down_graded_vals[ac_val] =
(enum mwifiex_wmm_ac_e) ac_val;
} else { for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
priv->wmm.ac_down_graded_vals[ac_val]
= mwifiex_wmm_eval_downgrade_ac(priv,
(enum mwifiex_wmm_ac_e) ac_val);
mwifiex_dbg(priv->adapter, INFO, "info: WMM: AC PRIO %d maps to %d\n",
ac_val,
priv->wmm.ac_down_graded_vals[ac_val]);
}
}
}
/* * This function converts the IP TOS field to an WMM AC * Queue assignment.
*/ staticenum mwifiex_wmm_ac_e
mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
{ /* Map of TOS UP values to WMM AC */ staticconstenum mwifiex_wmm_ac_e tos_to_ac[] = {
WMM_AC_BE,
WMM_AC_BK,
WMM_AC_BK,
WMM_AC_BE,
WMM_AC_VI,
WMM_AC_VI,
WMM_AC_VO,
WMM_AC_VO
};
if (tos >= ARRAY_SIZE(tos_to_ac)) return WMM_AC_BE;
return tos_to_ac[tos];
}
/* * This function evaluates a given TID and downgrades it to a lower * TID if the WMM Parameter IE received from the AP indicates that the * AP is disabled (due to call admission control (ACM bit). Mapping * of TID to AC is taken care of internally.
*/
u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
{ enum mwifiex_wmm_ac_e ac, ac_down;
u8 new_tid;
ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid);
ac_down = priv->wmm.ac_down_graded_vals[ac];
/* Send the index to tid array, picking from the array will be * taken care by dequeuing function
*/
new_tid = ac_to_tid[ac_down][tid % 2];
return new_tid;
}
/* * This function initializes the WMM state information and the * WMM data path queues.
*/ void
mwifiex_wmm_init(struct mwifiex_adapter *adapter)
{ int i, j; struct mwifiex_private *priv;
for (j = 0; j < adapter->priv_num; ++j) {
priv = adapter->priv[j]; if (!priv) continue;
for (i = 0; i < MAX_NUM_TID; ++i) { if (!disable_tx_amsdu &&
adapter->tx_buf_size > MWIFIEX_TX_DATA_BUF_SIZE_2K)
priv->aggr_prio_tbl[i].amsdu =
priv->tos_to_tid_inv[i]; else
priv->aggr_prio_tbl[i].amsdu =
BA_STREAM_NOT_ALLOWED;
priv->aggr_prio_tbl[i].ampdu_ap =
priv->tos_to_tid_inv[i];
priv->aggr_prio_tbl[i].ampdu_user =
priv->tos_to_tid_inv[i];
}
int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter)
{ struct mwifiex_private *priv; int i;
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i]; if (adapter->if_ops.is_port_ready &&
!adapter->if_ops.is_port_ready(priv)) continue; if (!skb_queue_empty(&priv->bypass_txq)) returnfalse;
}
returntrue;
}
/* * This function checks if WMM Tx queue is empty.
*/ int
mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
{ int i; struct mwifiex_private *priv;
for (i = 0; i < adapter->priv_num; ++i) {
priv = adapter->priv[i]; if (!priv->port_open &&
(priv->bss_mode != NL80211_IFTYPE_ADHOC)) continue; if (adapter->if_ops.is_port_ready &&
!adapter->if_ops.is_port_ready(priv)) continue; if (atomic_read(&priv->wmm.tx_pkts_queued)) returnfalse;
}
returntrue;
}
/* * This function deletes all packets in an RA list node. * * The packet sent completion callback handler are called with * status failure, after they are dequeued to ensure proper * cleanup. The RA list node itself is freed at the end.
*/ staticvoid
mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra_list)
{ struct mwifiex_adapter *adapter = priv->adapter; struct sk_buff *skb, *tmp;
/* * This function deletes all packets in an RA list. * * Each nodes in the RA list are freed individually first, and then * the RA list itself is freed.
*/ staticvoid
mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv, struct list_head *ra_list_head)
{ struct mwifiex_ra_list_tbl *ra_list;
/* * This function deletes all route addresses from all RA lists.
*/ staticvoid mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
{ struct mwifiex_ra_list_tbl *ra_list, *tmp_node; int i;
for (i = 0; i < MAX_NUM_TID; ++i) {
mwifiex_dbg(priv->adapter, INFO, "info: ra_list: freeing buf for tid %d\n", i);
list_for_each_entry_safe(ra_list, tmp_node,
&priv->wmm.tid_tbl_ptr[i].ra_list,
list) {
list_del(&ra_list->list);
kfree(ra_list);
}
/* * This function cleans up the Tx and Rx queues. * * Cleanup includes - * - All packets in RA lists * - All entries in Rx reorder table * - All entries in Tx BA stream table * - MPA buffer (if required) * - All RA lists
*/ void
mwifiex_clean_txrx(struct mwifiex_private *priv)
{ struct sk_buff *skb, *tmp;
/* * This function retrieves a particular RA list node, matching with the * given TID and RA address.
*/ struct mwifiex_ra_list_tbl *
mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr)
{ struct mwifiex_ra_list_tbl *ra_list;
/* This function updates non-tdls peer ralist tx_pause while * tdls channel switching
*/ void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv,
u8 *mac, u8 tx_pause)
{ struct mwifiex_ra_list_tbl *ra_list;
u32 pkt_cnt = 0, tx_pkts_queued; int i;
spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; ++i) {
list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[i].ra_list,
list) { if (!memcmp(ra_list->ra, mac, ETH_ALEN)) continue;
/* * This function retrieves an RA list node for a given TID and * RA address pair. * * If no such node is found, a new node is added first and then * retrieved.
*/ struct mwifiex_ra_list_tbl *
mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr)
{ struct mwifiex_ra_list_tbl *ra_list;
/* * This function deletes RA list nodes for given mac for all TIDs. * Function also decrements TX pending count accordingly.
*/ void
mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv, const u8 *ra_addr)
{ struct mwifiex_ra_list_tbl *ra_list; int i;
spin_lock_bh(&priv->wmm.ra_list_spinlock);
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_get_ralist_node(priv, i, ra_addr);
if (!ra_list) continue;
mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list); if (ra_list->tx_paused)
priv->wmm.pkts_paused[i] -= ra_list->total_pkt_count; else
atomic_sub(ra_list->total_pkt_count,
&priv->wmm.tx_pkts_queued);
list_del(&ra_list->list);
kfree(ra_list);
}
spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/* * This function checks if a particular RA list node exists in a given TID * table index.
*/ int
mwifiex_is_ralist_valid(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra_list, int ptr_index)
{ struct mwifiex_ra_list_tbl *rlist;
list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list,
list) { if (rlist == ra_list) returntrue;
}
returnfalse;
}
/* * This function adds a packet to bypass TX queue. * This is special TX queue for packets which can be sent even when port_open * is false.
*/ void
mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, struct sk_buff *skb)
{
skb_queue_tail(&priv->bypass_txq, skb);
}
/* * This function adds a packet to WMM queue. * * In disconnected state the packet is immediately dropped and the * packet send completion callback is called with status failure. * * Otherwise, the correct RA list node is located and the packet * is queued at the list tail.
*/ void
mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, struct sk_buff *skb)
{ struct mwifiex_adapter *adapter = priv->adapter;
u32 tid; struct mwifiex_ra_list_tbl *ra_list;
u8 ra[ETH_ALEN], tid_down; struct list_head list_head; int tdls_status = TDLS_NOT_SETUP; struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
memcpy(ra, eth_hdr->h_dest, ETH_ALEN);
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) { if (ntohs(eth_hdr->h_proto) == ETH_P_TDLS)
mwifiex_dbg(adapter, DATA, "TDLS setup packet for %pM.\t" "Don't block\n", ra); elseif (memcmp(priv->cfg_bssid, ra, ETH_ALEN))
tdls_status = mwifiex_get_tdls_link_status(priv, ra);
}
if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
mwifiex_dbg(adapter, DATA, "data: drop packet in disconnect\n");
mwifiex_write_data_complete(adapter, skb, 0, -1); return;
}
tid = skb->priority;
spin_lock_bh(&priv->wmm.ra_list_spinlock);
tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
/* In case of infra as we have already created the list during association we just don't have to call get_queue_raptr, we will
have only 1 raptr for a tid in case of infra */ if (!mwifiex_queuing_ra_based(priv) &&
!mwifiex_is_skb_mgmt_frame(skb)) { switch (tdls_status) { case TDLS_SETUP_COMPLETE: case TDLS_CHAN_SWITCHING: case TDLS_IN_BASE_CHAN: case TDLS_IN_OFF_CHAN:
ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down,
ra);
tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; break; case TDLS_SETUP_INPROGRESS:
skb_queue_tail(&priv->tdls_txq, skb);
spin_unlock_bh(&priv->wmm.ra_list_spinlock); return; default:
list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list;
ra_list = list_first_entry_or_null(&list_head, struct mwifiex_ra_list_tbl, list); break;
}
} else {
memcpy(ra, skb->data, ETH_ALEN); if (is_multicast_ether_addr(ra) || mwifiex_is_skb_mgmt_frame(skb))
eth_broadcast_addr(ra);
ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
}
if (!ra_list) {
spin_unlock_bh(&priv->wmm.ra_list_spinlock);
mwifiex_write_data_complete(adapter, skb, 0, -1); return;
}
if (atomic_read(&priv->wmm.highest_queued_prio) <
priv->tos_to_tid_inv[tid_down])
atomic_set(&priv->wmm.highest_queued_prio,
priv->tos_to_tid_inv[tid_down]);
if (ra_list->tx_paused)
priv->wmm.pkts_paused[tid_down]++; else
atomic_inc(&priv->wmm.tx_pkts_queued);
spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/* * This function processes the get WMM status command response from firmware. * * The response may contain multiple TLVs - * - AC Queue status TLVs * - Current WMM Parameter IE TLV * - Admission Control action frame TLVs * * This function parses the TLVs and then calls further specific functions * to process any changes in the queue prioritize or state.
*/ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, conststruct host_cmd_ds_command *resp)
{
u8 *curr = (u8 *) &resp->params.get_wmm_status;
uint16_t resp_len = le16_to_cpu(resp->size), tlv_len; int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK; bool valid = true;
/* * Callback handler from the command module to allow insertion of a WMM TLV. * * If the BSS we are associating to supports WMM, this function adds the * required WMM Information IE to the association request command buffer in * the form of a Marvell extended IEEE IE.
*/
u32
mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
u8 **assoc_buf, struct ieee_types_wmm_parameter *wmm_ie, struct ieee80211_ht_cap *ht_cap)
{ struct mwifiex_ie_types_wmm_param_set *wmm_tlv;
u32 ret_len = 0;
/* Null checks */ if (!assoc_buf) return 0; if (!(*assoc_buf)) return 0;
if (!wmm_ie) return 0;
mwifiex_dbg(priv->adapter, INFO, "info: WMM: process assoc req: bss->wmm_ie=%#x\n",
wmm_ie->vend_hdr.element_id);
/* * This function computes the time delay in the driver queues for a * given packet. * * When the packet is received at the OS/Driver interface, the current * time is set in the packet structure. The difference between the present * time and that received time is computed in this function and limited * based on pre-compiled limits in the driver.
*/
u8
mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, conststruct sk_buff *skb)
{
u32 queue_delay = ktime_to_ms(net_timedelta(skb->tstamp));
u8 ret_val;
/* * Queue delay is passed as a uint8 in units of 2ms (ms shifted * by 1). Min value (other than 0) is therefore 2ms, max is 510ms. * * Pass max value if queue_delay is beyond the uint8 range
*/
ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
mwifiex_dbg(priv->adapter, DATA, "data: WMM: Pkt Delay: %d ms,\t" "%d ms sent to FW\n", queue_delay, ret_val);
return ret_val;
}
/* * This function retrieves the highest priority RA list table pointer.
*/ staticstruct mwifiex_ra_list_tbl *
mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, struct mwifiex_private **priv, int *tid)
{ struct mwifiex_private *priv_tmp; struct mwifiex_ra_list_tbl *ptr; struct mwifiex_tid_tbl *tid_ptr;
atomic_t *hqp; int i, j;
/* check the BSS with highest priority first */ for (j = adapter->priv_num - 1; j >= 0; --j) { /* iterate over BSS with the equal priority */
list_for_each_entry(adapter->bss_prio_tbl[j].bss_prio_cur,
&adapter->bss_prio_tbl[j].bss_prio_head,
list) {
if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) != 0) {
atomic_set(&priv_tmp->wmm.highest_queued_prio,
HIGH_PRIO_TID); /* Iterate current private once more, since * there still exist packets in data queue
*/ goto try_again;
} else
atomic_set(&priv_tmp->wmm.highest_queued_prio,
NO_PKT_PRIO_TID);
}
}
/* This functions rotates ra and bss lists so packets are picked round robin. * * After a packet is successfully transmitted, rotate the ra list, so the ra * next to the one transmitted, will come first in the list. This way we pick * the ra' in a round robin fashion. Same applies to bss nodes of equal * priority. * * Function also increments wmm.packets_out counter.
*/ void mwifiex_rotate_priolists(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra, int tid)
{ struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bss_prio_tbl *tbl = adapter->bss_prio_tbl; struct mwifiex_tid_tbl *tid_ptr = &priv->wmm.tid_tbl_ptr[tid];
spin_lock_bh(&tbl[priv->bss_priority].bss_prio_lock); /* * dirty trick: we remove 'head' temporarily and reinsert it after * curr bss node. imagine list to stay fixed while head is moved
*/
list_move(&tbl[priv->bss_priority].bss_prio_head,
&tbl[priv->bss_priority].bss_prio_cur->list);
spin_unlock_bh(&tbl[priv->bss_priority].bss_prio_lock);
spin_lock_bh(&priv->wmm.ra_list_spinlock); if (mwifiex_is_ralist_valid(priv, ra, tid)) {
priv->wmm.packets_out[tid]++; /* same as above */
list_move(&tid_ptr->ra_list, &ra->list);
}
spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}
/* * This function checks if 11n aggregation is possible.
*/ staticint
mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ptr, int max_buf_size)
{ int count = 0, total_size = 0; struct sk_buff *skb, *tmp; int max_amsdu_size;
/* * This function checks if the first packet in the given RA list * is already processed or not.
*/ staticint
mwifiex_is_ptr_processed(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ptr)
{ struct sk_buff *skb; struct mwifiex_txinfo *tx_info;
if (skb_queue_empty(&ptr->skb_head)) returnfalse;
skb = skb_peek(&ptr->skb_head);
tx_info = MWIFIEX_SKB_TXCB(skb); if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT) returntrue;
returnfalse;
}
/* * This function sends a single processed packet to firmware for * transmission.
*/ staticvoid
mwifiex_send_processed_packet(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ptr, int ptr_index)
__releases(&priv->wmm.ra_list_spinlock)
{ struct mwifiex_tx_param tx_param; struct mwifiex_adapter *adapter = priv->adapter; int ret = -1; struct sk_buff *skb, *skb_next; struct mwifiex_txinfo *tx_info;
if (skb_queue_empty(&ptr->skb_head)) {
spin_unlock_bh(&priv->wmm.ra_list_spinlock); return;
}
/* * This function dequeues a packet from the highest priority list * and transmits it.
*/ staticint
mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
{ struct mwifiex_ra_list_tbl *ptr; struct mwifiex_private *priv = NULL; int ptr_index = 0;
u8 ra[ETH_ALEN]; int tid_del = 0, tid = 0;
ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index); if (!ptr) return -1;
spin_lock_bh(&priv->wmm.ra_list_spinlock); if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
spin_unlock_bh(&priv->wmm.ra_list_spinlock); return -1;
}
if (mwifiex_is_ptr_processed(priv, ptr)) {
mwifiex_send_processed_packet(priv, ptr, ptr_index); /* ra_list_spinlock has been freed in
mwifiex_send_processed_packet() */ return 0;
}
if (!ptr->is_11n_enabled ||
ptr->ba_status ||
priv->wps.session_enable) { if (ptr->is_11n_enabled &&
ptr->ba_status &&
ptr->amsdu_in_ampdu &&
mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index); /* ra_list_spinlock has been freed in * mwifiex_11n_aggregate_pkt()
*/ else
mwifiex_send_single_packet(priv, ptr, ptr_index); /* ra_list_spinlock has been freed in * mwifiex_send_single_packet()
*/
} else { if (mwifiex_is_ampdu_allowed(priv, ptr, tid) &&
ptr->ba_pkt_count > ptr->ba_packet_thr) { if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
mwifiex_create_ba_tbl(priv, ptr->ra, tid,
BA_SETUP_INPROGRESS);
mwifiex_send_addba(priv, tid, ptr->ra);
} elseif (mwifiex_find_stream_to_delete
(priv, tid, &tid_del, ra)) {
mwifiex_create_ba_tbl(priv, ptr->ra, tid,
BA_SETUP_INPROGRESS);
mwifiex_send_delba(priv, tid_del, ra, 1);
}
} if (mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index); /* ra_list_spinlock has been freed in
mwifiex_11n_aggregate_pkt() */ else
mwifiex_send_single_packet(priv, ptr, ptr_index); /* ra_list_spinlock has been freed in
mwifiex_send_single_packet() */
} return 0;
}
/* * This function transmits the highest priority packet awaiting in the * WMM Queues.
*/ void
mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
{ do { if (mwifiex_dequeue_tx_packet(adapter)) break; if (adapter->iface_type != MWIFIEX_SDIO) { if (adapter->data_sent ||
adapter->tx_lock_flag) break;
} else { if (atomic_read(&adapter->tx_queued) >=
MWIFIEX_MAX_PKTS_TXQ) break;
}
} while (!mwifiex_wmm_lists_empty(adapter));
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.7 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.