Commit | Line | Data |
---|---|---|
dad0d04f FF |
1 | /** |
2 | * Copyright (c) 2014 Redpine Signals Inc. | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include "rsi_mgmt.h" | |
18 | #include "rsi_common.h" | |
19 | ||
20 | /** | |
21 | * rsi_determine_min_weight_queue() - This function determines the queue with | |
22 | * the min weight. | |
23 | * @common: Pointer to the driver private structure. | |
24 | * | |
25 | * Return: q_num: Corresponding queue number. | |
26 | */ | |
27 | static u8 rsi_determine_min_weight_queue(struct rsi_common *common) | |
28 | { | |
29 | struct wmm_qinfo *tx_qinfo = common->tx_qinfo; | |
30 | u32 q_len = 0; | |
31 | u8 ii = 0; | |
32 | ||
33 | for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { | |
34 | q_len = skb_queue_len(&common->tx_queue[ii]); | |
35 | if ((tx_qinfo[ii].pkt_contended) && q_len) { | |
36 | common->min_weight = tx_qinfo[ii].weight; | |
37 | break; | |
38 | } | |
39 | } | |
40 | return ii; | |
41 | } | |
42 | ||
43 | /** | |
44 | * rsi_recalculate_weights() - This function recalculates the weights | |
45 | * corresponding to each queue. | |
46 | * @common: Pointer to the driver private structure. | |
47 | * | |
48 | * Return: recontend_queue bool variable | |
49 | */ | |
50 | static bool rsi_recalculate_weights(struct rsi_common *common) | |
51 | { | |
52 | struct wmm_qinfo *tx_qinfo = common->tx_qinfo; | |
53 | bool recontend_queue = false; | |
54 | u8 ii = 0; | |
55 | u32 q_len = 0; | |
56 | ||
57 | for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { | |
58 | q_len = skb_queue_len(&common->tx_queue[ii]); | |
59 | /* Check for the need of contention */ | |
60 | if (q_len) { | |
61 | if (tx_qinfo[ii].pkt_contended) { | |
62 | tx_qinfo[ii].weight = | |
63 | ((tx_qinfo[ii].weight > common->min_weight) ? | |
64 | tx_qinfo[ii].weight - common->min_weight : 0); | |
65 | } else { | |
66 | tx_qinfo[ii].pkt_contended = 1; | |
67 | tx_qinfo[ii].weight = tx_qinfo[ii].wme_params; | |
68 | recontend_queue = true; | |
69 | } | |
70 | } else { /* No packets so no contention */ | |
71 | tx_qinfo[ii].weight = 0; | |
72 | tx_qinfo[ii].pkt_contended = 0; | |
73 | } | |
74 | } | |
75 | ||
76 | return recontend_queue; | |
77 | } | |
78 | ||
79 | /** | |
80 | * rsi_core_determine_hal_queue() - This function determines the queue from | |
81 | * which packet has to be dequeued. | |
82 | * @common: Pointer to the driver private structure. | |
83 | * | |
84 | * Return: q_num: Corresponding queue number on success. | |
85 | */ | |
86 | static u8 rsi_core_determine_hal_queue(struct rsi_common *common) | |
87 | { | |
88 | bool recontend_queue = false; | |
89 | u32 q_len = 0; | |
90 | u8 q_num = INVALID_QUEUE; | |
91 | u8 ii, min = 0; | |
92 | ||
93 | if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { | |
94 | if (!common->mgmt_q_block) | |
95 | q_num = MGMT_SOFT_Q; | |
96 | return q_num; | |
97 | } | |
98 | ||
99 | if (common->pkt_cnt != 0) { | |
100 | --common->pkt_cnt; | |
101 | return common->selected_qnum; | |
102 | } | |
103 | ||
104 | get_queue_num: | |
105 | q_num = 0; | |
106 | recontend_queue = false; | |
107 | ||
108 | q_num = rsi_determine_min_weight_queue(common); | |
109 | q_len = skb_queue_len(&common->tx_queue[ii]); | |
110 | ii = q_num; | |
111 | ||
112 | /* Selecting the queue with least back off */ | |
113 | for (; ii < NUM_EDCA_QUEUES; ii++) { | |
114 | if (((common->tx_qinfo[ii].pkt_contended) && | |
115 | (common->tx_qinfo[ii].weight < min)) && q_len) { | |
116 | min = common->tx_qinfo[ii].weight; | |
117 | q_num = ii; | |
118 | } | |
119 | } | |
120 | ||
121 | common->tx_qinfo[q_num].pkt_contended = 0; | |
122 | /* Adjust the back off values for all queues again */ | |
123 | recontend_queue = rsi_recalculate_weights(common); | |
124 | ||
125 | q_len = skb_queue_len(&common->tx_queue[q_num]); | |
126 | if (!q_len) { | |
127 | /* If any queues are freshly contended and the selected queue | |
128 | * doesn't have any packets | |
129 | * then get the queue number again with fresh values | |
130 | */ | |
131 | if (recontend_queue) | |
132 | goto get_queue_num; | |
133 | ||
134 | q_num = INVALID_QUEUE; | |
135 | return q_num; | |
136 | } | |
137 | ||
138 | common->selected_qnum = q_num; | |
139 | q_len = skb_queue_len(&common->tx_queue[q_num]); | |
140 | ||
141 | switch (common->selected_qnum) { | |
142 | case VO_Q: | |
143 | if (q_len > MAX_CONTINUOUS_VO_PKTS) | |
144 | common->pkt_cnt = (MAX_CONTINUOUS_VO_PKTS - 1); | |
145 | else | |
146 | common->pkt_cnt = --q_len; | |
147 | break; | |
148 | ||
149 | case VI_Q: | |
150 | if (q_len > MAX_CONTINUOUS_VI_PKTS) | |
151 | common->pkt_cnt = (MAX_CONTINUOUS_VI_PKTS - 1); | |
152 | else | |
153 | common->pkt_cnt = --q_len; | |
154 | ||
155 | break; | |
156 | ||
157 | default: | |
158 | common->pkt_cnt = 0; | |
159 | break; | |
160 | } | |
161 | ||
162 | return q_num; | |
163 | } | |
164 | ||
165 | /** | |
166 | * rsi_core_queue_pkt() - This functions enqueues the packet to the queue | |
167 | * specified by the queue number. | |
168 | * @common: Pointer to the driver private structure. | |
169 | * @skb: Pointer to the socket buffer structure. | |
170 | * | |
171 | * Return: None. | |
172 | */ | |
173 | static void rsi_core_queue_pkt(struct rsi_common *common, | |
174 | struct sk_buff *skb) | |
175 | { | |
176 | u8 q_num = skb->priority; | |
177 | if (q_num >= NUM_SOFT_QUEUES) { | |
178 | rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", | |
179 | __func__, q_num); | |
180 | dev_kfree_skb(skb); | |
181 | return; | |
182 | } | |
183 | ||
184 | skb_queue_tail(&common->tx_queue[q_num], skb); | |
185 | } | |
186 | ||
187 | /** | |
188 | * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue | |
189 | * specified by the queue number. | |
190 | * @common: Pointer to the driver private structure. | |
191 | * @q_num: Queue number. | |
192 | * | |
193 | * Return: Pointer to sk_buff structure. | |
194 | */ | |
195 | static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common, | |
196 | u8 q_num) | |
197 | { | |
198 | if (q_num >= NUM_SOFT_QUEUES) { | |
199 | rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", | |
200 | __func__, q_num); | |
201 | return NULL; | |
202 | } | |
203 | ||
204 | return skb_dequeue(&common->tx_queue[q_num]); | |
205 | } | |
206 | ||
207 | /** | |
208 | * rsi_core_qos_processor() - This function is used to determine the wmm queue | |
209 | * based on the backoff procedure. Data packets are | |
210 | * dequeued from the selected hal queue and sent to | |
211 | * the below layers. | |
212 | * @common: Pointer to the driver private structure. | |
213 | * | |
214 | * Return: None. | |
215 | */ | |
216 | void rsi_core_qos_processor(struct rsi_common *common) | |
217 | { | |
218 | struct rsi_hw *adapter = common->priv; | |
219 | struct sk_buff *skb; | |
220 | unsigned long tstamp_1, tstamp_2; | |
221 | u8 q_num; | |
222 | int status; | |
223 | ||
224 | tstamp_1 = jiffies; | |
225 | while (1) { | |
226 | q_num = rsi_core_determine_hal_queue(common); | |
227 | rsi_dbg(DATA_TX_ZONE, | |
228 | "%s: Queue number = %d\n", __func__, q_num); | |
229 | ||
230 | if (q_num == INVALID_QUEUE) { | |
231 | rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__); | |
232 | break; | |
233 | } | |
234 | ||
235 | mutex_lock(&common->tx_rxlock); | |
236 | ||
237 | status = adapter->check_hw_queue_status(adapter, q_num); | |
238 | if ((status <= 0)) { | |
239 | mutex_unlock(&common->tx_rxlock); | |
240 | break; | |
241 | } | |
242 | ||
243 | if ((q_num < MGMT_SOFT_Q) && | |
244 | ((skb_queue_len(&common->tx_queue[q_num])) <= | |
245 | MIN_DATA_QUEUE_WATER_MARK)) { | |
246 | if (ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) | |
247 | ieee80211_wake_queue(adapter->hw, | |
248 | WME_AC(q_num)); | |
249 | } | |
250 | ||
251 | skb = rsi_core_dequeue_pkt(common, q_num); | |
252 | if (skb == NULL) { | |
253 | mutex_unlock(&common->tx_rxlock); | |
254 | break; | |
255 | } | |
256 | ||
257 | if (q_num == MGMT_SOFT_Q) | |
258 | status = rsi_send_mgmt_pkt(common, skb); | |
259 | else | |
260 | status = rsi_send_data_pkt(common, skb); | |
261 | ||
262 | if (status) { | |
263 | mutex_unlock(&common->tx_rxlock); | |
264 | break; | |
265 | } | |
266 | ||
267 | common->tx_stats.total_tx_pkt_send[q_num]++; | |
268 | ||
269 | tstamp_2 = jiffies; | |
270 | mutex_unlock(&common->tx_rxlock); | |
271 | ||
272 | if (tstamp_2 > tstamp_1 + (300 * HZ / 1000)) | |
273 | schedule(); | |
274 | } | |
275 | } | |
276 | ||
277 | /** | |
278 | * rsi_core_xmit() - This function transmits the packets received from mac80211 | |
279 | * @common: Pointer to the driver private structure. | |
280 | * @skb: Pointer to the socket buffer structure. | |
281 | * | |
282 | * Return: None. | |
283 | */ | |
284 | void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) | |
285 | { | |
286 | struct rsi_hw *adapter = common->priv; | |
287 | struct ieee80211_tx_info *info; | |
288 | struct skb_info *tx_params; | |
289 | struct ieee80211_hdr *tmp_hdr = NULL; | |
290 | u8 q_num, tid = 0; | |
291 | ||
292 | if ((!skb) || (!skb->len)) { | |
293 | rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", | |
294 | __func__); | |
295 | goto xmit_fail; | |
296 | } | |
297 | info = IEEE80211_SKB_CB(skb); | |
298 | tx_params = (struct skb_info *)info->driver_data; | |
299 | tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; | |
300 | ||
301 | if (common->fsm_state != FSM_MAC_INIT_DONE) { | |
302 | rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); | |
303 | goto xmit_fail; | |
304 | } | |
305 | ||
306 | if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) || | |
307 | (ieee80211_is_ctl(tmp_hdr->frame_control))) { | |
308 | q_num = MGMT_SOFT_Q; | |
309 | skb->priority = q_num; | |
310 | } else { | |
311 | if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { | |
312 | tid = (skb->data[24] & IEEE80211_QOS_TID); | |
313 | skb->priority = TID_TO_WME_AC(tid); | |
314 | } else { | |
315 | tid = IEEE80211_NONQOS_TID; | |
316 | skb->priority = BE_Q; | |
317 | } | |
318 | q_num = skb->priority; | |
319 | tx_params->tid = tid; | |
320 | tx_params->sta_id = 0; | |
321 | } | |
322 | ||
323 | if ((q_num != MGMT_SOFT_Q) && | |
324 | ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= | |
325 | DATA_QUEUE_WATER_MARK)) { | |
326 | if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) | |
327 | ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); | |
328 | rsi_set_event(&common->tx_thread.event); | |
329 | goto xmit_fail; | |
330 | } | |
331 | ||
332 | rsi_core_queue_pkt(common, skb); | |
333 | rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__); | |
334 | rsi_set_event(&common->tx_thread.event); | |
335 | ||
336 | return; | |
337 | ||
338 | xmit_fail: | |
339 | rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); | |
340 | /* Dropping pkt here */ | |
341 | ieee80211_free_txskb(common->priv->hw, skb); | |
342 | } |