1 /*
2 * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3 * Copyright (c) 2015 iComm Corporation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <ssv6200.h>
18 #include <linux/nl80211.h>
19 #include <linux/etherdevice.h>
20 #include <linux/delay.h>
21 #include <linux/version.h>
22 #include <linux/time.h>
23 #include <linux/sched.h>
24 #include <net/mac80211.h>
25 #include <ssv6200.h>
26 #include "lib.h"
27 #include "dev.h"
28 #include "ap.h"
29 #include "ssv_rc_common.h"
30 #include "ssv_rc.h"
31 int ssv6200_bcast_queue_len(struct ssv6xxx_bcast_txq *bcast_txq);
32 #define IS_EQUAL(a,b) ( (a) == (b) )
33 #define SET_BIT(v,b) ( (v) |= (0x01<<b) )
34 #define CLEAR_BIT(v,b) ( (v) &= ~(0x01<<b) )
35 #define IS_BIT_SET(v,b) ( (v) & (0x01<<(b) ) )
36 #define PBUF_BASE_ADDR 0x80000000
37 #define PBUF_ADDR_SHIFT 16
38 #define PBUF_MapPkttoID(_PKT) (((u32)_PKT&0x0FFF0000)>>PBUF_ADDR_SHIFT)
39 #define PBUF_MapIDtoPkt(_ID) (PBUF_BASE_ADDR|((_ID)<<PBUF_ADDR_SHIFT))
40 #define SSV6xxx_BEACON_MAX_ALLOCATE_CNT 10
41 #define MTX_BCN_PKTID_CH_LOCK_SHIFT MTX_BCN_PKTID_CH_LOCK_SFT
42 #define MTX_BCN_CFG_VLD_SHIFT MTX_BCN_CFG_VLD_SFT
43 #define MTX_BCN_CFG_VLD_MASK MTX_BCN_CFG_VLD_MSK
44 #define AUTO_BCN_ONGOING_MASK MTX_AUTO_BCN_ONGOING_MSK
45 #define AUTO_BCN_ONGOING_SHIFT MTX_AUTO_BCN_ONGOING_SFT
46 #define MTX_BCN_TIMER_EN_SHIFT MTX_BCN_TIMER_EN_SFT
47 #define MTX_TSF_TIMER_EN_SHIFT MTX_TSF_TIMER_EN_SFT
48 #define MTX_HALT_MNG_UNTIL_DTIM_SHIFT MTX_HALT_MNG_UNTIL_DTIM_SFT
49 #define MTX_BCN_ENABLE_MASK (MTX_BCN_TIMER_EN_I_MSK)
50 #define MTX_BCN_PERIOD_SHIFT MTX_BCN_PERIOD_SFT
51 #define MTX_DTIM_NUM_SHIFT MTX_DTIM_NUM_SFT
52 #define MTX_DTIM_OFST0 MTX_DTIM_OFST0_SFT
53 enum ssv6xxx_beacon_type{
54 SSV6xxx_BEACON_0,
55 SSV6xxx_BEACON_1,
56 };
57 static const u32 ssv6xxx_beacon_adr[] =
58 {
59 ADR_MTX_BCN_CFG0,
60 ADR_MTX_BCN_CFG1,
61 };
ssv6xxx_beacon_reg_lock(struct ssv_softc * sc,bool block)62 void ssv6xxx_beacon_reg_lock(struct ssv_softc *sc, bool block)
63 {
64 u32 val;
65 val = block<<MTX_BCN_PKTID_CH_LOCK_SHIFT;
66 #ifdef BEACON_DEBUG
67 printk("ssv6xxx_beacon_reg_lock val[0x:%08x]\n ", val);
68 #endif
69 SMAC_REG_WRITE(sc->sh, ADR_MTX_BCN_MISC, val);
70 }
ssv6xxx_beacon_set_info(struct ssv_softc * sc,u8 beacon_interval,u8 dtim_cnt)71 void ssv6xxx_beacon_set_info(struct ssv_softc *sc, u8 beacon_interval, u8 dtim_cnt)
72 {
73 u32 val;
74 if(beacon_interval==0)
75 beacon_interval = 100;
76 #ifdef BEACON_DEBUG
77 printk("[A] BSS_CHANGED_BEACON_INT beacon_int[%d] dtim_cnt[%d]\n",beacon_interval, (dtim_cnt));
78 #endif
79 val = (beacon_interval<<MTX_BCN_PERIOD_SHIFT)| (dtim_cnt<<MTX_DTIM_NUM_SHIFT);
80 SMAC_REG_WRITE(sc->sh, ADR_MTX_BCN_PRD, val);
81 }
ssv6xxx_beacon_enable(struct ssv_softc * sc,bool bEnable)82 bool ssv6xxx_beacon_enable(struct ssv_softc *sc, bool bEnable)
83 {
84 u32 regval=0;
85 int ret = 0;
86 if(bEnable && !sc->beacon_usage)
87 {
88 printk("[A] Reject to set beacon!!!. ssv6xxx_beacon_enable bEnable[%d] sc->beacon_usage[%d]\n",bEnable ,sc->beacon_usage);
89 sc->enable_beacon = BEACON_WAITING_ENABLED;
90 return 0;
91 }
92 if((bEnable && (BEACON_ENABLED & sc->enable_beacon))||
93 (!bEnable && !sc->enable_beacon))
94 {
95 printk("[A] ssv6xxx_beacon_enable bEnable[%d] and sc->enable_beacon[%d] are the same. no need to execute.\n",bEnable ,sc->enable_beacon);
96 if(bEnable){
97 printk(" Ignore enable beacon cmd!!!!\n");
98 return 0;
99 }
100 }
101 SMAC_REG_READ(sc->sh, ADR_MTX_BCN_EN_MISC, ®val);
102 #ifdef BEACON_DEBUG
103 printk("[A] ssv6xxx_beacon_enable read misc reg val [%08x]\n", regval);
104 #endif
105 regval &= MTX_BCN_ENABLE_MASK;
106 #ifdef BEACON_DEBUG
107 printk("[A] ssv6xxx_beacon_enable read misc reg val [%08x]\n", regval);
108 #endif
109 regval |= (bEnable<<MTX_BCN_TIMER_EN_SHIFT);
110 ret = SMAC_REG_WRITE(sc->sh, ADR_MTX_BCN_EN_MISC, regval);
111 #ifdef BEACON_DEBUG
112 printk("[A] ssv6xxx_beacon_enable read misc reg val [%08x]\n", regval);
113 #endif
114 sc->enable_beacon = (bEnable==true)?BEACON_ENABLED:0;
115 return ret;
116 }
ssv6xxx_beacon_fill_content(struct ssv_softc * sc,u32 regaddr,u8 * beacon,int size)117 int ssv6xxx_beacon_fill_content(struct ssv_softc *sc, u32 regaddr, u8 *beacon, int size)
118 {
119 u32 i, val;
120 u32 *ptr = (u32*)beacon;
121 size = size/4;
122 for(i=0; i<size; i++)
123 {
124 val = (u32)(*(ptr+i));
125 #ifdef BEACON_DEBUG
126 printk("[%08x] ", val );
127 #endif
128 SMAC_REG_WRITE(sc->sh, regaddr+i*4, val);
129 }
130 #ifdef BEACON_DEBUG
131 printk("\n");
132 #endif
133 return 0;
134 }
ssv6xxx_beacon_fill_tx_desc(struct ssv_softc * sc,struct sk_buff * beacon_skb)135 void ssv6xxx_beacon_fill_tx_desc(struct ssv_softc *sc, struct sk_buff* beacon_skb)
136 {
137 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(beacon_skb);
138 struct ssv6200_tx_desc *tx_desc;
139 u16 pb_offset = TXPB_OFFSET;
140 struct ssv_rate_info ssv_rate;
141 skb_push(beacon_skb, pb_offset);
142 tx_desc = (struct ssv6200_tx_desc *)beacon_skb->data;
143 memset(tx_desc,0, pb_offset);
144 ssv6xxx_rc_hw_rate_idx(sc, tx_info, &ssv_rate);
145 tx_desc->len = beacon_skb->len-pb_offset;
146 tx_desc->c_type = M2_TXREQ;
147 tx_desc->f80211 = 1;
148 tx_desc->ack_policy = 1;
149 tx_desc->hdr_offset = pb_offset;
150 tx_desc->hdr_len = 24;
151 tx_desc->payload_offset = tx_desc->hdr_offset + tx_desc->hdr_len;
152 tx_desc->crate_idx = ssv_rate.crate_hw_idx;
153 tx_desc->drate_idx = ssv_rate.drate_hw_idx;
154 skb_put(beacon_skb, 4);
155 }
ssv6xxx_beacon_get_valid_reg(struct ssv_softc * sc)156 inline enum ssv6xxx_beacon_type ssv6xxx_beacon_get_valid_reg(struct ssv_softc *sc)
157 {
158 u32 regval =0;
159 SMAC_REG_READ(sc->sh, ADR_MTX_BCN_MISC, ®val);
160 regval &= MTX_BCN_CFG_VLD_MASK;
161 regval = regval >>MTX_BCN_CFG_VLD_SHIFT;
162 if(regval==0x2 || regval == 0x0)
163 return SSV6xxx_BEACON_0;
164 else if(regval==0x1)
165 return SSV6xxx_BEACON_1;
166 else
167 printk("=============>ERROR!!drv_bcn_reg_available\n");
168 return SSV6xxx_BEACON_0;
169 }
ssv6xxx_beacon_set(struct ssv_softc * sc,struct sk_buff * beacon_skb,int dtim_offset)170 bool ssv6xxx_beacon_set(struct ssv_softc *sc, struct sk_buff *beacon_skb, int dtim_offset)
171 {
172 u32 reg_tx_beacon_adr = ADR_MTX_BCN_CFG0;
173 enum ssv6xxx_beacon_type avl_bcn_type = SSV6xxx_BEACON_0;
174 bool ret = true;
175 int val;
176 ssv6xxx_beacon_reg_lock(sc, 1);
177 avl_bcn_type = ssv6xxx_beacon_get_valid_reg(sc);
178 if(avl_bcn_type == SSV6xxx_BEACON_1)
179 reg_tx_beacon_adr = ADR_MTX_BCN_CFG1;
180 #ifdef BEACON_DEBUG
181 printk("[A] ssv6xxx_beacon_set avl_bcn_type[%d]\n", avl_bcn_type);
182 #endif
183 do{
184 if(IS_BIT_SET(sc->beacon_usage, avl_bcn_type))
185 {
186 #ifdef BEACON_DEBUG
187 printk("[A] beacon has already been set old len[%d] new len[%d]\n", sc->beacon_info[avl_bcn_type].len, beacon_skb->len);
188 #endif
189 if (sc->beacon_info[avl_bcn_type].len >= beacon_skb->len)
190 {
191 break;
192 }
193 else
194 {
195 if(false == ssv6xxx_pbuf_free(sc, sc->beacon_info[avl_bcn_type].pubf_addr))
196 {
197 #ifdef BEACON_DEBUG
198 printk("=============>ERROR!!Intend to allcoate beacon from ASIC fail.\n");
199 #endif
200 ret = false;
201 goto out;
202 }
203 CLEAR_BIT(sc->beacon_usage, avl_bcn_type);
204 }
205 }
206 sc->beacon_info[avl_bcn_type].pubf_addr = ssv6xxx_pbuf_alloc(sc, beacon_skb->len, TX_BUF);
207 sc->beacon_info[avl_bcn_type].len = beacon_skb->len;
208 if(sc->beacon_info[avl_bcn_type].pubf_addr == 0)
209 {
210 ret = false;
211 goto out;
212 }
213 SET_BIT(sc->beacon_usage, avl_bcn_type);
214 #ifdef BEACON_DEBUG
215 printk("[A] beacon type[%d] usage[%d] allocate new beacon addr[%08x] \n", avl_bcn_type, sc->beacon_usage, sc->beacon_info[avl_bcn_type].pubf_addr);
216 #endif
217 }while(0);
218 ssv6xxx_beacon_fill_content(sc, sc->beacon_info[avl_bcn_type].pubf_addr, beacon_skb->data, beacon_skb->len);
219 val = (PBUF_MapPkttoID(sc->beacon_info[avl_bcn_type].pubf_addr))|(dtim_offset<<MTX_DTIM_OFST0);
220 SMAC_REG_WRITE(sc->sh, reg_tx_beacon_adr, val);
221 #ifdef BEACON_DEBUG
222 printk("[A] update to register reg_tx_beacon_adr[%08x] val[%08x]\n", reg_tx_beacon_adr, val);
223 #endif
224 out:
225 ssv6xxx_beacon_reg_lock(sc, 0);
226 if(sc->beacon_usage && (sc->enable_beacon&BEACON_WAITING_ENABLED)){
227 printk("[A] enable beacon for BEACON_WAITING_ENABLED flags\n");
228 ssv6xxx_beacon_enable(sc, true);
229 }
230 return ret;
231 }
ssv6xxx_auto_bcn_ongoing(struct ssv_softc * sc)232 inline bool ssv6xxx_auto_bcn_ongoing(struct ssv_softc *sc)
233 {
234 u32 regval;
235 SMAC_REG_READ(sc->sh, ADR_MTX_BCN_MISC, ®val);
236 return ((AUTO_BCN_ONGOING_MASK®val)>>AUTO_BCN_ONGOING_SHIFT);
237 }
ssv6xxx_beacon_release(struct ssv_softc * sc)238 void ssv6xxx_beacon_release(struct ssv_softc *sc)
239 {
240 int cnt=10;
241 printk("[A] ssv6xxx_beacon_release Enter\n");
242 cancel_work_sync(&sc->set_tim_work);
243 do {
244 if(ssv6xxx_auto_bcn_ongoing(sc))
245 ssv6xxx_beacon_enable(sc, false);
246 else
247 break;
248 cnt--;
249 if(cnt<=0)
250 break;
251 } while(1);
252 if(IS_BIT_SET(sc->beacon_usage, SSV6xxx_BEACON_0))
253 {
254 ssv6xxx_pbuf_free(sc, sc->beacon_info[SSV6xxx_BEACON_0].pubf_addr);
255 CLEAR_BIT(sc->beacon_usage, SSV6xxx_BEACON_0);
256 }
257 if(IS_BIT_SET(sc->beacon_usage, SSV6xxx_BEACON_1))
258 {
259 ssv6xxx_pbuf_free(sc, sc->beacon_info[SSV6xxx_BEACON_1].pubf_addr);
260 CLEAR_BIT(sc->beacon_usage, SSV6xxx_BEACON_1);
261 }
262 sc->enable_beacon = 0;
263 if(sc->beacon_buf){
264 dev_kfree_skb_any(sc->beacon_buf);
265 sc->beacon_buf = NULL;
266 }
267 #ifdef BEACON_DEBUG
268 printk("[A] ssv6xxx_beacon_release leave\n");
269 #endif
270 }
ssv6xxx_beacon_change(struct ssv_softc * sc,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool aid0_bit_set)271 void ssv6xxx_beacon_change(struct ssv_softc *sc, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool aid0_bit_set)
272 {
273 struct sk_buff *skb;
274 struct sk_buff *old_skb = NULL;
275 u16 tim_offset, tim_length;
276 if(sc == NULL || hw == NULL || vif == NULL ){
277 printk("[Error]........ssv6xxx_beacon_change input error\n");
278 return;
279 }
280 do{
281 skb = ieee80211_beacon_get_tim(hw, vif,
282 &tim_offset, &tim_length);
283 if(skb == NULL){
284 printk("[Error]........skb is NULL\n");
285 break;
286 }
287 if (tim_offset && tim_length >= 6) {
288 skb->data[tim_offset + 2] = 0;
289 if (aid0_bit_set)
290 skb->data[tim_offset + 4] |= 1;
291 else
292 skb->data[tim_offset + 4] &= ~1;
293 }
294 #ifdef BEACON_DEBUG
295 printk("[A] beacon len [%d] tim_offset[%d]\n", skb->len, tim_offset);
296 #endif
297 ssv6xxx_beacon_fill_tx_desc(sc, skb);
298 #ifdef BEACON_DEBUG
299 printk("[A] beacon len [%d] tim_offset[%d]\n", skb->len, tim_offset);
300 #endif
301 if(sc->beacon_buf)
302 {
303 if(memcmp(sc->beacon_buf->data, skb->data, (skb->len-FCS_LEN)) == 0){
304 old_skb = skb;
305 break;
306 }
307 else{
308 old_skb = sc->beacon_buf;
309 sc->beacon_buf = skb;
310 }
311 }
312 else{
313 sc->beacon_buf = skb;
314 }
315 tim_offset+=2;
316 if(ssv6xxx_beacon_set(sc, skb, tim_offset))
317 {
318 u8 dtim_cnt = vif->bss_conf.dtim_period-1;
319 if(sc->beacon_dtim_cnt != dtim_cnt)
320 {
321 sc->beacon_dtim_cnt = dtim_cnt;
322 #ifdef BEACON_DEBUG
323 printk("[A] beacon_dtim_cnt [%d]\n", sc->beacon_dtim_cnt);
324 #endif
325 ssv6xxx_beacon_set_info(sc, sc->beacon_interval,
326 sc->beacon_dtim_cnt);
327 }
328 }
329 }while(0);
330 if(old_skb)
331 dev_kfree_skb_any(old_skb);
332 }
ssv6200_set_tim_work(struct work_struct * work)333 void ssv6200_set_tim_work(struct work_struct *work)
334 {
335 struct ssv_softc *sc =
336 container_of(work, struct ssv_softc, set_tim_work);
337 #ifdef BROADCAST_DEBUG
338 printk("%s() enter\n", __FUNCTION__);
339 #endif
340 ssv6xxx_beacon_change(sc, sc->hw, sc->ap_vif, sc->aid0_bit_set);
341 #ifdef BROADCAST_DEBUG
342 printk("%s() leave\n", __FUNCTION__);
343 #endif
344 }
ssv6200_bcast_queue_len(struct ssv6xxx_bcast_txq * bcast_txq)345 int ssv6200_bcast_queue_len(struct ssv6xxx_bcast_txq *bcast_txq)
346 {
347 u32 len;
348 unsigned long flags;
349 spin_lock_irqsave(&bcast_txq->txq_lock, flags);
350 len = bcast_txq->cur_qsize;
351 spin_unlock_irqrestore(&bcast_txq->txq_lock, flags);
352 return len;
353 }
ssv6200_bcast_dequeue(struct ssv6xxx_bcast_txq * bcast_txq,u8 * remain_len)354 struct sk_buff* ssv6200_bcast_dequeue(struct ssv6xxx_bcast_txq *bcast_txq, u8 *remain_len)
355 {
356 struct sk_buff *skb = NULL;
357 unsigned long flags;
358 spin_lock_irqsave(&bcast_txq->txq_lock, flags);
359 if(bcast_txq->cur_qsize){
360 bcast_txq->cur_qsize --;
361 if(remain_len)
362 *remain_len = bcast_txq->cur_qsize;
363 skb = __skb_dequeue(&bcast_txq->qhead);
364 }
365 spin_unlock_irqrestore(&bcast_txq->txq_lock, flags);
366 return skb;
367 }
ssv6200_bcast_enqueue(struct ssv_softc * sc,struct ssv6xxx_bcast_txq * bcast_txq,struct sk_buff * skb)368 int ssv6200_bcast_enqueue(struct ssv_softc *sc, struct ssv6xxx_bcast_txq *bcast_txq,
369 struct sk_buff *skb)
370 {
371 unsigned long flags;
372 spin_lock_irqsave(&bcast_txq->txq_lock, flags);
373 if (bcast_txq->cur_qsize >=
374 SSV6200_MAX_BCAST_QUEUE_LEN){
375 struct sk_buff *old_skb;
376 old_skb = __skb_dequeue(&bcast_txq->qhead);
377 bcast_txq->cur_qsize --;
378 ssv6xxx_txbuf_free_skb(old_skb, (void*)sc);
379 printk("[B] ssv6200_bcast_enqueue - remove oldest queue\n");
380 }
381 __skb_queue_tail(&bcast_txq->qhead, skb);
382 bcast_txq->cur_qsize ++;
383 spin_unlock_irqrestore(&bcast_txq->txq_lock, flags);
384 return bcast_txq->cur_qsize;
385 }
ssv6200_bcast_flush(struct ssv_softc * sc,struct ssv6xxx_bcast_txq * bcast_txq)386 void ssv6200_bcast_flush(struct ssv_softc *sc, struct ssv6xxx_bcast_txq *bcast_txq)
387 {
388 struct sk_buff *skb;
389 unsigned long flags;
390 #ifdef BCAST_DEBUG
391 printk("ssv6200_bcast_flush\n");
392 #endif
393 spin_lock_irqsave(&bcast_txq->txq_lock, flags);
394 while(bcast_txq->cur_qsize > 0) {
395 skb = __skb_dequeue(&bcast_txq->qhead);
396 bcast_txq->cur_qsize --;
397 ssv6xxx_txbuf_free_skb(skb, (void*)sc);
398 }
399 spin_unlock_irqrestore(&bcast_txq->txq_lock, flags);
400 }
401 static int queue_block_cnt = 0;
ssv6200_bcast_tx_work(struct work_struct * work)402 void ssv6200_bcast_tx_work(struct work_struct *work)
403 {
404 struct ssv_softc *sc =
405 container_of(work, struct ssv_softc, bcast_tx_work.work);
406 #if 1
407 struct sk_buff* skb;
408 int i;
409 u8 remain_size;
410 #endif
411 unsigned long flags;
412 bool needtimer = true;
413 long tmo = sc->bcast_interval;
414 spin_lock_irqsave(&sc->ps_state_lock, flags);
415 do{
416 #ifdef BCAST_DEBUG
417 printk("[B] bcast_timer: hw_mng_used[%d] HCI_TXQ_EMPTY[%d] bcast_queue_len[%d].....................\n",
418 sc->hw_mng_used, HCI_TXQ_EMPTY(sc->sh, 4), ssv6200_bcast_queue_len(&sc->bcast_txq));
419 #endif
420 if(sc->hw_mng_used != 0 ||
421 false == HCI_TXQ_EMPTY(sc->sh, 4)){
422 #ifdef BCAST_DEBUG
423 printk("HW queue still have frames insdide. skip this one hw_mng_used[%d] bEmptyTXQ4[%d]\n",
424 sc->hw_mng_used, HCI_TXQ_EMPTY(sc->sh, 4));
425 #endif
426 queue_block_cnt++;
427 if(queue_block_cnt>5){
428 queue_block_cnt = 0;
429 ssv6200_bcast_flush(sc, &sc->bcast_txq);
430 needtimer = false;
431 }
432 break;
433 }
434 queue_block_cnt = 0;
435 for(i=0;i<SSV6200_ID_MANAGER_QUEUE;i++){
436 skb = ssv6200_bcast_dequeue(&sc->bcast_txq, &remain_size);
437 if(!skb){
438 needtimer = false;
439 break;
440 }
441 if( (0 != remain_size) &&
442 (SSV6200_ID_MANAGER_QUEUE-1) != i ){
443 struct ieee80211_hdr *hdr;
444 struct ssv6200_tx_desc *tx_desc = (struct ssv6200_tx_desc *)skb->data;
445 hdr = (struct ieee80211_hdr *) ((u8*)tx_desc+tx_desc->hdr_offset);
446 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
447 }
448 #ifdef BCAST_DEBUG
449 printk("[B] bcast_timer:tx remain_size[%d] i[%d]\n", remain_size, i);
450 #endif
451 spin_unlock_irqrestore(&sc->ps_state_lock, flags);
452 if(HCI_SEND(sc->sh, skb, 4)<0){
453 printk("bcast_timer send fail!!!!!!! \n");
454 ssv6xxx_txbuf_free_skb(skb, (void*)sc);
455 BUG_ON(1);
456 }
457 spin_lock_irqsave(&sc->ps_state_lock, flags);
458 }
459 }while(0);
460 if(needtimer){
461 #ifdef BCAST_DEBUG
462 printk("[B] bcast_timer:need more timer to tx bcast frame time[%d]\n", sc->bcast_interval);
463 #endif
464 queue_delayed_work(sc->config_wq,
465 &sc->bcast_tx_work,
466 tmo);
467 }
468 else{
469 #ifdef BCAST_DEBUG
470 printk("[B] bcast_timer: ssv6200_bcast_stop\n");
471 #endif
472 ssv6200_bcast_stop(sc);
473 }
474 spin_unlock_irqrestore(&sc->ps_state_lock, flags);
475 #ifdef BCAST_DEBUG
476 printk("[B] bcast_timer: leave.....................\n");
477 #endif
478 }
ssv6200_bcast_start_work(struct work_struct * work)479 void ssv6200_bcast_start_work(struct work_struct *work)
480 {
481 struct ssv_softc *sc =
482 container_of(work, struct ssv_softc, bcast_start_work);
483 #ifdef BCAST_DEBUG
484 printk("[B] ssv6200_bcast_start_work==\n");
485 #endif
486 sc->bcast_interval = (sc->beacon_dtim_cnt+1) *
487 (sc->beacon_interval + 20) * HZ / 1000;
488 if (!sc->aid0_bit_set) {
489 sc->aid0_bit_set = true;
490 ssv6xxx_beacon_change(sc, sc->hw,
491 sc->ap_vif, sc->aid0_bit_set);
492 queue_delayed_work(sc->config_wq,
493 &sc->bcast_tx_work,
494 sc->bcast_interval);
495 #ifdef BCAST_DEBUG
496 printk("[B] bcast_start_work: Modify timer to DTIM[%d]ms==\n",
497 (sc->beacon_dtim_cnt+1)*(sc->beacon_interval + 20));
498 #endif
499 }
500 }
ssv6200_bcast_stop_work(struct work_struct * work)501 void ssv6200_bcast_stop_work(struct work_struct *work)
502 {
503 struct ssv_softc *sc =
504 container_of(work, struct ssv_softc, bcast_stop_work.work);
505 long tmo = HZ / 100;
506 #ifdef BCAST_DEBUG
507 printk("[B] ssv6200_bcast_stop_work\n");
508 #endif
509 if (sc->aid0_bit_set) {
510 if(0== ssv6200_bcast_queue_len(&sc->bcast_txq)){
511 cancel_delayed_work_sync(&sc->bcast_tx_work);
512 sc->aid0_bit_set = false;
513 ssv6xxx_beacon_change(sc, sc->hw,
514 sc->ap_vif, sc->aid0_bit_set);
515 #ifdef BCAST_DEBUG
516 printk("remove group bit in DTIM\n");
517 #endif
518 }
519 else{
520 #ifdef BCAST_DEBUG
521 printk("bcast_stop_work: bcast queue still have data. just modify timer to 10ms\n");
522 #endif
523 queue_delayed_work(sc->config_wq,
524 &sc->bcast_tx_work,
525 tmo);
526 }
527 }
528 }
ssv6200_bcast_stop(struct ssv_softc * sc)529 void ssv6200_bcast_stop(struct ssv_softc *sc)
530 {
531 queue_delayed_work(sc->config_wq,
532 &sc->bcast_stop_work, sc->beacon_interval*HZ/1024);
533 }
ssv6200_bcast_start(struct ssv_softc * sc)534 void ssv6200_bcast_start(struct ssv_softc *sc)
535 {
536 queue_work(sc->config_wq, &sc->bcast_start_work);
537 }
ssv6200_release_bcast_frame_res(struct ssv_softc * sc,struct ieee80211_vif * vif)538 void ssv6200_release_bcast_frame_res(struct ssv_softc *sc, struct ieee80211_vif *vif)
539 {
540 unsigned long flags;
541 struct ssv_vif_priv_data *priv_vif = (struct ssv_vif_priv_data *)vif->drv_priv;
542 spin_lock_irqsave(&sc->ps_state_lock, flags);
543 priv_vif->sta_asleep_mask = 0;
544 spin_unlock_irqrestore(&sc->ps_state_lock, flags);
545 cancel_work_sync(&sc->bcast_start_work);
546 cancel_delayed_work_sync(&sc->bcast_stop_work);
547 ssv6200_bcast_flush(sc, &sc->bcast_txq);
548 cancel_delayed_work_sync(&sc->bcast_tx_work);
549 }
550