123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /**
- * Copyright (c) 2014 Redpine Signals Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "rsi_mgmt.h"
- #include "rsi_common.h"
- #include "rsi_hal.h"
- #include "rsi_coex.h"
- /**
- * rsi_determine_min_weight_queue() - This function determines the queue with
- * the min weight.
- * @common: Pointer to the driver private structure.
- *
- * Return: q_num: Corresponding queue number.
- */
- static u8 rsi_determine_min_weight_queue(struct rsi_common *common)
- {
- struct wmm_qinfo *tx_qinfo = common->tx_qinfo;
- u32 q_len = 0;
- u8 ii = 0;
- for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) {
- q_len = skb_queue_len(&common->tx_queue[ii]);
- if ((tx_qinfo[ii].pkt_contended) && q_len) {
- common->min_weight = tx_qinfo[ii].weight;
- break;
- }
- }
- return ii;
- }
- /**
- * rsi_recalculate_weights() - This function recalculates the weights
- * corresponding to each queue.
- * @common: Pointer to the driver private structure.
- *
- * Return: recontend_queue bool variable
- */
- static bool rsi_recalculate_weights(struct rsi_common *common)
- {
- struct wmm_qinfo *tx_qinfo = common->tx_qinfo;
- bool recontend_queue = false;
- u8 ii = 0;
- u32 q_len = 0;
- for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) {
- q_len = skb_queue_len(&common->tx_queue[ii]);
- /* Check for the need of contention */
- if (q_len) {
- if (tx_qinfo[ii].pkt_contended) {
- tx_qinfo[ii].weight =
- ((tx_qinfo[ii].weight > common->min_weight) ?
- tx_qinfo[ii].weight - common->min_weight : 0);
- } else {
- tx_qinfo[ii].pkt_contended = 1;
- tx_qinfo[ii].weight = tx_qinfo[ii].wme_params;
- recontend_queue = true;
- }
- } else { /* No packets so no contention */
- tx_qinfo[ii].weight = 0;
- tx_qinfo[ii].pkt_contended = 0;
- }
- }
- return recontend_queue;
- }
- /**
- * rsi_get_num_pkts_dequeue() - This function determines the number of
- * packets to be dequeued based on the number
- * of bytes calculated using txop.
- *
- * @common: Pointer to the driver private structure.
- * @q_num: the queue from which pkts have to be dequeued
- *
- * Return: pkt_num: Number of pkts to be dequeued.
- */
- static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num)
- {
- struct rsi_hw *adapter = common->priv;
- struct sk_buff *skb;
- u32 pkt_cnt = 0;
- s16 txop = common->tx_qinfo[q_num].txop * 32;
- __le16 r_txop;
- struct ieee80211_rate rate;
- struct ieee80211_hdr *wh;
- struct ieee80211_vif *vif;
- rate.bitrate = RSI_RATE_MCS0 * 5 * 10; /* Convert to Kbps */
- if (q_num == VI_Q)
- txop = ((txop << 5) / 80);
- if (skb_queue_len(&common->tx_queue[q_num]))
- skb = skb_peek(&common->tx_queue[q_num]);
- else
- return 0;
- do {
- wh = (struct ieee80211_hdr *)skb->data;
- vif = rsi_get_vif(adapter, wh->addr2);
- r_txop = ieee80211_generic_frame_duration(adapter->hw,
- vif,
- common->band,
- skb->len, &rate);
- txop -= le16_to_cpu(r_txop);
- pkt_cnt += 1;
- /*checking if pkts are still there*/
- if (skb_queue_len(&common->tx_queue[q_num]) - pkt_cnt)
- skb = skb->next;
- else
- break;
- } while (txop > 0);
- return pkt_cnt;
- }
- /**
- * rsi_core_determine_hal_queue() - This function determines the queue from
- * which packet has to be dequeued.
- * @common: Pointer to the driver private structure.
- *
- * Return: q_num: Corresponding queue number on success.
- */
- static u8 rsi_core_determine_hal_queue(struct rsi_common *common)
- {
- bool recontend_queue = false;
- u32 q_len = 0;
- u8 q_num = INVALID_QUEUE;
- u8 ii = 0;
- if (skb_queue_len(&common->tx_queue[MGMT_BEACON_Q])) {
- q_num = MGMT_BEACON_Q;
- return q_num;
- }
- if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) {
- if (!common->mgmt_q_block)
- q_num = MGMT_SOFT_Q;
- return q_num;
- }
- if (common->hw_data_qs_blocked)
- return q_num;
- if (common->pkt_cnt != 0) {
- --common->pkt_cnt;
- return common->selected_qnum;
- }
- get_queue_num:
- recontend_queue = false;
- q_num = rsi_determine_min_weight_queue(common);
- ii = q_num;
- /* Selecting the queue with least back off */
- for (; ii < NUM_EDCA_QUEUES; ii++) {
- q_len = skb_queue_len(&common->tx_queue[ii]);
- if (((common->tx_qinfo[ii].pkt_contended) &&
- (common->tx_qinfo[ii].weight < common->min_weight)) &&
- q_len) {
- common->min_weight = common->tx_qinfo[ii].weight;
- q_num = ii;
- }
- }
- if (q_num < NUM_EDCA_QUEUES)
- common->tx_qinfo[q_num].pkt_contended = 0;
- /* Adjust the back off values for all queues again */
- recontend_queue = rsi_recalculate_weights(common);
- q_len = skb_queue_len(&common->tx_queue[q_num]);
- if (!q_len) {
- /* If any queues are freshly contended and the selected queue
- * doesn't have any packets
- * then get the queue number again with fresh values
- */
- if (recontend_queue)
- goto get_queue_num;
- q_num = INVALID_QUEUE;
- return q_num;
- }
- common->selected_qnum = q_num;
- q_len = skb_queue_len(&common->tx_queue[q_num]);
- if (q_num == VO_Q || q_num == VI_Q) {
- common->pkt_cnt = rsi_get_num_pkts_dequeue(common, q_num);
- common->pkt_cnt -= 1;
- }
- return q_num;
- }
- /**
- * rsi_core_queue_pkt() - This functions enqueues the packet to the queue
- * specified by the queue number.
- * @common: Pointer to the driver private structure.
- * @skb: Pointer to the socket buffer structure.
- *
- * Return: None.
- */
- static void rsi_core_queue_pkt(struct rsi_common *common,
- struct sk_buff *skb)
- {
- u8 q_num = skb->priority;
- if (q_num >= NUM_SOFT_QUEUES) {
- rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n",
- __func__, q_num);
- dev_kfree_skb(skb);
- return;
- }
- skb_queue_tail(&common->tx_queue[q_num], skb);
- }
- /**
- * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue
- * specified by the queue number.
- * @common: Pointer to the driver private structure.
- * @q_num: Queue number.
- *
- * Return: Pointer to sk_buff structure.
- */
- static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common,
- u8 q_num)
- {
- if (q_num >= NUM_SOFT_QUEUES) {
- rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n",
- __func__, q_num);
- return NULL;
- }
- return skb_dequeue(&common->tx_queue[q_num]);
- }
- /**
- * rsi_core_qos_processor() - This function is used to determine the wmm queue
- * based on the backoff procedure. Data packets are
- * dequeued from the selected hal queue and sent to
- * the below layers.
- * @common: Pointer to the driver private structure.
- *
- * Return: None.
- */
- void rsi_core_qos_processor(struct rsi_common *common)
- {
- struct rsi_hw *adapter = common->priv;
- struct sk_buff *skb;
- unsigned long tstamp_1, tstamp_2;
- u8 q_num;
- int status;
- tstamp_1 = jiffies;
- while (1) {
- q_num = rsi_core_determine_hal_queue(common);
- rsi_dbg(DATA_TX_ZONE,
- "%s: Queue number = %d\n", __func__, q_num);
- if (q_num == INVALID_QUEUE) {
- rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__);
- break;
- }
- if (common->hibernate_resume)
- break;
- mutex_lock(&common->tx_lock);
- status = adapter->check_hw_queue_status(adapter, q_num);
- if ((status <= 0)) {
- mutex_unlock(&common->tx_lock);
- break;
- }
- if ((q_num < MGMT_SOFT_Q) &&
- ((skb_queue_len(&common->tx_queue[q_num])) <=
- MIN_DATA_QUEUE_WATER_MARK)) {
- if (ieee80211_queue_stopped(adapter->hw, WME_AC(q_num)))
- ieee80211_wake_queue(adapter->hw,
- WME_AC(q_num));
- }
- skb = rsi_core_dequeue_pkt(common, q_num);
- if (skb == NULL) {
- rsi_dbg(ERR_ZONE, "skb null\n");
- mutex_unlock(&common->tx_lock);
- break;
- }
- if (q_num == MGMT_BEACON_Q) {
- status = rsi_send_pkt_to_bus(common, skb);
- dev_kfree_skb(skb);
- } else {
- #ifdef CONFIG_RSI_COEX
- if (common->coex_mode > 1) {
- status = rsi_coex_send_pkt(common, skb,
- RSI_WLAN_Q);
- } else {
- #endif
- if (q_num == MGMT_SOFT_Q)
- status = rsi_send_mgmt_pkt(common, skb);
- else
- status = rsi_send_data_pkt(common, skb);
- #ifdef CONFIG_RSI_COEX
- }
- #endif
- }
- if (status) {
- mutex_unlock(&common->tx_lock);
- break;
- }
- common->tx_stats.total_tx_pkt_send[q_num]++;
- tstamp_2 = jiffies;
- mutex_unlock(&common->tx_lock);
- if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000))
- schedule();
- }
- }
- struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr)
- {
- int i;
- for (i = 0; i < common->max_stations; i++) {
- if (!common->stations[i].sta)
- continue;
- if (!(memcmp(common->stations[i].sta->addr,
- mac_addr, ETH_ALEN)))
- return &common->stations[i];
- }
- return NULL;
- }
- struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac)
- {
- struct ieee80211_vif *vif;
- int i;
- for (i = 0; i < RSI_MAX_VIFS; i++) {
- vif = adapter->vifs[i];
- if (!vif)
- continue;
- if (!memcmp(vif->addr, mac, ETH_ALEN))
- return vif;
- }
- return NULL;
- }
- /**
- * rsi_core_xmit() - This function transmits the packets received from mac80211
- * @common: Pointer to the driver private structure.
- * @skb: Pointer to the socket buffer structure.
- *
- * Return: None.
- */
- void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
- {
- struct rsi_hw *adapter = common->priv;
- struct ieee80211_tx_info *info;
- struct skb_info *tx_params;
- struct ieee80211_hdr *wh = NULL;
- struct ieee80211_vif *vif;
- u8 q_num, tid = 0;
- struct rsi_sta *rsta = NULL;
- if ((!skb) || (!skb->len)) {
- rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n",
- __func__);
- goto xmit_fail;
- }
- if (common->fsm_state != FSM_MAC_INIT_DONE) {
- rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__);
- goto xmit_fail;
- }
- if (common->wow_flags & RSI_WOW_ENABLED) {
- rsi_dbg(ERR_ZONE,
- "%s: Blocking Tx_packets when WOWLAN is enabled\n",
- __func__);
- goto xmit_fail;
- }
- info = IEEE80211_SKB_CB(skb);
- tx_params = (struct skb_info *)info->driver_data;
- wh = (struct ieee80211_hdr *)&skb->data[0];
- tx_params->sta_id = 0;
- vif = rsi_get_vif(adapter, wh->addr2);
- if (!vif)
- goto xmit_fail;
- tx_params->vif = vif;
- tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id;
- if ((ieee80211_is_mgmt(wh->frame_control)) ||
- (ieee80211_is_ctl(wh->frame_control)) ||
- (ieee80211_is_qos_nullfunc(wh->frame_control))) {
- if (ieee80211_is_assoc_req(wh->frame_control) ||
- ieee80211_is_reassoc_req(wh->frame_control)) {
- struct ieee80211_bss_conf *bss = &vif->bss_conf;
- common->eapol4_confirm = false;
- rsi_hal_send_sta_notify_frame(common,
- RSI_IFTYPE_STATION,
- STA_CONNECTED, bss->bssid,
- bss->qos, bss->aid, 0,
- vif);
- }
- q_num = MGMT_SOFT_Q;
- skb->priority = q_num;
- if (rsi_prepare_mgmt_desc(common, skb)) {
- rsi_dbg(ERR_ZONE, "Failed to prepare desc\n");
- goto xmit_fail;
- }
- } else {
- if (ieee80211_is_data_qos(wh->frame_control)) {
- u8 *qos = ieee80211_get_qos_ctl(wh);
- tid = *qos & IEEE80211_QOS_CTL_TID_MASK;
- skb->priority = TID_TO_WME_AC(tid);
- } else {
- tid = IEEE80211_NONQOS_TID;
- skb->priority = BE_Q;
- }
- q_num = skb->priority;
- tx_params->tid = tid;
- if (((vif->type == NL80211_IFTYPE_AP) ||
- (vif->type == NL80211_IFTYPE_P2P_GO)) &&
- (!is_broadcast_ether_addr(wh->addr1)) &&
- (!is_multicast_ether_addr(wh->addr1))) {
- rsta = rsi_find_sta(common, wh->addr1);
- if (!rsta)
- goto xmit_fail;
- tx_params->sta_id = rsta->sta_id;
- } else {
- tx_params->sta_id = 0;
- }
- if (rsta) {
- /* Start aggregation if not done for this tid */
- if (!rsta->start_tx_aggr[tid]) {
- rsta->start_tx_aggr[tid] = true;
- ieee80211_start_tx_ba_session(rsta->sta,
- tid, 0);
- }
- }
- if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
- q_num = MGMT_SOFT_Q;
- skb->priority = q_num;
- }
- if (rsi_prepare_data_desc(common, skb)) {
- rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n");
- goto xmit_fail;
- }
- }
- if ((q_num < MGMT_SOFT_Q) &&
- ((skb_queue_len(&common->tx_queue[q_num]) + 1) >=
- DATA_QUEUE_WATER_MARK)) {
- rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__);
- if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num)))
- ieee80211_stop_queue(adapter->hw, WME_AC(q_num));
- rsi_set_event(&common->tx_thread.event);
- goto xmit_fail;
- }
- rsi_core_queue_pkt(common, skb);
- rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thread <===\n", __func__);
- rsi_set_event(&common->tx_thread.event);
- return;
- xmit_fail:
- rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__);
- /* Dropping pkt here */
- ieee80211_free_txskb(common->priv->hw, skb);
- }
|