Skip to content

Commit dad0d04

Browse files
fariyaflinvjw
authored andcommitted
rsi: Add RS9113 wireless driver
This patch adds the Redpine Signals' 91x wireless driver. Signed-off-by: Fariya Fatima <[email protected]> Signed-off-by: John W. Linville <[email protected]>
1 parent 097638a commit dad0d04

21 files changed

+6644
-0
lines changed

drivers/net/wireless/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,5 +281,6 @@ source "drivers/net/wireless/ti/Kconfig"
281281
source "drivers/net/wireless/zd1211rw/Kconfig"
282282
source "drivers/net/wireless/mwifiex/Kconfig"
283283
source "drivers/net/wireless/cw1200/Kconfig"
284+
source "drivers/net/wireless/rsi/Kconfig"
284285

285286
endif # WLAN

drivers/net/wireless/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@ obj-$(CONFIG_BRCMFMAC) += brcm80211/
5959
obj-$(CONFIG_BRCMSMAC) += brcm80211/
6060

6161
obj-$(CONFIG_CW1200) += cw1200/
62+
obj-$(CONFIG_RSI_91X) += rsi/

drivers/net/wireless/rsi/Kconfig

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
config RSI_91X
2+
tristate "Redpine Signals Inc 91x WLAN driver support"
3+
depends on MAC80211
4+
---help---
5+
This option enabes support for RSI 1x1 devices.
6+
Select M (recommended), if you have a RSI 1x1 wireless module.
7+
8+
config RSI_DEBUGFS
9+
bool "Redpine Signals Inc debug support"
10+
depends on RSI_91X
11+
default y
12+
---help---
13+
Say Y, if you would like to enable debug support. This option
14+
creates debugfs entries
15+
16+
config RSI_SDIO
17+
tristate "Redpine Signals SDIO bus support"
18+
depends on MMC && RSI_91X
19+
default m
20+
---help---
21+
This option enables the SDIO bus support in rsi drivers.
22+
Select M (recommended), if you have a RSI 1x1 wireless module.
23+
24+
config RSI_USB
25+
tristate "Redpine Signals USB bus support"
26+
depends on USB && RSI_91X
27+
default m
28+
---help---
29+
This option enables the USB bus support in rsi drivers.
30+
Select M (recommended), if you have a RSI 1x1 wireless module.

drivers/net/wireless/rsi/Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
rsi_91x-y += rsi_91x_main.o
2+
rsi_91x-y += rsi_91x_core.o
3+
rsi_91x-y += rsi_91x_mac80211.o
4+
rsi_91x-y += rsi_91x_mgmt.o
5+
rsi_91x-y += rsi_91x_pkt.o
6+
rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o
7+
8+
rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
9+
rsi_sdio-y += rsi_91x_sdio.o rsi_91x_sdio_ops.o
10+
obj-$(CONFIG_RSI_91X) += rsi_91x.o
11+
obj-$(CONFIG_RSI_SDIO) += rsi_sdio.o
12+
obj-$(CONFIG_RSI_USB) += rsi_usb.o
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
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+
}

0 commit comments

Comments
 (0)