nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (c) 2013 Broadcom Corporation |
||
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 ANY |
||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
15 | */ |
||
16 | #include <linux/slab.h> |
||
17 | #include <linux/netdevice.h> |
||
18 | #include <net/cfg80211.h> |
||
19 | |||
20 | #include <brcmu_wifi.h> |
||
21 | #include <brcmu_utils.h> |
||
22 | #include <defs.h> |
||
23 | #include "core.h" |
||
24 | #include "debug.h" |
||
25 | #include "fwil.h" |
||
26 | #include "fwil_types.h" |
||
27 | #include "btcoex.h" |
||
28 | #include "p2p.h" |
||
29 | #include "cfg80211.h" |
||
30 | |||
31 | /* T1 start SCO/eSCO priority suppression */ |
||
32 | #define BRCMF_BTCOEX_OPPR_WIN_TIME msecs_to_jiffies(2000) |
||
33 | |||
34 | /* BT registers values during DHCP */ |
||
35 | #define BRCMF_BT_DHCP_REG50 0x8022 |
||
36 | #define BRCMF_BT_DHCP_REG51 0 |
||
37 | #define BRCMF_BT_DHCP_REG64 0 |
||
38 | #define BRCMF_BT_DHCP_REG65 0 |
||
39 | #define BRCMF_BT_DHCP_REG71 0 |
||
40 | #define BRCMF_BT_DHCP_REG66 0x2710 |
||
41 | #define BRCMF_BT_DHCP_REG41 0x33 |
||
42 | #define BRCMF_BT_DHCP_REG68 0x190 |
||
43 | |||
44 | /* number of samples for SCO detection */ |
||
45 | #define BRCMF_BT_SCO_SAMPLES 12 |
||
46 | |||
47 | /** |
||
48 | * enum brcmf_btcoex_state - BT coex DHCP state machine states |
||
49 | * @BRCMF_BT_DHCP_IDLE: DCHP is idle |
||
50 | * @BRCMF_BT_DHCP_START: DHCP started, wait before |
||
51 | * boosting wifi priority |
||
52 | * @BRCMF_BT_DHCP_OPPR_WIN: graceful DHCP opportunity ended, |
||
53 | * boost wifi priority |
||
54 | * @BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT: wifi priority boost end, |
||
55 | * restore defaults |
||
56 | */ |
||
57 | enum brcmf_btcoex_state { |
||
58 | BRCMF_BT_DHCP_IDLE, |
||
59 | BRCMF_BT_DHCP_START, |
||
60 | BRCMF_BT_DHCP_OPPR_WIN, |
||
61 | BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT |
||
62 | }; |
||
63 | |||
64 | /** |
||
65 | * struct brcmf_btcoex_info - BT coex related information |
||
66 | * @vif: interface for which request was done. |
||
67 | * @timer: timer for DHCP state machine |
||
68 | * @timeout: configured timeout. |
||
69 | * @timer_on: DHCP timer active |
||
70 | * @dhcp_done: DHCP finished before T1/T2 timer expiration |
||
71 | * @bt_state: DHCP state machine state |
||
72 | * @work: DHCP state machine work |
||
73 | * @cfg: driver private data for cfg80211 interface |
||
74 | * @reg66: saved value of btc_params 66 |
||
75 | * @reg41: saved value of btc_params 41 |
||
76 | * @reg68: saved value of btc_params 68 |
||
77 | * @saved_regs_part1: flag indicating regs 66,41,68 |
||
78 | * have been saved |
||
79 | * @reg51: saved value of btc_params 51 |
||
80 | * @reg64: saved value of btc_params 64 |
||
81 | * @reg65: saved value of btc_params 65 |
||
82 | * @reg71: saved value of btc_params 71 |
||
83 | * @saved_regs_part1: flag indicating regs 50,51,64,65,71 |
||
84 | * have been saved |
||
85 | */ |
||
86 | struct brcmf_btcoex_info { |
||
87 | struct brcmf_cfg80211_vif *vif; |
||
88 | struct timer_list timer; |
||
89 | u16 timeout; |
||
90 | bool timer_on; |
||
91 | bool dhcp_done; |
||
92 | enum brcmf_btcoex_state bt_state; |
||
93 | struct work_struct work; |
||
94 | struct brcmf_cfg80211_info *cfg; |
||
95 | u32 reg66; |
||
96 | u32 reg41; |
||
97 | u32 reg68; |
||
98 | bool saved_regs_part1; |
||
99 | u32 reg50; |
||
100 | u32 reg51; |
||
101 | u32 reg64; |
||
102 | u32 reg65; |
||
103 | u32 reg71; |
||
104 | bool saved_regs_part2; |
||
105 | }; |
||
106 | |||
107 | /** |
||
108 | * brcmf_btcoex_params_write() - write btc_params firmware variable |
||
109 | * @ifp: interface |
||
110 | * @addr: btc_params register number |
||
111 | * @data: data to write |
||
112 | */ |
||
113 | static s32 brcmf_btcoex_params_write(struct brcmf_if *ifp, u32 addr, u32 data) |
||
114 | { |
||
115 | struct { |
||
116 | __le32 addr; |
||
117 | __le32 data; |
||
118 | } reg_write; |
||
119 | |||
120 | reg_write.addr = cpu_to_le32(addr); |
||
121 | reg_write.data = cpu_to_le32(data); |
||
122 | return brcmf_fil_iovar_data_set(ifp, "btc_params", |
||
123 | ®_write, sizeof(reg_write)); |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * brcmf_btcoex_params_read() - read btc_params firmware variable |
||
128 | * @ifp: interface |
||
129 | * @addr: btc_params register number |
||
130 | * @data: read data |
||
131 | */ |
||
132 | static s32 brcmf_btcoex_params_read(struct brcmf_if *ifp, u32 addr, u32 *data) |
||
133 | { |
||
134 | *data = addr; |
||
135 | |||
136 | return brcmf_fil_iovar_int_get(ifp, "btc_params", data); |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * brcmf_btcoex_boost_wifi() - control BT SCO/eSCO parameters |
||
141 | * @btci: BT coex info |
||
142 | * @trump_sco: |
||
143 | * true - set SCO/eSCO parameters for compatibility |
||
144 | * during DHCP window |
||
145 | * false - restore saved parameter values |
||
146 | * |
||
147 | * Enhanced BT COEX settings for eSCO compatibility during DHCP window |
||
148 | */ |
||
149 | static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci, |
||
150 | bool trump_sco) |
||
151 | { |
||
152 | struct brcmf_if *ifp = brcmf_get_ifp(btci->cfg->pub, 0); |
||
153 | |||
154 | if (trump_sco && !btci->saved_regs_part2) { |
||
155 | /* this should reduce eSCO agressive |
||
156 | * retransmit w/o breaking it |
||
157 | */ |
||
158 | |||
159 | /* save current */ |
||
160 | brcmf_dbg(INFO, "new SCO/eSCO coex algo {save & override}\n"); |
||
161 | brcmf_btcoex_params_read(ifp, 50, &btci->reg50); |
||
162 | brcmf_btcoex_params_read(ifp, 51, &btci->reg51); |
||
163 | brcmf_btcoex_params_read(ifp, 64, &btci->reg64); |
||
164 | brcmf_btcoex_params_read(ifp, 65, &btci->reg65); |
||
165 | brcmf_btcoex_params_read(ifp, 71, &btci->reg71); |
||
166 | |||
167 | btci->saved_regs_part2 = true; |
||
168 | brcmf_dbg(INFO, |
||
169 | "saved bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
||
170 | btci->reg50, btci->reg51, btci->reg64, |
||
171 | btci->reg65, btci->reg71); |
||
172 | |||
173 | /* pacify the eSco */ |
||
174 | brcmf_btcoex_params_write(ifp, 50, BRCMF_BT_DHCP_REG50); |
||
175 | brcmf_btcoex_params_write(ifp, 51, BRCMF_BT_DHCP_REG51); |
||
176 | brcmf_btcoex_params_write(ifp, 64, BRCMF_BT_DHCP_REG64); |
||
177 | brcmf_btcoex_params_write(ifp, 65, BRCMF_BT_DHCP_REG65); |
||
178 | brcmf_btcoex_params_write(ifp, 71, BRCMF_BT_DHCP_REG71); |
||
179 | |||
180 | } else if (btci->saved_regs_part2) { |
||
181 | /* restore previously saved bt params */ |
||
182 | brcmf_dbg(INFO, "Do new SCO/eSCO coex algo {restore}\n"); |
||
183 | brcmf_btcoex_params_write(ifp, 50, btci->reg50); |
||
184 | brcmf_btcoex_params_write(ifp, 51, btci->reg51); |
||
185 | brcmf_btcoex_params_write(ifp, 64, btci->reg64); |
||
186 | brcmf_btcoex_params_write(ifp, 65, btci->reg65); |
||
187 | brcmf_btcoex_params_write(ifp, 71, btci->reg71); |
||
188 | |||
189 | brcmf_dbg(INFO, |
||
190 | "restored bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
||
191 | btci->reg50, btci->reg51, btci->reg64, |
||
192 | btci->reg65, btci->reg71); |
||
193 | |||
194 | btci->saved_regs_part2 = false; |
||
195 | } else { |
||
196 | brcmf_dbg(INFO, "attempted to restore not saved BTCOEX params\n"); |
||
197 | } |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * brcmf_btcoex_is_sco_active() - check if SCO/eSCO is active |
||
202 | * @ifp: interface |
||
203 | * |
||
204 | * return: true if SCO/eSCO session is active |
||
205 | */ |
||
206 | static bool brcmf_btcoex_is_sco_active(struct brcmf_if *ifp) |
||
207 | { |
||
208 | int ioc_res = 0; |
||
209 | bool res = false; |
||
210 | int sco_id_cnt = 0; |
||
211 | u32 param27; |
||
212 | int i; |
||
213 | |||
214 | for (i = 0; i < BRCMF_BT_SCO_SAMPLES; i++) { |
||
215 | ioc_res = brcmf_btcoex_params_read(ifp, 27, ¶m27); |
||
216 | |||
217 | if (ioc_res < 0) { |
||
218 | brcmf_err("ioc read btc params error\n"); |
||
219 | break; |
||
220 | } |
||
221 | |||
222 | brcmf_dbg(INFO, "sample[%d], btc_params 27:%x\n", i, param27); |
||
223 | |||
224 | if ((param27 & 0x6) == 2) { /* count both sco & esco */ |
||
225 | sco_id_cnt++; |
||
226 | } |
||
227 | |||
228 | if (sco_id_cnt > 2) { |
||
229 | brcmf_dbg(INFO, |
||
230 | "sco/esco detected, pkt id_cnt:%d samples:%d\n", |
||
231 | sco_id_cnt, i); |
||
232 | res = true; |
||
233 | break; |
||
234 | } |
||
235 | } |
||
236 | brcmf_dbg(TRACE, "exit: result=%d\n", res); |
||
237 | return res; |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * btcmf_btcoex_save_part1() - save first step parameters. |
||
242 | */ |
||
243 | static void btcmf_btcoex_save_part1(struct brcmf_btcoex_info *btci) |
||
244 | { |
||
245 | struct brcmf_if *ifp = btci->vif->ifp; |
||
246 | |||
247 | if (!btci->saved_regs_part1) { |
||
248 | /* Retrieve and save original reg value */ |
||
249 | brcmf_btcoex_params_read(ifp, 66, &btci->reg66); |
||
250 | brcmf_btcoex_params_read(ifp, 41, &btci->reg41); |
||
251 | brcmf_btcoex_params_read(ifp, 68, &btci->reg68); |
||
252 | btci->saved_regs_part1 = true; |
||
253 | brcmf_dbg(INFO, |
||
254 | "saved btc_params regs (66,41,68) 0x%x 0x%x 0x%x\n", |
||
255 | btci->reg66, btci->reg41, |
||
256 | btci->reg68); |
||
257 | } |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * brcmf_btcoex_restore_part1() - restore first step parameters. |
||
262 | */ |
||
263 | static void brcmf_btcoex_restore_part1(struct brcmf_btcoex_info *btci) |
||
264 | { |
||
265 | struct brcmf_if *ifp; |
||
266 | |||
267 | if (btci->saved_regs_part1) { |
||
268 | btci->saved_regs_part1 = false; |
||
269 | ifp = btci->vif->ifp; |
||
270 | brcmf_btcoex_params_write(ifp, 66, btci->reg66); |
||
271 | brcmf_btcoex_params_write(ifp, 41, btci->reg41); |
||
272 | brcmf_btcoex_params_write(ifp, 68, btci->reg68); |
||
273 | brcmf_dbg(INFO, |
||
274 | "restored btc_params regs {66,41,68} 0x%x 0x%x 0x%x\n", |
||
275 | btci->reg66, btci->reg41, |
||
276 | btci->reg68); |
||
277 | } |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * brcmf_btcoex_timerfunc() - BT coex timer callback |
||
282 | */ |
||
283 | static void brcmf_btcoex_timerfunc(ulong data) |
||
284 | { |
||
285 | struct brcmf_btcoex_info *bt_local = (struct brcmf_btcoex_info *)data; |
||
286 | brcmf_dbg(TRACE, "enter\n"); |
||
287 | |||
288 | bt_local->timer_on = false; |
||
289 | schedule_work(&bt_local->work); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * brcmf_btcoex_handler() - BT coex state machine work handler |
||
294 | * @work: work |
||
295 | */ |
||
296 | static void brcmf_btcoex_handler(struct work_struct *work) |
||
297 | { |
||
298 | struct brcmf_btcoex_info *btci; |
||
299 | btci = container_of(work, struct brcmf_btcoex_info, work); |
||
300 | if (btci->timer_on) { |
||
301 | btci->timer_on = false; |
||
302 | del_timer_sync(&btci->timer); |
||
303 | } |
||
304 | |||
305 | switch (btci->bt_state) { |
||
306 | case BRCMF_BT_DHCP_START: |
||
307 | /* DHCP started provide OPPORTUNITY window |
||
308 | to get DHCP address |
||
309 | */ |
||
310 | brcmf_dbg(INFO, "DHCP started\n"); |
||
311 | btci->bt_state = BRCMF_BT_DHCP_OPPR_WIN; |
||
312 | if (btci->timeout < BRCMF_BTCOEX_OPPR_WIN_TIME) { |
||
313 | mod_timer(&btci->timer, btci->timer.expires); |
||
314 | } else { |
||
315 | btci->timeout -= BRCMF_BTCOEX_OPPR_WIN_TIME; |
||
316 | mod_timer(&btci->timer, |
||
317 | jiffies + BRCMF_BTCOEX_OPPR_WIN_TIME); |
||
318 | } |
||
319 | btci->timer_on = true; |
||
320 | break; |
||
321 | |||
322 | case BRCMF_BT_DHCP_OPPR_WIN: |
||
323 | if (btci->dhcp_done) { |
||
324 | brcmf_dbg(INFO, "DHCP done before T1 expiration\n"); |
||
325 | goto idle; |
||
326 | } |
||
327 | |||
328 | /* DHCP is not over yet, start lowering BT priority */ |
||
329 | brcmf_dbg(INFO, "DHCP T1:%d expired\n", |
||
330 | jiffies_to_msecs(BRCMF_BTCOEX_OPPR_WIN_TIME)); |
||
331 | brcmf_btcoex_boost_wifi(btci, true); |
||
332 | |||
333 | btci->bt_state = BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT; |
||
334 | mod_timer(&btci->timer, jiffies + btci->timeout); |
||
335 | btci->timer_on = true; |
||
336 | break; |
||
337 | |||
338 | case BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT: |
||
339 | if (btci->dhcp_done) |
||
340 | brcmf_dbg(INFO, "DHCP done before T2 expiration\n"); |
||
341 | else |
||
342 | brcmf_dbg(INFO, "DHCP T2:%d expired\n", |
||
343 | BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT); |
||
344 | |||
345 | goto idle; |
||
346 | |||
347 | default: |
||
348 | brcmf_err("invalid state=%d !!!\n", btci->bt_state); |
||
349 | goto idle; |
||
350 | } |
||
351 | |||
352 | return; |
||
353 | |||
354 | idle: |
||
355 | btci->bt_state = BRCMF_BT_DHCP_IDLE; |
||
356 | btci->timer_on = false; |
||
357 | brcmf_btcoex_boost_wifi(btci, false); |
||
358 | cfg80211_crit_proto_stopped(&btci->vif->wdev, GFP_KERNEL); |
||
359 | brcmf_btcoex_restore_part1(btci); |
||
360 | btci->vif = NULL; |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * brcmf_btcoex_attach() - initialize BT coex data |
||
365 | * @cfg: driver private cfg80211 data |
||
366 | * |
||
367 | * return: 0 on success |
||
368 | */ |
||
369 | int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg) |
||
370 | { |
||
371 | struct brcmf_btcoex_info *btci = NULL; |
||
372 | brcmf_dbg(TRACE, "enter\n"); |
||
373 | |||
374 | btci = kmalloc(sizeof(struct brcmf_btcoex_info), GFP_KERNEL); |
||
375 | if (!btci) |
||
376 | return -ENOMEM; |
||
377 | |||
378 | btci->bt_state = BRCMF_BT_DHCP_IDLE; |
||
379 | |||
380 | /* Set up timer for BT */ |
||
381 | btci->timer_on = false; |
||
382 | btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME; |
||
383 | setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci); |
||
384 | btci->cfg = cfg; |
||
385 | btci->saved_regs_part1 = false; |
||
386 | btci->saved_regs_part2 = false; |
||
387 | |||
388 | INIT_WORK(&btci->work, brcmf_btcoex_handler); |
||
389 | |||
390 | cfg->btcoex = btci; |
||
391 | return 0; |
||
392 | } |
||
393 | |||
394 | /** |
||
395 | * brcmf_btcoex_detach - clean BT coex data |
||
396 | * @cfg: driver private cfg80211 data |
||
397 | */ |
||
398 | void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg) |
||
399 | { |
||
400 | brcmf_dbg(TRACE, "enter\n"); |
||
401 | |||
402 | if (!cfg->btcoex) |
||
403 | return; |
||
404 | |||
405 | if (cfg->btcoex->timer_on) { |
||
406 | cfg->btcoex->timer_on = false; |
||
407 | del_timer_sync(&cfg->btcoex->timer); |
||
408 | } |
||
409 | |||
410 | cancel_work_sync(&cfg->btcoex->work); |
||
411 | |||
412 | brcmf_btcoex_boost_wifi(cfg->btcoex, false); |
||
413 | brcmf_btcoex_restore_part1(cfg->btcoex); |
||
414 | |||
415 | kfree(cfg->btcoex); |
||
416 | cfg->btcoex = NULL; |
||
417 | } |
||
418 | |||
419 | static void brcmf_btcoex_dhcp_start(struct brcmf_btcoex_info *btci) |
||
420 | { |
||
421 | struct brcmf_if *ifp = btci->vif->ifp; |
||
422 | |||
423 | btcmf_btcoex_save_part1(btci); |
||
424 | /* set new regs values */ |
||
425 | brcmf_btcoex_params_write(ifp, 66, BRCMF_BT_DHCP_REG66); |
||
426 | brcmf_btcoex_params_write(ifp, 41, BRCMF_BT_DHCP_REG41); |
||
427 | brcmf_btcoex_params_write(ifp, 68, BRCMF_BT_DHCP_REG68); |
||
428 | btci->dhcp_done = false; |
||
429 | btci->bt_state = BRCMF_BT_DHCP_START; |
||
430 | schedule_work(&btci->work); |
||
431 | brcmf_dbg(TRACE, "enable BT DHCP Timer\n"); |
||
432 | } |
||
433 | |||
434 | static void brcmf_btcoex_dhcp_end(struct brcmf_btcoex_info *btci) |
||
435 | { |
||
436 | /* Stop any bt timer because DHCP session is done */ |
||
437 | btci->dhcp_done = true; |
||
438 | if (btci->timer_on) { |
||
439 | brcmf_dbg(INFO, "disable BT DHCP Timer\n"); |
||
440 | btci->timer_on = false; |
||
441 | del_timer_sync(&btci->timer); |
||
442 | |||
443 | /* schedule worker if transition to IDLE is needed */ |
||
444 | if (btci->bt_state != BRCMF_BT_DHCP_IDLE) { |
||
445 | brcmf_dbg(INFO, "bt_state:%d\n", |
||
446 | btci->bt_state); |
||
447 | schedule_work(&btci->work); |
||
448 | } |
||
449 | } else { |
||
450 | /* Restore original values */ |
||
451 | brcmf_btcoex_restore_part1(btci); |
||
452 | } |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * brcmf_btcoex_set_mode - set BT coex mode |
||
457 | * @cfg: driver private cfg80211 data |
||
458 | * @mode: Wifi-Bluetooth coexistence mode |
||
459 | * |
||
460 | * return: 0 on success |
||
461 | */ |
||
462 | int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif, |
||
463 | enum brcmf_btcoex_mode mode, u16 duration) |
||
464 | { |
||
465 | struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy); |
||
466 | struct brcmf_btcoex_info *btci = cfg->btcoex; |
||
467 | struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); |
||
468 | |||
469 | switch (mode) { |
||
470 | case BRCMF_BTCOEX_DISABLED: |
||
471 | brcmf_dbg(INFO, "DHCP session starts\n"); |
||
472 | if (btci->bt_state != BRCMF_BT_DHCP_IDLE) |
||
473 | return -EBUSY; |
||
474 | /* Start BT timer only for SCO connection */ |
||
475 | if (brcmf_btcoex_is_sco_active(ifp)) { |
||
476 | btci->timeout = msecs_to_jiffies(duration); |
||
477 | btci->vif = vif; |
||
478 | brcmf_btcoex_dhcp_start(btci); |
||
479 | } |
||
480 | break; |
||
481 | |||
482 | case BRCMF_BTCOEX_ENABLED: |
||
483 | brcmf_dbg(INFO, "DHCP session ends\n"); |
||
484 | if (btci->bt_state != BRCMF_BT_DHCP_IDLE && |
||
485 | vif == btci->vif) { |
||
486 | brcmf_btcoex_dhcp_end(btci); |
||
487 | } |
||
488 | break; |
||
489 | default: |
||
490 | brcmf_dbg(INFO, "Unknown mode, ignored\n"); |
||
491 | } |
||
492 | return 0; |
||
493 | } |