]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
brcmfmac: raise SDIO host lock to higher level
[mirror_ubuntu-artful-kernel.git] / drivers / net / wireless / brcm80211 / brcmfmac / bcmsdh.c
CommitLineData
5b435de0
AS
1/*
2 * Copyright (c) 2010 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/* ****************** SDIO CARD Interface Functions **************************/
17
02f77195
JP
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
5b435de0
AS
20#include <linux/types.h>
21#include <linux/netdevice.h>
ee40fa06 22#include <linux/export.h>
5b435de0
AS
23#include <linux/pci.h>
24#include <linux/pci_ids.h>
25#include <linux/sched.h>
26#include <linux/completion.h>
27#include <linux/mmc/sdio.h>
28#include <linux/mmc/sdio_func.h>
29#include <linux/mmc/card.h>
30
31#include <defs.h>
32#include <brcm_hw_ids.h>
33#include <brcmu_utils.h>
34#include <brcmu_wifi.h>
35#include <soc.h>
5b435de0
AS
36#include "dhd_bus.h"
37#include "dhd_dbg.h"
38#include "sdio_host.h"
39
40#define SDIOH_API_ACCESS_RETRY_LIMIT 2
41
ba89bf19
FL
42#ifdef CONFIG_BRCMFMAC_SDIO_OOB
43static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
44{
45 struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id);
46
47 brcmf_dbg(INTR, "oob intr triggered\n");
48
49 /*
50 * out-of-band interrupt is level-triggered which won't
51 * be cleared until dpc
52 */
53 if (sdiodev->irq_en) {
54 disable_irq_nosync(irq);
55 sdiodev->irq_en = false;
56 }
57
58 brcmf_sdbrcm_isr(sdiodev->bus);
59
60 return IRQ_HANDLED;
61}
62
63int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
64{
65 int ret = 0;
66 u8 data;
67 unsigned long flags;
68
69 brcmf_dbg(TRACE, "Entering\n");
70
71 brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq);
72 ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
73 sdiodev->irq_flags, "brcmf_oob_intr",
74 &sdiodev->func[1]->card->dev);
75 if (ret != 0)
76 return ret;
77 spin_lock_init(&sdiodev->irq_en_lock);
78 spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
79 sdiodev->irq_en = true;
80 spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
81
82 ret = enable_irq_wake(sdiodev->irq);
83 if (ret != 0)
84 return ret;
85 sdiodev->irq_wake = true;
86
87 /* must configure SDIO_CCCR_IENx to enable irq */
45db339c 88 data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
ba89bf19 89 data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
3bba829f 90 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
ba89bf19 91
f304a993 92 /* redirect, configure and enable io for interrupt signal */
ba89bf19 93 data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
f304a993 94 if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
ba89bf19 95 data |= SDIO_SEPINT_ACT_HI;
3bba829f 96 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
ba89bf19
FL
97
98 return 0;
99}
100
101int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
102{
103 brcmf_dbg(TRACE, "Entering\n");
104
3bba829f
FL
105 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
106 brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
ba89bf19
FL
107
108 if (sdiodev->irq_wake) {
109 disable_irq_wake(sdiodev->irq);
110 sdiodev->irq_wake = false;
111 }
112 free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev);
113 sdiodev->irq_en = false;
114
115 return 0;
116}
117#else /* CONFIG_BRCMFMAC_SDIO_OOB */
118static void brcmf_sdio_irqhandler(struct sdio_func *func)
5b435de0 119{
d76d1c8c 120 struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
5b435de0 121
ba89bf19 122 brcmf_dbg(INTR, "ib intr triggered\n");
5b435de0 123
5b435de0 124 brcmf_sdbrcm_isr(sdiodev->bus);
5b435de0
AS
125}
126
fbf59108 127/* dummy handler for SDIO function 2 interrupt */
ba89bf19 128static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
fbf59108
FL
129{
130}
131
ba89bf19 132int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
5b435de0
AS
133{
134 brcmf_dbg(TRACE, "Entering\n");
135
136 sdio_claim_host(sdiodev->func[1]);
ba89bf19
FL
137 sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
138 sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
5b435de0
AS
139 sdio_release_host(sdiodev->func[1]);
140
141 return 0;
142}
143
ba89bf19 144int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
5b435de0
AS
145{
146 brcmf_dbg(TRACE, "Entering\n");
147
148 sdio_claim_host(sdiodev->func[1]);
fbf59108 149 sdio_release_irq(sdiodev->func[2]);
5b435de0
AS
150 sdio_release_irq(sdiodev->func[1]);
151 sdio_release_host(sdiodev->func[1]);
152
153 return 0;
154}
ba89bf19 155#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
5b435de0 156
5b435de0
AS
157int
158brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
159{
7d9cfc28
FL
160 int err = 0, i;
161 u8 addr[3];
162 s32 retry;
163
164 addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
165 addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
166 addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
167
168 for (i = 0; i < 3; i++) {
169 retry = 0;
170 do {
171 if (retry)
172 usleep_range(1000, 2000);
173 err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
174 SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
175 &addr[i]);
176 } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
177
178 if (err) {
179 brcmf_dbg(ERROR, "failed at addr:0x%0x\n",
180 SBSDIO_FUNC1_SBADDRLOW + i);
181 break;
182 }
183 }
5b435de0
AS
184
185 return err;
186}
187
e9b8d91d
FL
188static int
189brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
190 void *data, bool write)
191{
192 u8 func_num, reg_size;
193 u32 bar;
194 s32 retry = 0;
195 int ret;
196
197 /*
198 * figure out how to read the register based on address range
d8b3fc59 199 * 0x00 ~ 0x7FF: function 0 CCCR and FBR
e9b8d91d
FL
200 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
201 * The rest: function 1 silicon backplane core registers
202 */
d8b3fc59 203 if ((addr & ~REG_F0_REG_MASK) == 0) {
e9b8d91d
FL
204 func_num = SDIO_FUNC_0;
205 reg_size = 1;
206 } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
207 func_num = SDIO_FUNC_1;
208 reg_size = 1;
209 } else {
210 func_num = SDIO_FUNC_1;
211 reg_size = 4;
212
213 /* Set the window for SB core register */
214 bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
215 if (bar != sdiodev->sbwad) {
216 ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
217 if (ret != 0) {
218 memset(data, 0xFF, reg_size);
219 return ret;
220 }
221 sdiodev->sbwad = bar;
222 }
223 addr &= SBSDIO_SB_OFT_ADDR_MASK;
224 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
225 }
226
227 do {
228 if (!write)
229 memset(data, 0, reg_size);
230 if (retry) /* wait for 1 ms till bus get settled down */
231 usleep_range(1000, 2000);
232 if (reg_size == 1)
233 ret = brcmf_sdioh_request_byte(sdiodev, write,
234 func_num, addr, data);
235 else
236 ret = brcmf_sdioh_request_word(sdiodev, write,
237 func_num, addr, data, 4);
238 } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
239
5c15c23a 240 if (ret != 0)
e9b8d91d
FL
241 brcmf_dbg(ERROR, "failed with %d\n", ret);
242
243 return ret;
244}
245
246u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
247{
248 u8 data;
249 int retval;
250
251 brcmf_dbg(INFO, "addr:0x%08x\n", addr);
7057fd00 252 sdio_claim_host(sdiodev->func[1]);
e9b8d91d 253 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
7057fd00 254 sdio_release_host(sdiodev->func[1]);
e9b8d91d
FL
255 brcmf_dbg(INFO, "data:0x%02x\n", data);
256
257 if (ret)
258 *ret = retval;
259
260 return data;
261}
262
263u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
264{
265 u32 data;
266 int retval;
267
268 brcmf_dbg(INFO, "addr:0x%08x\n", addr);
7057fd00 269 sdio_claim_host(sdiodev->func[1]);
e9b8d91d 270 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
7057fd00 271 sdio_release_host(sdiodev->func[1]);
e9b8d91d
FL
272 brcmf_dbg(INFO, "data:0x%08x\n", data);
273
274 if (ret)
275 *ret = retval;
276
277 return data;
278}
279
280void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
281 u8 data, int *ret)
282{
283 int retval;
284
285 brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
7057fd00 286 sdio_claim_host(sdiodev->func[1]);
e9b8d91d 287 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
7057fd00 288 sdio_release_host(sdiodev->func[1]);
e9b8d91d
FL
289
290 if (ret)
291 *ret = retval;
292}
293
294void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
295 u32 data, int *ret)
296{
297 int retval;
298
299 brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
7057fd00 300 sdio_claim_host(sdiodev->func[1]);
e9b8d91d 301 retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
7057fd00 302 sdio_release_host(sdiodev->func[1]);
e9b8d91d
FL
303
304 if (ret)
305 *ret = retval;
306}
307
5adfeb63
AS
308static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
309 uint flags, uint width, u32 *addr)
5b435de0 310{
5adfeb63 311 uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
5b435de0
AS
312 int err = 0;
313
5b435de0
AS
314 /* Async not implemented yet */
315 if (flags & SDIO_REQ_ASYNC)
316 return -ENOTSUPP;
317
318 if (bar0 != sdiodev->sbwad) {
319 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
320 if (err)
321 return err;
322
323 sdiodev->sbwad = bar0;
324 }
325
5adfeb63
AS
326 *addr &= SBSDIO_SB_OFT_ADDR_MASK;
327
328 if (width == 4)
329 *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
330
331 return 0;
332}
333
334int
335brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
336 uint flags, u8 *buf, uint nbytes)
337{
338 struct sk_buff *mypkt;
339 int err;
340
341 mypkt = brcmu_pkt_buf_get_skb(nbytes);
342 if (!mypkt) {
343 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
344 nbytes);
345 return -EIO;
346 }
347
348 err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
349 if (!err)
350 memcpy(buf, mypkt->data, nbytes);
351
352 brcmu_pkt_buf_free_skb(mypkt);
353 return err;
354}
355
356int
357brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
358 uint flags, struct sk_buff *pkt)
359{
360 uint incr_fix;
361 uint width;
362 int err = 0;
363
364 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
365 fn, addr, pkt->len);
366
7057fd00
FL
367 sdio_claim_host(sdiodev->func[1]);
368
5adfeb63
AS
369 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
370 err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
371 if (err)
7057fd00 372 goto done;
5b435de0
AS
373
374 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
5adfeb63 375 err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
4c6e869d 376 fn, addr, pkt);
5adfeb63 377
7057fd00
FL
378done:
379 sdio_release_host(sdiodev->func[1]);
380
5adfeb63
AS
381 return err;
382}
383
384int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
385 uint flags, struct sk_buff_head *pktq)
386{
387 uint incr_fix;
388 uint width;
389 int err = 0;
390
391 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
392 fn, addr, pktq->qlen);
393
7057fd00
FL
394 sdio_claim_host(sdiodev->func[1]);
395
5b435de0 396 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
5adfeb63
AS
397 err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
398 if (err)
7057fd00 399 goto done;
5b435de0 400
5adfeb63
AS
401 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
402 err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
403 pktq);
5b435de0 404
7057fd00
FL
405done:
406 sdio_release_host(sdiodev->func[1]);
407
5adfeb63 408 return err;
5b435de0
AS
409}
410
411int
412brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
5adfeb63
AS
413 uint flags, u8 *buf, uint nbytes)
414{
415 struct sk_buff *mypkt;
416 int err;
417
418 mypkt = brcmu_pkt_buf_get_skb(nbytes);
419 if (!mypkt) {
420 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
421 nbytes);
422 return -EIO;
423 }
424
425 memcpy(mypkt->data, buf, nbytes);
426 err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
427
428 brcmu_pkt_buf_free_skb(mypkt);
429 return err;
430
431}
432
433int
434brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
435 uint flags, struct sk_buff *pkt)
5b435de0
AS
436{
437 uint incr_fix;
438 uint width;
439 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
440 int err = 0;
441
5adfeb63
AS
442 brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
443 fn, addr, pkt->len);
5b435de0
AS
444
445 /* Async not implemented yet */
446 if (flags & SDIO_REQ_ASYNC)
447 return -ENOTSUPP;
448
7057fd00
FL
449 sdio_claim_host(sdiodev->func[1]);
450
5b435de0
AS
451 if (bar0 != sdiodev->sbwad) {
452 err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
453 if (err)
7057fd00 454 goto done;
5b435de0
AS
455
456 sdiodev->sbwad = bar0;
457 }
458
459 addr &= SBSDIO_SB_OFT_ADDR_MASK;
460
461 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
462 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
463 if (width == 4)
464 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
465
7057fd00
FL
466 err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
467 addr, pkt);
468
469done:
470 sdio_release_host(sdiodev->func[1]);
471
472 return err;
5b435de0
AS
473}
474
475int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
476 u8 *buf, uint nbytes)
477{
4c6e869d
AS
478 struct sk_buff *mypkt;
479 bool write = rw ? SDIOH_WRITE : SDIOH_READ;
480 int err;
481
5b435de0
AS
482 addr &= SBSDIO_SB_OFT_ADDR_MASK;
483 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
484
4c6e869d
AS
485 mypkt = brcmu_pkt_buf_get_skb(nbytes);
486 if (!mypkt) {
487 brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
488 nbytes);
489 return -EIO;
490 }
491
492 /* For a write, copy the buffer data into the packet. */
493 if (write)
494 memcpy(mypkt->data, buf, nbytes);
495
496 err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
497 SDIO_FUNC_1, addr, mypkt);
498
499 /* For a read, copy the packet data back to the buffer. */
500 if (!err && !write)
501 memcpy(buf, mypkt->data, nbytes);
502
503 brcmu_pkt_buf_free_skb(mypkt);
504 return err;
5b435de0
AS
505}
506
507int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
508{
509 char t_func = (char)fn;
510 brcmf_dbg(TRACE, "Enter\n");
511
512 /* issue abort cmd52 command through F0 */
7057fd00 513 sdio_claim_host(sdiodev->func[1]);
5b435de0
AS
514 brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
515 SDIO_CCCR_ABORT, &t_func);
7057fd00 516 sdio_release_host(sdiodev->func[1]);
5b435de0
AS
517
518 brcmf_dbg(TRACE, "Exit\n");
519 return 0;
520}
521
522int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
523{
524 u32 regs = 0;
525 int ret = 0;
526
527 ret = brcmf_sdioh_attach(sdiodev);
528 if (ret)
529 goto out;
530
531 regs = SI_ENUM_BASE;
532
533 /* Report the BAR, to fix if needed */
534 sdiodev->sbwad = SI_ENUM_BASE;
535
536 /* try to attach to the target device */
4175b88b 537 sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
5b435de0
AS
538 if (!sdiodev->bus) {
539 brcmf_dbg(ERROR, "device attach failed\n");
540 ret = -ENODEV;
541 goto out;
542 }
543
544out:
545 if (ret)
546 brcmf_sdio_remove(sdiodev);
547
548 return ret;
549}
550EXPORT_SYMBOL(brcmf_sdio_probe);
551
552int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
553{
554 if (sdiodev->bus) {
555 brcmf_sdbrcm_disconnect(sdiodev->bus);
556 sdiodev->bus = NULL;
557 }
558
559 brcmf_sdioh_detach(sdiodev);
560
561 sdiodev->sbwad = 0;
562
563 return 0;
564}
565EXPORT_SYMBOL(brcmf_sdio_remove);
566
567void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
568{
569 if (enable)
570 brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
571 else
572 brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
573}