static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_tx_queue_info qi; int ret = 0, qnum; if (queue >= IEEE80211_NUM_ACS) return 0; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); qi.tqi_aifs = params->aifs; qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; qi.tqi_burstTime = params->txop * 32; qnum = get_hw_qnum(queue, priv->hwq_map); ath_dbg(common, CONFIG, "Configure tx [queue/hwq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", queue, qnum, params->aifs, params->cw_min, params->cw_max, params->txop); ret = ath_htc_txq_update(priv, qnum, &qi); if (ret) { ath_err(common, "TXQ Update failed\n"); goto out; } if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) && (qnum == priv->hwq_map[IEEE80211_AC_BE])) ath9k_htc_beaconq_config(priv); out: ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; }
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ath9k_htc_sta *ista; struct ath9k_htc_tx_ctl tx_ctl; enum htc_endpoint_id epid; u16 qnum, hw_qnum; __le16 fc; u8 *tx_fhdr; u8 sta_idx, vif_idx; hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; if (tx_info->control.vif && (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv) vif_idx = ((struct ath9k_htc_vif *) tx_info->control.vif->drv_priv)->index; else vif_idx = priv->nvifs; if (sta) { ista = (struct ath9k_htc_sta *) sta->drv_priv; sta_idx = ista->index; } else { sta_idx = 0; } memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); if (ieee80211_is_data(fc)) { struct tx_frame_hdr tx_hdr; u8 *qc; memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); tx_hdr.node_idx = sta_idx; tx_hdr.vif_idx = vif_idx; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_ctl.type = ATH9K_HTC_AMPDU; tx_hdr.data_type = ATH9K_HTC_AMPDU; } else { tx_ctl.type = ATH9K_HTC_NORMAL; tx_hdr.data_type = ATH9K_HTC_NORMAL; } if (ieee80211_is_data(fc)) { qc = ieee80211_get_qos_ctl(hdr); tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } /* Check for RTS protection */ if (priv->hw->wiphy->rts_threshold != (u32) -1) if (skb->len > priv->hw->wiphy->rts_threshold) tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS; /* CTS-to-self */ if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) && (priv->op_flags & OP_PROTECT_ENABLE)) tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY; tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; else tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; tx_fhdr = skb_push(skb, sizeof(tx_hdr)); memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); qnum = skb_get_queue_mapping(skb); hw_qnum = get_hw_qnum(qnum, priv->hwq_map); switch (hw_qnum) { case 0: epid = priv->data_be_ep; break; case 2: epid = priv->data_vi_ep; break; case 3: epid = priv->data_vo_ep; break; case 1: default: epid = priv->data_bk_ep; break; } } else { struct tx_mgmt_hdr mgmt_hdr; memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); tx_ctl.type = ATH9K_HTC_NORMAL; mgmt_hdr.node_idx = sta_idx; mgmt_hdr.vif_idx = vif_idx; mgmt_hdr.tidno = 0; mgmt_hdr.flags = 0; mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; else mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); epid = priv->mgmt_ep; } return htc_send(priv->htc, skb, epid, &tx_ctl); }