diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211')
17 files changed, 2048 insertions, 1801 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 57cddee03252..1d2ceac3a221 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile | |||
@@ -24,6 +24,7 @@ ccflags-y += -D__CHECK_ENDIAN__ | |||
24 | obj-$(CONFIG_BRCMFMAC) += brcmfmac.o | 24 | obj-$(CONFIG_BRCMFMAC) += brcmfmac.o |
25 | brcmfmac-objs += \ | 25 | brcmfmac-objs += \ |
26 | wl_cfg80211.o \ | 26 | wl_cfg80211.o \ |
27 | chip.o \ | ||
27 | fwil.o \ | 28 | fwil.o \ |
28 | fweh.o \ | 29 | fweh.o \ |
29 | fwsignal.o \ | 30 | fwsignal.o \ |
@@ -36,8 +37,7 @@ brcmfmac-objs += \ | |||
36 | btcoex.o | 37 | btcoex.o |
37 | brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ | 38 | brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ |
38 | dhd_sdio.o \ | 39 | dhd_sdio.o \ |
39 | bcmsdh.o \ | 40 | bcmsdh.o |
40 | sdio_chip.o | ||
41 | brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ | 41 | brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ |
42 | usb.o | 42 | usb.o |
43 | brcmfmac-$(CONFIG_BRCMDBG) += \ | 43 | brcmfmac-$(CONFIG_BRCMDBG) += \ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index fa35b23bbaa7..a16e644e7c08 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include "dhd_bus.h" | 43 | #include "dhd_bus.h" |
44 | #include "dhd_dbg.h" | 44 | #include "dhd_dbg.h" |
45 | #include "sdio_host.h" | 45 | #include "sdio_host.h" |
46 | #include "sdio_chip.h" | ||
47 | 46 | ||
48 | #define SDIOH_API_ACCESS_RETRY_LIMIT 2 | 47 | #define SDIOH_API_ACCESS_RETRY_LIMIT 2 |
49 | 48 | ||
@@ -54,6 +53,12 @@ | |||
54 | /* Maximum milliseconds to wait for F2 to come up */ | 53 | /* Maximum milliseconds to wait for F2 to come up */ |
55 | #define SDIO_WAIT_F2RDY 3000 | 54 | #define SDIO_WAIT_F2RDY 3000 |
56 | 55 | ||
56 | #define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */ | ||
57 | #define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */ | ||
58 | |||
59 | static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE; | ||
60 | module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0); | ||
61 | MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]"); | ||
57 | 62 | ||
58 | static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id) | 63 | static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id) |
59 | { | 64 | { |
@@ -264,26 +269,17 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, | |||
264 | break; | 269 | break; |
265 | } | 270 | } |
266 | 271 | ||
267 | if (ret) { | 272 | if (ret) |
268 | /* | 273 | brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n", |
269 | * SleepCSR register access can fail when | 274 | write ? "write" : "read", fn, addr, ret); |
270 | * waking up the device so reduce this noise | 275 | |
271 | * in the logs. | ||
272 | */ | ||
273 | if (addr != SBSDIO_FUNC1_SLEEPCSR) | ||
274 | brcmf_err("failed to %s data F%d@0x%05x, err: %d\n", | ||
275 | write ? "write" : "read", fn, addr, ret); | ||
276 | else | ||
277 | brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n", | ||
278 | write ? "write" : "read", fn, addr, ret); | ||
279 | } | ||
280 | return ret; | 276 | return ret; |
281 | } | 277 | } |
282 | 278 | ||
283 | static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, | 279 | static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, |
284 | u8 regsz, void *data, bool write) | 280 | u8 regsz, void *data, bool write) |
285 | { | 281 | { |
286 | u8 func_num; | 282 | u8 func; |
287 | s32 retry = 0; | 283 | s32 retry = 0; |
288 | int ret; | 284 | int ret; |
289 | 285 | ||
@@ -297,9 +293,9 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, | |||
297 | * The rest: function 1 silicon backplane core registers | 293 | * The rest: function 1 silicon backplane core registers |
298 | */ | 294 | */ |
299 | if ((addr & ~REG_F0_REG_MASK) == 0) | 295 | if ((addr & ~REG_F0_REG_MASK) == 0) |
300 | func_num = SDIO_FUNC_0; | 296 | func = SDIO_FUNC_0; |
301 | else | 297 | else |
302 | func_num = SDIO_FUNC_1; | 298 | func = SDIO_FUNC_1; |
303 | 299 | ||
304 | do { | 300 | do { |
305 | if (!write) | 301 | if (!write) |
@@ -307,16 +303,26 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, | |||
307 | /* for retry wait for 1 ms till bus get settled down */ | 303 | /* for retry wait for 1 ms till bus get settled down */ |
308 | if (retry) | 304 | if (retry) |
309 | usleep_range(1000, 2000); | 305 | usleep_range(1000, 2000); |
310 | ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz, | 306 | ret = brcmf_sdiod_request_data(sdiodev, func, addr, regsz, |
311 | data, write); | 307 | data, write); |
312 | } while (ret != 0 && ret != -ENOMEDIUM && | 308 | } while (ret != 0 && ret != -ENOMEDIUM && |
313 | retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); | 309 | retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); |
314 | 310 | ||
315 | if (ret == -ENOMEDIUM) | 311 | if (ret == -ENOMEDIUM) |
316 | brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); | 312 | brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); |
317 | else if (ret != 0) | 313 | else if (ret != 0) { |
318 | brcmf_err("failed with %d\n", ret); | 314 | /* |
319 | 315 | * SleepCSR register access can fail when | |
316 | * waking up the device so reduce this noise | ||
317 | * in the logs. | ||
318 | */ | ||
319 | if (addr != SBSDIO_FUNC1_SLEEPCSR) | ||
320 | brcmf_err("failed to %s data F%d@0x%05x, err: %d\n", | ||
321 | write ? "write" : "read", func, addr, ret); | ||
322 | else | ||
323 | brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n", | ||
324 | write ? "write" : "read", func, addr, ret); | ||
325 | } | ||
320 | return ret; | 326 | return ret; |
321 | } | 327 | } |
322 | 328 | ||
@@ -488,7 +494,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, | |||
488 | struct mmc_request mmc_req; | 494 | struct mmc_request mmc_req; |
489 | struct mmc_command mmc_cmd; | 495 | struct mmc_command mmc_cmd; |
490 | struct mmc_data mmc_dat; | 496 | struct mmc_data mmc_dat; |
491 | struct sg_table st; | ||
492 | struct scatterlist *sgl; | 497 | struct scatterlist *sgl; |
493 | int ret = 0; | 498 | int ret = 0; |
494 | 499 | ||
@@ -533,16 +538,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, | |||
533 | pkt_offset = 0; | 538 | pkt_offset = 0; |
534 | pkt_next = target_list->next; | 539 | pkt_next = target_list->next; |
535 | 540 | ||
536 | if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) { | ||
537 | ret = -ENOMEM; | ||
538 | goto exit; | ||
539 | } | ||
540 | |||
541 | memset(&mmc_req, 0, sizeof(struct mmc_request)); | 541 | memset(&mmc_req, 0, sizeof(struct mmc_request)); |
542 | memset(&mmc_cmd, 0, sizeof(struct mmc_command)); | 542 | memset(&mmc_cmd, 0, sizeof(struct mmc_command)); |
543 | memset(&mmc_dat, 0, sizeof(struct mmc_data)); | 543 | memset(&mmc_dat, 0, sizeof(struct mmc_data)); |
544 | 544 | ||
545 | mmc_dat.sg = st.sgl; | 545 | mmc_dat.sg = sdiodev->sgtable.sgl; |
546 | mmc_dat.blksz = func_blk_sz; | 546 | mmc_dat.blksz = func_blk_sz; |
547 | mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; | 547 | mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; |
548 | mmc_cmd.opcode = SD_IO_RW_EXTENDED; | 548 | mmc_cmd.opcode = SD_IO_RW_EXTENDED; |
@@ -558,7 +558,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, | |||
558 | while (seg_sz) { | 558 | while (seg_sz) { |
559 | req_sz = 0; | 559 | req_sz = 0; |
560 | sg_cnt = 0; | 560 | sg_cnt = 0; |
561 | sgl = st.sgl; | 561 | sgl = sdiodev->sgtable.sgl; |
562 | /* prep sg table */ | 562 | /* prep sg table */ |
563 | while (pkt_next != (struct sk_buff *)target_list) { | 563 | while (pkt_next != (struct sk_buff *)target_list) { |
564 | pkt_data = pkt_next->data + pkt_offset; | 564 | pkt_data = pkt_next->data + pkt_offset; |
@@ -640,7 +640,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, | |||
640 | } | 640 | } |
641 | 641 | ||
642 | exit: | 642 | exit: |
643 | sg_free_table(&st); | 643 | sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents); |
644 | while ((pkt_next = __skb_dequeue(&local_list)) != NULL) | 644 | while ((pkt_next = __skb_dequeue(&local_list)) != NULL) |
645 | brcmu_pkt_buf_free_skb(pkt_next); | 645 | brcmu_pkt_buf_free_skb(pkt_next); |
646 | 646 | ||
@@ -827,7 +827,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, | |||
827 | } | 827 | } |
828 | if (!write) | 828 | if (!write) |
829 | memcpy(data, pkt->data, dsize); | 829 | memcpy(data, pkt->data, dsize); |
830 | skb_trim(pkt, dsize); | 830 | skb_trim(pkt, 0); |
831 | 831 | ||
832 | /* Adjust for next transfer (if any) */ | 832 | /* Adjust for next transfer (if any) */ |
833 | size -= dsize; | 833 | size -= dsize; |
@@ -864,6 +864,29 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn) | |||
864 | return 0; | 864 | return 0; |
865 | } | 865 | } |
866 | 866 | ||
867 | static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) | ||
868 | { | ||
869 | uint nents; | ||
870 | int err; | ||
871 | |||
872 | if (!sdiodev->sg_support) | ||
873 | return; | ||
874 | |||
875 | nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz); | ||
876 | nents += (nents >> 4) + 1; | ||
877 | |||
878 | WARN_ON(nents > sdiodev->max_segment_count); | ||
879 | |||
880 | brcmf_dbg(TRACE, "nents=%d\n", nents); | ||
881 | err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL); | ||
882 | if (err < 0) { | ||
883 | brcmf_err("allocation failed: disable scatter-gather"); | ||
884 | sdiodev->sg_support = false; | ||
885 | } | ||
886 | |||
887 | sdiodev->txglomsz = brcmf_sdiod_txglomsz; | ||
888 | } | ||
889 | |||
867 | static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) | 890 | static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) |
868 | { | 891 | { |
869 | if (sdiodev->bus) { | 892 | if (sdiodev->bus) { |
@@ -881,6 +904,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) | |||
881 | sdio_disable_func(sdiodev->func[1]); | 904 | sdio_disable_func(sdiodev->func[1]); |
882 | sdio_release_host(sdiodev->func[1]); | 905 | sdio_release_host(sdiodev->func[1]); |
883 | 906 | ||
907 | sg_free_table(&sdiodev->sgtable); | ||
884 | sdiodev->sbwad = 0; | 908 | sdiodev->sbwad = 0; |
885 | 909 | ||
886 | return 0; | 910 | return 0; |
@@ -936,6 +960,11 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) | |||
936 | SG_MAX_SINGLE_ALLOC); | 960 | SG_MAX_SINGLE_ALLOC); |
937 | sdiodev->max_segment_size = host->max_seg_size; | 961 | sdiodev->max_segment_size = host->max_seg_size; |
938 | 962 | ||
963 | /* allocate scatter-gather table. sg support | ||
964 | * will be disabled upon allocation failure. | ||
965 | */ | ||
966 | brcmf_sdiod_sgtable_alloc(sdiodev); | ||
967 | |||
939 | /* try to attach to the target device */ | 968 | /* try to attach to the target device */ |
940 | sdiodev->bus = brcmf_sdio_probe(sdiodev); | 969 | sdiodev->bus = brcmf_sdio_probe(sdiodev); |
941 | if (!sdiodev->bus) { | 970 | if (!sdiodev->bus) { |
@@ -960,6 +989,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { | |||
960 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)}, | 989 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)}, |
961 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, | 990 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, |
962 | SDIO_DEVICE_ID_BROADCOM_4335_4339)}, | 991 | SDIO_DEVICE_ID_BROADCOM_4335_4339)}, |
992 | {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4354)}, | ||
963 | { /* end: all zeroes */ }, | 993 | { /* end: all zeroes */ }, |
964 | }; | 994 | }; |
965 | MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); | 995 | MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); |
@@ -1073,9 +1103,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev) | |||
1073 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | 1103 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
1074 | int ret = 0; | 1104 | int ret = 0; |
1075 | 1105 | ||
1076 | brcmf_dbg(SDIO, "\n"); | 1106 | brcmf_dbg(SDIO, "Enter\n"); |
1077 | |||
1078 | atomic_set(&sdiodev->suspend, true); | ||
1079 | 1107 | ||
1080 | sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); | 1108 | sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); |
1081 | if (!(sdio_flags & MMC_PM_KEEP_POWER)) { | 1109 | if (!(sdio_flags & MMC_PM_KEEP_POWER)) { |
@@ -1083,9 +1111,12 @@ static int brcmf_ops_sdio_suspend(struct device *dev) | |||
1083 | return -EINVAL; | 1111 | return -EINVAL; |
1084 | } | 1112 | } |
1085 | 1113 | ||
1114 | atomic_set(&sdiodev->suspend, true); | ||
1115 | |||
1086 | ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); | 1116 | ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); |
1087 | if (ret) { | 1117 | if (ret) { |
1088 | brcmf_err("Failed to set pm_flags\n"); | 1118 | brcmf_err("Failed to set pm_flags\n"); |
1119 | atomic_set(&sdiodev->suspend, false); | ||
1089 | return ret; | 1120 | return ret; |
1090 | } | 1121 | } |
1091 | 1122 | ||
@@ -1099,6 +1130,7 @@ static int brcmf_ops_sdio_resume(struct device *dev) | |||
1099 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 1130 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
1100 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | 1131 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
1101 | 1132 | ||
1133 | brcmf_dbg(SDIO, "Enter\n"); | ||
1102 | brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); | 1134 | brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); |
1103 | atomic_set(&sdiodev->suspend, false); | 1135 | atomic_set(&sdiodev->suspend, false); |
1104 | return 0; | 1136 | return 0; |
@@ -1115,14 +1147,15 @@ static struct sdio_driver brcmf_sdmmc_driver = { | |||
1115 | .remove = brcmf_ops_sdio_remove, | 1147 | .remove = brcmf_ops_sdio_remove, |
1116 | .name = BRCMFMAC_SDIO_PDATA_NAME, | 1148 | .name = BRCMFMAC_SDIO_PDATA_NAME, |
1117 | .id_table = brcmf_sdmmc_ids, | 1149 | .id_table = brcmf_sdmmc_ids, |
1118 | #ifdef CONFIG_PM_SLEEP | ||
1119 | .drv = { | 1150 | .drv = { |
1151 | .owner = THIS_MODULE, | ||
1152 | #ifdef CONFIG_PM_SLEEP | ||
1120 | .pm = &brcmf_sdio_pm_ops, | 1153 | .pm = &brcmf_sdio_pm_ops, |
1121 | }, | ||
1122 | #endif /* CONFIG_PM_SLEEP */ | 1154 | #endif /* CONFIG_PM_SLEEP */ |
1155 | }, | ||
1123 | }; | 1156 | }; |
1124 | 1157 | ||
1125 | static int brcmf_sdio_pd_probe(struct platform_device *pdev) | 1158 | static int __init brcmf_sdio_pd_probe(struct platform_device *pdev) |
1126 | { | 1159 | { |
1127 | brcmf_dbg(SDIO, "Enter\n"); | 1160 | brcmf_dbg(SDIO, "Enter\n"); |
1128 | 1161 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c new file mode 100644 index 000000000000..df130ef53d1c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c | |||
@@ -0,0 +1,1034 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 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/kernel.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/ssb/ssb_regs.h> | ||
20 | #include <linux/bcma/bcma.h> | ||
21 | #include <linux/bcma/bcma_regs.h> | ||
22 | |||
23 | #include <defs.h> | ||
24 | #include <soc.h> | ||
25 | #include <brcm_hw_ids.h> | ||
26 | #include <brcmu_utils.h> | ||
27 | #include <chipcommon.h> | ||
28 | #include "dhd_dbg.h" | ||
29 | #include "chip.h" | ||
30 | |||
31 | /* SOC Interconnect types (aka chip types) */ | ||
32 | #define SOCI_SB 0 | ||
33 | #define SOCI_AI 1 | ||
34 | |||
35 | /* PL-368 DMP definitions */ | ||
36 | #define DMP_DESC_TYPE_MSK 0x0000000F | ||
37 | #define DMP_DESC_EMPTY 0x00000000 | ||
38 | #define DMP_DESC_VALID 0x00000001 | ||
39 | #define DMP_DESC_COMPONENT 0x00000001 | ||
40 | #define DMP_DESC_MASTER_PORT 0x00000003 | ||
41 | #define DMP_DESC_ADDRESS 0x00000005 | ||
42 | #define DMP_DESC_ADDRSIZE_GT32 0x00000008 | ||
43 | #define DMP_DESC_EOT 0x0000000F | ||
44 | |||
45 | #define DMP_COMP_DESIGNER 0xFFF00000 | ||
46 | #define DMP_COMP_DESIGNER_S 20 | ||
47 | #define DMP_COMP_PARTNUM 0x000FFF00 | ||
48 | #define DMP_COMP_PARTNUM_S 8 | ||
49 | #define DMP_COMP_CLASS 0x000000F0 | ||
50 | #define DMP_COMP_CLASS_S 4 | ||
51 | #define DMP_COMP_REVISION 0xFF000000 | ||
52 | #define DMP_COMP_REVISION_S 24 | ||
53 | #define DMP_COMP_NUM_SWRAP 0x00F80000 | ||
54 | #define DMP_COMP_NUM_SWRAP_S 19 | ||
55 | #define DMP_COMP_NUM_MWRAP 0x0007C000 | ||
56 | #define DMP_COMP_NUM_MWRAP_S 14 | ||
57 | #define DMP_COMP_NUM_SPORT 0x00003E00 | ||
58 | #define DMP_COMP_NUM_SPORT_S 9 | ||
59 | #define DMP_COMP_NUM_MPORT 0x000001F0 | ||
60 | #define DMP_COMP_NUM_MPORT_S 4 | ||
61 | |||
62 | #define DMP_MASTER_PORT_UID 0x0000FF00 | ||
63 | #define DMP_MASTER_PORT_UID_S 8 | ||
64 | #define DMP_MASTER_PORT_NUM 0x000000F0 | ||
65 | #define DMP_MASTER_PORT_NUM_S 4 | ||
66 | |||
67 | #define DMP_SLAVE_ADDR_BASE 0xFFFFF000 | ||
68 | #define DMP_SLAVE_ADDR_BASE_S 12 | ||
69 | #define DMP_SLAVE_PORT_NUM 0x00000F00 | ||
70 | #define DMP_SLAVE_PORT_NUM_S 8 | ||
71 | #define DMP_SLAVE_TYPE 0x000000C0 | ||
72 | #define DMP_SLAVE_TYPE_S 6 | ||
73 | #define DMP_SLAVE_TYPE_SLAVE 0 | ||
74 | #define DMP_SLAVE_TYPE_BRIDGE 1 | ||
75 | #define DMP_SLAVE_TYPE_SWRAP 2 | ||
76 | #define DMP_SLAVE_TYPE_MWRAP 3 | ||
77 | #define DMP_SLAVE_SIZE_TYPE 0x00000030 | ||
78 | #define DMP_SLAVE_SIZE_TYPE_S 4 | ||
79 | #define DMP_SLAVE_SIZE_4K 0 | ||
80 | #define DMP_SLAVE_SIZE_8K 1 | ||
81 | #define DMP_SLAVE_SIZE_16K 2 | ||
82 | #define DMP_SLAVE_SIZE_DESC 3 | ||
83 | |||
84 | /* EROM CompIdentB */ | ||
85 | #define CIB_REV_MASK 0xff000000 | ||
86 | #define CIB_REV_SHIFT 24 | ||
87 | |||
88 | /* ARM CR4 core specific control flag bits */ | ||
89 | #define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020 | ||
90 | |||
91 | /* D11 core specific control flag bits */ | ||
92 | #define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004 | ||
93 | #define D11_BCMA_IOCTL_PHYRESET 0x0008 | ||
94 | |||
95 | /* chip core base & ramsize */ | ||
96 | /* bcm4329 */ | ||
97 | /* SDIO device core, ID 0x829 */ | ||
98 | #define BCM4329_CORE_BUS_BASE 0x18011000 | ||
99 | /* internal memory core, ID 0x80e */ | ||
100 | #define BCM4329_CORE_SOCRAM_BASE 0x18003000 | ||
101 | /* ARM Cortex M3 core, ID 0x82a */ | ||
102 | #define BCM4329_CORE_ARM_BASE 0x18002000 | ||
103 | #define BCM4329_RAMSIZE 0x48000 | ||
104 | |||
105 | /* bcm43143 */ | ||
106 | /* SDIO device core */ | ||
107 | #define BCM43143_CORE_BUS_BASE 0x18002000 | ||
108 | /* internal memory core */ | ||
109 | #define BCM43143_CORE_SOCRAM_BASE 0x18004000 | ||
110 | /* ARM Cortex M3 core, ID 0x82a */ | ||
111 | #define BCM43143_CORE_ARM_BASE 0x18003000 | ||
112 | #define BCM43143_RAMSIZE 0x70000 | ||
113 | |||
114 | #define CORE_SB(base, field) \ | ||
115 | (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) | ||
116 | #define SBCOREREV(sbidh) \ | ||
117 | ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ | ||
118 | ((sbidh) & SSB_IDHIGH_RCLO)) | ||
119 | |||
120 | struct sbconfig { | ||
121 | u32 PAD[2]; | ||
122 | u32 sbipsflag; /* initiator port ocp slave flag */ | ||
123 | u32 PAD[3]; | ||
124 | u32 sbtpsflag; /* target port ocp slave flag */ | ||
125 | u32 PAD[11]; | ||
126 | u32 sbtmerrloga; /* (sonics >= 2.3) */ | ||
127 | u32 PAD; | ||
128 | u32 sbtmerrlog; /* (sonics >= 2.3) */ | ||
129 | u32 PAD[3]; | ||
130 | u32 sbadmatch3; /* address match3 */ | ||
131 | u32 PAD; | ||
132 | u32 sbadmatch2; /* address match2 */ | ||
133 | u32 PAD; | ||
134 | u32 sbadmatch1; /* address match1 */ | ||
135 | u32 PAD[7]; | ||
136 | u32 sbimstate; /* initiator agent state */ | ||
137 | u32 sbintvec; /* interrupt mask */ | ||
138 | u32 sbtmstatelow; /* target state */ | ||
139 | u32 sbtmstatehigh; /* target state */ | ||
140 | u32 sbbwa0; /* bandwidth allocation table0 */ | ||
141 | u32 PAD; | ||
142 | u32 sbimconfiglow; /* initiator configuration */ | ||
143 | u32 sbimconfighigh; /* initiator configuration */ | ||
144 | u32 sbadmatch0; /* address match0 */ | ||
145 | u32 PAD; | ||
146 | u32 sbtmconfiglow; /* target configuration */ | ||
147 | u32 sbtmconfighigh; /* target configuration */ | ||
148 | u32 sbbconfig; /* broadcast configuration */ | ||
149 | u32 PAD; | ||
150 | u32 sbbstate; /* broadcast state */ | ||
151 | u32 PAD[3]; | ||
152 | u32 sbactcnfg; /* activate configuration */ | ||
153 | u32 PAD[3]; | ||
154 | u32 sbflagst; /* current sbflags */ | ||
155 | u32 PAD[3]; | ||
156 | u32 sbidlow; /* identification */ | ||
157 | u32 sbidhigh; /* identification */ | ||
158 | }; | ||
159 | |||
160 | struct brcmf_core_priv { | ||
161 | struct brcmf_core pub; | ||
162 | u32 wrapbase; | ||
163 | struct list_head list; | ||
164 | struct brcmf_chip_priv *chip; | ||
165 | }; | ||
166 | |||
167 | /* ARM CR4 core specific control flag bits */ | ||
168 | #define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020 | ||
169 | |||
170 | /* D11 core specific control flag bits */ | ||
171 | #define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004 | ||
172 | #define D11_BCMA_IOCTL_PHYRESET 0x0008 | ||
173 | |||
174 | struct brcmf_chip_priv { | ||
175 | struct brcmf_chip pub; | ||
176 | const struct brcmf_buscore_ops *ops; | ||
177 | void *ctx; | ||
178 | /* assured first core is chipcommon, second core is buscore */ | ||
179 | struct list_head cores; | ||
180 | u16 num_cores; | ||
181 | |||
182 | bool (*iscoreup)(struct brcmf_core_priv *core); | ||
183 | void (*coredisable)(struct brcmf_core_priv *core, u32 prereset, | ||
184 | u32 reset); | ||
185 | void (*resetcore)(struct brcmf_core_priv *core, u32 prereset, u32 reset, | ||
186 | u32 postreset); | ||
187 | }; | ||
188 | |||
189 | static void brcmf_chip_sb_corerev(struct brcmf_chip_priv *ci, | ||
190 | struct brcmf_core *core) | ||
191 | { | ||
192 | u32 regdata; | ||
193 | |||
194 | regdata = ci->ops->read32(ci->ctx, CORE_SB(core->base, sbidhigh)); | ||
195 | core->rev = SBCOREREV(regdata); | ||
196 | } | ||
197 | |||
198 | static bool brcmf_chip_sb_iscoreup(struct brcmf_core_priv *core) | ||
199 | { | ||
200 | struct brcmf_chip_priv *ci; | ||
201 | u32 regdata; | ||
202 | u32 address; | ||
203 | |||
204 | ci = core->chip; | ||
205 | address = CORE_SB(core->pub.base, sbtmstatelow); | ||
206 | regdata = ci->ops->read32(ci->ctx, address); | ||
207 | regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | | ||
208 | SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); | ||
209 | return SSB_TMSLOW_CLOCK == regdata; | ||
210 | } | ||
211 | |||
212 | static bool brcmf_chip_ai_iscoreup(struct brcmf_core_priv *core) | ||
213 | { | ||
214 | struct brcmf_chip_priv *ci; | ||
215 | u32 regdata; | ||
216 | bool ret; | ||
217 | |||
218 | ci = core->chip; | ||
219 | regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); | ||
220 | ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; | ||
221 | |||
222 | regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL); | ||
223 | ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); | ||
224 | |||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | static void brcmf_chip_sb_coredisable(struct brcmf_core_priv *core, | ||
229 | u32 prereset, u32 reset) | ||
230 | { | ||
231 | struct brcmf_chip_priv *ci; | ||
232 | u32 val, base; | ||
233 | |||
234 | ci = core->chip; | ||
235 | base = core->pub.base; | ||
236 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
237 | if (val & SSB_TMSLOW_RESET) | ||
238 | return; | ||
239 | |||
240 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
241 | if ((val & SSB_TMSLOW_CLOCK) != 0) { | ||
242 | /* | ||
243 | * set target reject and spin until busy is clear | ||
244 | * (preserve core-specific bits) | ||
245 | */ | ||
246 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
247 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), | ||
248 | val | SSB_TMSLOW_REJECT); | ||
249 | |||
250 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
251 | udelay(1); | ||
252 | SPINWAIT((ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)) | ||
253 | & SSB_TMSHIGH_BUSY), 100000); | ||
254 | |||
255 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)); | ||
256 | if (val & SSB_TMSHIGH_BUSY) | ||
257 | brcmf_err("core state still busy\n"); | ||
258 | |||
259 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow)); | ||
260 | if (val & SSB_IDLOW_INITIATOR) { | ||
261 | val = ci->ops->read32(ci->ctx, | ||
262 | CORE_SB(base, sbimstate)); | ||
263 | val |= SSB_IMSTATE_REJECT; | ||
264 | ci->ops->write32(ci->ctx, | ||
265 | CORE_SB(base, sbimstate), val); | ||
266 | val = ci->ops->read32(ci->ctx, | ||
267 | CORE_SB(base, sbimstate)); | ||
268 | udelay(1); | ||
269 | SPINWAIT((ci->ops->read32(ci->ctx, | ||
270 | CORE_SB(base, sbimstate)) & | ||
271 | SSB_IMSTATE_BUSY), 100000); | ||
272 | } | ||
273 | |||
274 | /* set reset and reject while enabling the clocks */ | ||
275 | val = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | | ||
276 | SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; | ||
277 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), val); | ||
278 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
279 | udelay(10); | ||
280 | |||
281 | /* clear the initiator reject bit */ | ||
282 | val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow)); | ||
283 | if (val & SSB_IDLOW_INITIATOR) { | ||
284 | val = ci->ops->read32(ci->ctx, | ||
285 | CORE_SB(base, sbimstate)); | ||
286 | val &= ~SSB_IMSTATE_REJECT; | ||
287 | ci->ops->write32(ci->ctx, | ||
288 | CORE_SB(base, sbimstate), val); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /* leave reset and reject asserted */ | ||
293 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), | ||
294 | (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); | ||
295 | udelay(1); | ||
296 | } | ||
297 | |||
298 | static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core, | ||
299 | u32 prereset, u32 reset) | ||
300 | { | ||
301 | struct brcmf_chip_priv *ci; | ||
302 | u32 regdata; | ||
303 | |||
304 | ci = core->chip; | ||
305 | |||
306 | /* if core is already in reset, just return */ | ||
307 | regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL); | ||
308 | if ((regdata & BCMA_RESET_CTL_RESET) != 0) | ||
309 | return; | ||
310 | |||
311 | /* configure reset */ | ||
312 | ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, | ||
313 | prereset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); | ||
314 | ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); | ||
315 | |||
316 | /* put in reset */ | ||
317 | ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, | ||
318 | BCMA_RESET_CTL_RESET); | ||
319 | usleep_range(10, 20); | ||
320 | |||
321 | /* wait till reset is 1 */ | ||
322 | SPINWAIT(ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) != | ||
323 | BCMA_RESET_CTL_RESET, 300); | ||
324 | |||
325 | /* in-reset configure */ | ||
326 | ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, | ||
327 | reset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); | ||
328 | ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); | ||
329 | } | ||
330 | |||
331 | static void brcmf_chip_sb_resetcore(struct brcmf_core_priv *core, u32 prereset, | ||
332 | u32 reset, u32 postreset) | ||
333 | { | ||
334 | struct brcmf_chip_priv *ci; | ||
335 | u32 regdata; | ||
336 | u32 base; | ||
337 | |||
338 | ci = core->chip; | ||
339 | base = core->pub.base; | ||
340 | /* | ||
341 | * Must do the disable sequence first to work for | ||
342 | * arbitrary current core state. | ||
343 | */ | ||
344 | brcmf_chip_sb_coredisable(core, 0, 0); | ||
345 | |||
346 | /* | ||
347 | * Now do the initialization sequence. | ||
348 | * set reset while enabling the clock and | ||
349 | * forcing them on throughout the core | ||
350 | */ | ||
351 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), | ||
352 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | | ||
353 | SSB_TMSLOW_RESET); | ||
354 | regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
355 | udelay(1); | ||
356 | |||
357 | /* clear any serror */ | ||
358 | regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)); | ||
359 | if (regdata & SSB_TMSHIGH_SERR) | ||
360 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatehigh), 0); | ||
361 | |||
362 | regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbimstate)); | ||
363 | if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { | ||
364 | regdata &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); | ||
365 | ci->ops->write32(ci->ctx, CORE_SB(base, sbimstate), regdata); | ||
366 | } | ||
367 | |||
368 | /* clear reset and allow it to propagate throughout the core */ | ||
369 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), | ||
370 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK); | ||
371 | regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
372 | udelay(1); | ||
373 | |||
374 | /* leave clock enabled */ | ||
375 | ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), | ||
376 | SSB_TMSLOW_CLOCK); | ||
377 | regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); | ||
378 | udelay(1); | ||
379 | } | ||
380 | |||
381 | static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset, | ||
382 | u32 reset, u32 postreset) | ||
383 | { | ||
384 | struct brcmf_chip_priv *ci; | ||
385 | int count; | ||
386 | |||
387 | ci = core->chip; | ||
388 | |||
389 | /* must disable first to work for arbitrary current core state */ | ||
390 | brcmf_chip_ai_coredisable(core, prereset, reset); | ||
391 | |||
392 | count = 0; | ||
393 | while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) & | ||
394 | BCMA_RESET_CTL_RESET) { | ||
395 | ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, 0); | ||
396 | count++; | ||
397 | if (count > 50) | ||
398 | break; | ||
399 | usleep_range(40, 60); | ||
400 | } | ||
401 | |||
402 | ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, | ||
403 | postreset | BCMA_IOCTL_CLK); | ||
404 | ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); | ||
405 | } | ||
406 | |||
407 | static char *brcmf_chip_name(uint chipid, char *buf, uint len) | ||
408 | { | ||
409 | const char *fmt; | ||
410 | |||
411 | fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; | ||
412 | snprintf(buf, len, fmt, chipid); | ||
413 | return buf; | ||
414 | } | ||
415 | |||
416 | static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci, | ||
417 | u16 coreid, u32 base, | ||
418 | u32 wrapbase) | ||
419 | { | ||
420 | struct brcmf_core_priv *core; | ||
421 | |||
422 | core = kzalloc(sizeof(*core), GFP_KERNEL); | ||
423 | if (!core) | ||
424 | return ERR_PTR(-ENOMEM); | ||
425 | |||
426 | core->pub.id = coreid; | ||
427 | core->pub.base = base; | ||
428 | core->chip = ci; | ||
429 | core->wrapbase = wrapbase; | ||
430 | |||
431 | list_add_tail(&core->list, &ci->cores); | ||
432 | return &core->pub; | ||
433 | } | ||
434 | |||
435 | #ifdef DEBUG | ||
436 | /* safety check for chipinfo */ | ||
437 | static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) | ||
438 | { | ||
439 | struct brcmf_core_priv *core; | ||
440 | bool need_socram = false; | ||
441 | bool has_socram = false; | ||
442 | int idx = 1; | ||
443 | |||
444 | list_for_each_entry(core, &ci->cores, list) { | ||
445 | brcmf_dbg(INFO, " [%-2d] core 0x%x:%-2d base 0x%08x wrap 0x%08x\n", | ||
446 | idx++, core->pub.id, core->pub.rev, core->pub.base, | ||
447 | core->wrapbase); | ||
448 | |||
449 | switch (core->pub.id) { | ||
450 | case BCMA_CORE_ARM_CM3: | ||
451 | need_socram = true; | ||
452 | break; | ||
453 | case BCMA_CORE_INTERNAL_MEM: | ||
454 | has_socram = true; | ||
455 | break; | ||
456 | case BCMA_CORE_ARM_CR4: | ||
457 | if (ci->pub.rambase == 0) { | ||
458 | brcmf_err("RAM base not provided with ARM CR4 core\n"); | ||
459 | return -ENOMEM; | ||
460 | } | ||
461 | break; | ||
462 | default: | ||
463 | break; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | /* check RAM core presence for ARM CM3 core */ | ||
468 | if (need_socram && !has_socram) { | ||
469 | brcmf_err("RAM core not provided with ARM CM3 core\n"); | ||
470 | return -ENODEV; | ||
471 | } | ||
472 | return 0; | ||
473 | } | ||
474 | #else /* DEBUG */ | ||
475 | static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) | ||
476 | { | ||
477 | return 0; | ||
478 | } | ||
479 | #endif | ||
480 | |||
481 | static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) | ||
482 | { | ||
483 | switch (ci->pub.chip) { | ||
484 | case BCM4329_CHIP_ID: | ||
485 | ci->pub.ramsize = BCM4329_RAMSIZE; | ||
486 | break; | ||
487 | case BCM43143_CHIP_ID: | ||
488 | ci->pub.ramsize = BCM43143_RAMSIZE; | ||
489 | break; | ||
490 | case BCM43241_CHIP_ID: | ||
491 | ci->pub.ramsize = 0x90000; | ||
492 | break; | ||
493 | case BCM4330_CHIP_ID: | ||
494 | ci->pub.ramsize = 0x48000; | ||
495 | break; | ||
496 | case BCM4334_CHIP_ID: | ||
497 | ci->pub.ramsize = 0x80000; | ||
498 | break; | ||
499 | case BCM4335_CHIP_ID: | ||
500 | ci->pub.ramsize = 0xc0000; | ||
501 | ci->pub.rambase = 0x180000; | ||
502 | break; | ||
503 | case BCM43362_CHIP_ID: | ||
504 | ci->pub.ramsize = 0x3c000; | ||
505 | break; | ||
506 | case BCM4339_CHIP_ID: | ||
507 | case BCM4354_CHIP_ID: | ||
508 | ci->pub.ramsize = 0xc0000; | ||
509 | ci->pub.rambase = 0x180000; | ||
510 | break; | ||
511 | default: | ||
512 | brcmf_err("unknown chip: %s\n", ci->pub.name); | ||
513 | break; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr, | ||
518 | u8 *type) | ||
519 | { | ||
520 | u32 val; | ||
521 | |||
522 | /* read next descriptor */ | ||
523 | val = ci->ops->read32(ci->ctx, *eromaddr); | ||
524 | *eromaddr += 4; | ||
525 | |||
526 | if (!type) | ||
527 | return val; | ||
528 | |||
529 | /* determine descriptor type */ | ||
530 | *type = (val & DMP_DESC_TYPE_MSK); | ||
531 | if ((*type & ~DMP_DESC_ADDRSIZE_GT32) == DMP_DESC_ADDRESS) | ||
532 | *type = DMP_DESC_ADDRESS; | ||
533 | |||
534 | return val; | ||
535 | } | ||
536 | |||
537 | static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, | ||
538 | u32 *regbase, u32 *wrapbase) | ||
539 | { | ||
540 | u8 desc; | ||
541 | u32 val; | ||
542 | u8 mpnum = 0; | ||
543 | u8 stype, sztype, wraptype; | ||
544 | |||
545 | *regbase = 0; | ||
546 | *wrapbase = 0; | ||
547 | |||
548 | val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); | ||
549 | if (desc == DMP_DESC_MASTER_PORT) { | ||
550 | mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S; | ||
551 | wraptype = DMP_SLAVE_TYPE_MWRAP; | ||
552 | } else if (desc == DMP_DESC_ADDRESS) { | ||
553 | /* revert erom address */ | ||
554 | *eromaddr -= 4; | ||
555 | wraptype = DMP_SLAVE_TYPE_SWRAP; | ||
556 | } else { | ||
557 | *eromaddr -= 4; | ||
558 | return -EILSEQ; | ||
559 | } | ||
560 | |||
561 | do { | ||
562 | /* locate address descriptor */ | ||
563 | do { | ||
564 | val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); | ||
565 | /* unexpected table end */ | ||
566 | if (desc == DMP_DESC_EOT) { | ||
567 | *eromaddr -= 4; | ||
568 | return -EFAULT; | ||
569 | } | ||
570 | } while (desc != DMP_DESC_ADDRESS); | ||
571 | |||
572 | /* skip upper 32-bit address descriptor */ | ||
573 | if (val & DMP_DESC_ADDRSIZE_GT32) | ||
574 | brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); | ||
575 | |||
576 | sztype = (val & DMP_SLAVE_SIZE_TYPE) >> DMP_SLAVE_SIZE_TYPE_S; | ||
577 | |||
578 | /* next size descriptor can be skipped */ | ||
579 | if (sztype == DMP_SLAVE_SIZE_DESC) { | ||
580 | val = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); | ||
581 | /* skip upper size descriptor if present */ | ||
582 | if (val & DMP_DESC_ADDRSIZE_GT32) | ||
583 | brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); | ||
584 | } | ||
585 | |||
586 | /* only look for 4K register regions */ | ||
587 | if (sztype != DMP_SLAVE_SIZE_4K) | ||
588 | continue; | ||
589 | |||
590 | stype = (val & DMP_SLAVE_TYPE) >> DMP_SLAVE_TYPE_S; | ||
591 | |||
592 | /* only regular slave and wrapper */ | ||
593 | if (*regbase == 0 && stype == DMP_SLAVE_TYPE_SLAVE) | ||
594 | *regbase = val & DMP_SLAVE_ADDR_BASE; | ||
595 | if (*wrapbase == 0 && stype == wraptype) | ||
596 | *wrapbase = val & DMP_SLAVE_ADDR_BASE; | ||
597 | } while (*regbase == 0 || *wrapbase == 0); | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | static | ||
603 | int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) | ||
604 | { | ||
605 | struct brcmf_core *core; | ||
606 | u32 eromaddr; | ||
607 | u8 desc_type = 0; | ||
608 | u32 val; | ||
609 | u16 id; | ||
610 | u8 nmp, nsp, nmw, nsw, rev; | ||
611 | u32 base, wrap; | ||
612 | int err; | ||
613 | |||
614 | eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr)); | ||
615 | |||
616 | while (desc_type != DMP_DESC_EOT) { | ||
617 | val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); | ||
618 | if (!(val & DMP_DESC_VALID)) | ||
619 | continue; | ||
620 | |||
621 | if (desc_type == DMP_DESC_EMPTY) | ||
622 | continue; | ||
623 | |||
624 | /* need a component descriptor */ | ||
625 | if (desc_type != DMP_DESC_COMPONENT) | ||
626 | continue; | ||
627 | |||
628 | id = (val & DMP_COMP_PARTNUM) >> DMP_COMP_PARTNUM_S; | ||
629 | |||
630 | /* next descriptor must be component as well */ | ||
631 | val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); | ||
632 | if (WARN_ON((val & DMP_DESC_TYPE_MSK) != DMP_DESC_COMPONENT)) | ||
633 | return -EFAULT; | ||
634 | |||
635 | /* only look at cores with master port(s) */ | ||
636 | nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S; | ||
637 | nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S; | ||
638 | nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S; | ||
639 | nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S; | ||
640 | rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; | ||
641 | |||
642 | /* need core with ports */ | ||
643 | if (nmw + nsw == 0) | ||
644 | continue; | ||
645 | |||
646 | /* try to obtain register address info */ | ||
647 | err = brcmf_chip_dmp_get_regaddr(ci, &eromaddr, &base, &wrap); | ||
648 | if (err) | ||
649 | continue; | ||
650 | |||
651 | /* finally a core to be added */ | ||
652 | core = brcmf_chip_add_core(ci, id, base, wrap); | ||
653 | if (IS_ERR(core)) | ||
654 | return PTR_ERR(core); | ||
655 | |||
656 | core->rev = rev; | ||
657 | } | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) | ||
663 | { | ||
664 | struct brcmf_core *core; | ||
665 | u32 regdata; | ||
666 | u32 socitype; | ||
667 | |||
668 | /* Get CC core rev | ||
669 | * Chipid is assume to be at offset 0 from SI_ENUM_BASE | ||
670 | * For different chiptypes or old sdio hosts w/o chipcommon, | ||
671 | * other ways of recognition should be added here. | ||
672 | */ | ||
673 | regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid)); | ||
674 | ci->pub.chip = regdata & CID_ID_MASK; | ||
675 | ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; | ||
676 | socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; | ||
677 | |||
678 | brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name)); | ||
679 | brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n", | ||
680 | socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name, | ||
681 | ci->pub.chiprev); | ||
682 | |||
683 | if (socitype == SOCI_SB) { | ||
684 | if (ci->pub.chip != BCM4329_CHIP_ID) { | ||
685 | brcmf_err("SB chip is not supported\n"); | ||
686 | return -ENODEV; | ||
687 | } | ||
688 | ci->iscoreup = brcmf_chip_sb_iscoreup; | ||
689 | ci->coredisable = brcmf_chip_sb_coredisable; | ||
690 | ci->resetcore = brcmf_chip_sb_resetcore; | ||
691 | |||
692 | core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, | ||
693 | SI_ENUM_BASE, 0); | ||
694 | brcmf_chip_sb_corerev(ci, core); | ||
695 | core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, | ||
696 | BCM4329_CORE_BUS_BASE, 0); | ||
697 | brcmf_chip_sb_corerev(ci, core); | ||
698 | core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, | ||
699 | BCM4329_CORE_SOCRAM_BASE, 0); | ||
700 | brcmf_chip_sb_corerev(ci, core); | ||
701 | core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, | ||
702 | BCM4329_CORE_ARM_BASE, 0); | ||
703 | brcmf_chip_sb_corerev(ci, core); | ||
704 | |||
705 | core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); | ||
706 | brcmf_chip_sb_corerev(ci, core); | ||
707 | } else if (socitype == SOCI_AI) { | ||
708 | ci->iscoreup = brcmf_chip_ai_iscoreup; | ||
709 | ci->coredisable = brcmf_chip_ai_coredisable; | ||
710 | ci->resetcore = brcmf_chip_ai_resetcore; | ||
711 | |||
712 | brcmf_chip_dmp_erom_scan(ci); | ||
713 | } else { | ||
714 | brcmf_err("chip backplane type %u is not supported\n", | ||
715 | socitype); | ||
716 | return -ENODEV; | ||
717 | } | ||
718 | |||
719 | brcmf_chip_get_raminfo(ci); | ||
720 | |||
721 | return brcmf_chip_cores_check(ci); | ||
722 | } | ||
723 | |||
724 | static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id) | ||
725 | { | ||
726 | struct brcmf_core *core; | ||
727 | struct brcmf_core_priv *cr4; | ||
728 | u32 val; | ||
729 | |||
730 | |||
731 | core = brcmf_chip_get_core(&chip->pub, id); | ||
732 | if (!core) | ||
733 | return; | ||
734 | |||
735 | switch (id) { | ||
736 | case BCMA_CORE_ARM_CM3: | ||
737 | brcmf_chip_coredisable(core, 0, 0); | ||
738 | break; | ||
739 | case BCMA_CORE_ARM_CR4: | ||
740 | cr4 = container_of(core, struct brcmf_core_priv, pub); | ||
741 | |||
742 | /* clear all IOCTL bits except HALT bit */ | ||
743 | val = chip->ops->read32(chip->ctx, cr4->wrapbase + BCMA_IOCTL); | ||
744 | val &= ARMCR4_BCMA_IOCTL_CPUHALT; | ||
745 | brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT, | ||
746 | ARMCR4_BCMA_IOCTL_CPUHALT); | ||
747 | break; | ||
748 | default: | ||
749 | brcmf_err("unknown id: %u\n", id); | ||
750 | break; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | static int brcmf_chip_setup(struct brcmf_chip_priv *chip) | ||
755 | { | ||
756 | struct brcmf_chip *pub; | ||
757 | struct brcmf_core_priv *cc; | ||
758 | u32 base; | ||
759 | u32 val; | ||
760 | int ret = 0; | ||
761 | |||
762 | pub = &chip->pub; | ||
763 | cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list); | ||
764 | base = cc->pub.base; | ||
765 | |||
766 | /* get chipcommon capabilites */ | ||
767 | pub->cc_caps = chip->ops->read32(chip->ctx, | ||
768 | CORE_CC_REG(base, capabilities)); | ||
769 | |||
770 | /* get pmu caps & rev */ | ||
771 | if (pub->cc_caps & CC_CAP_PMU) { | ||
772 | val = chip->ops->read32(chip->ctx, | ||
773 | CORE_CC_REG(base, pmucapabilities)); | ||
774 | pub->pmurev = val & PCAP_REV_MASK; | ||
775 | pub->pmucaps = val; | ||
776 | } | ||
777 | |||
778 | brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, pmucaps=0x%x\n", | ||
779 | cc->pub.rev, pub->pmurev, pub->pmucaps); | ||
780 | |||
781 | /* execute bus core specific setup */ | ||
782 | if (chip->ops->setup) | ||
783 | ret = chip->ops->setup(chip->ctx, pub); | ||
784 | |||
785 | /* | ||
786 | * Make sure any on-chip ARM is off (in case strapping is wrong), | ||
787 | * or downloaded code was already running. | ||
788 | */ | ||
789 | brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); | ||
790 | brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); | ||
791 | return ret; | ||
792 | } | ||
793 | |||
794 | struct brcmf_chip *brcmf_chip_attach(void *ctx, | ||
795 | const struct brcmf_buscore_ops *ops) | ||
796 | { | ||
797 | struct brcmf_chip_priv *chip; | ||
798 | int err = 0; | ||
799 | |||
800 | if (WARN_ON(!ops->read32)) | ||
801 | err = -EINVAL; | ||
802 | if (WARN_ON(!ops->write32)) | ||
803 | err = -EINVAL; | ||
804 | if (WARN_ON(!ops->prepare)) | ||
805 | err = -EINVAL; | ||
806 | if (WARN_ON(!ops->exit_dl)) | ||
807 | err = -EINVAL; | ||
808 | if (err < 0) | ||
809 | return ERR_PTR(-EINVAL); | ||
810 | |||
811 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
812 | if (!chip) | ||
813 | return ERR_PTR(-ENOMEM); | ||
814 | |||
815 | INIT_LIST_HEAD(&chip->cores); | ||
816 | chip->num_cores = 0; | ||
817 | chip->ops = ops; | ||
818 | chip->ctx = ctx; | ||
819 | |||
820 | err = ops->prepare(ctx); | ||
821 | if (err < 0) | ||
822 | goto fail; | ||
823 | |||
824 | err = brcmf_chip_recognition(chip); | ||
825 | if (err < 0) | ||
826 | goto fail; | ||
827 | |||
828 | err = brcmf_chip_setup(chip); | ||
829 | if (err < 0) | ||
830 | goto fail; | ||
831 | |||
832 | return &chip->pub; | ||
833 | |||
834 | fail: | ||
835 | brcmf_chip_detach(&chip->pub); | ||
836 | return ERR_PTR(err); | ||
837 | } | ||
838 | |||
839 | void brcmf_chip_detach(struct brcmf_chip *pub) | ||
840 | { | ||
841 | struct brcmf_chip_priv *chip; | ||
842 | struct brcmf_core_priv *core; | ||
843 | struct brcmf_core_priv *tmp; | ||
844 | |||
845 | chip = container_of(pub, struct brcmf_chip_priv, pub); | ||
846 | list_for_each_entry_safe(core, tmp, &chip->cores, list) { | ||
847 | list_del(&core->list); | ||
848 | kfree(core); | ||
849 | } | ||
850 | kfree(chip); | ||
851 | } | ||
852 | |||
853 | struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid) | ||
854 | { | ||
855 | struct brcmf_chip_priv *chip; | ||
856 | struct brcmf_core_priv *core; | ||
857 | |||
858 | chip = container_of(pub, struct brcmf_chip_priv, pub); | ||
859 | list_for_each_entry(core, &chip->cores, list) | ||
860 | if (core->pub.id == coreid) | ||
861 | return &core->pub; | ||
862 | |||
863 | return NULL; | ||
864 | } | ||
865 | |||
866 | struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub) | ||
867 | { | ||
868 | struct brcmf_chip_priv *chip; | ||
869 | struct brcmf_core_priv *cc; | ||
870 | |||
871 | chip = container_of(pub, struct brcmf_chip_priv, pub); | ||
872 | cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list); | ||
873 | if (WARN_ON(!cc || cc->pub.id != BCMA_CORE_CHIPCOMMON)) | ||
874 | return brcmf_chip_get_core(pub, BCMA_CORE_CHIPCOMMON); | ||
875 | return &cc->pub; | ||
876 | } | ||
877 | |||
878 | bool brcmf_chip_iscoreup(struct brcmf_core *pub) | ||
879 | { | ||
880 | struct brcmf_core_priv *core; | ||
881 | |||
882 | core = container_of(pub, struct brcmf_core_priv, pub); | ||
883 | return core->chip->iscoreup(core); | ||
884 | } | ||
885 | |||
886 | void brcmf_chip_coredisable(struct brcmf_core *pub, u32 prereset, u32 reset) | ||
887 | { | ||
888 | struct brcmf_core_priv *core; | ||
889 | |||
890 | core = container_of(pub, struct brcmf_core_priv, pub); | ||
891 | core->chip->coredisable(core, prereset, reset); | ||
892 | } | ||
893 | |||
894 | void brcmf_chip_resetcore(struct brcmf_core *pub, u32 prereset, u32 reset, | ||
895 | u32 postreset) | ||
896 | { | ||
897 | struct brcmf_core_priv *core; | ||
898 | |||
899 | core = container_of(pub, struct brcmf_core_priv, pub); | ||
900 | core->chip->resetcore(core, prereset, reset, postreset); | ||
901 | } | ||
902 | |||
903 | static void | ||
904 | brcmf_chip_cm3_enterdl(struct brcmf_chip_priv *chip) | ||
905 | { | ||
906 | struct brcmf_core *core; | ||
907 | |||
908 | brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); | ||
909 | core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); | ||
910 | brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | | ||
911 | D11_BCMA_IOCTL_PHYCLOCKEN, | ||
912 | D11_BCMA_IOCTL_PHYCLOCKEN, | ||
913 | D11_BCMA_IOCTL_PHYCLOCKEN); | ||
914 | core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); | ||
915 | brcmf_chip_resetcore(core, 0, 0, 0); | ||
916 | } | ||
917 | |||
918 | static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip) | ||
919 | { | ||
920 | struct brcmf_core *core; | ||
921 | |||
922 | core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); | ||
923 | if (!brcmf_chip_iscoreup(core)) { | ||
924 | brcmf_err("SOCRAM core is down after reset?\n"); | ||
925 | return false; | ||
926 | } | ||
927 | |||
928 | chip->ops->exit_dl(chip->ctx, &chip->pub, 0); | ||
929 | |||
930 | core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3); | ||
931 | brcmf_chip_resetcore(core, 0, 0, 0); | ||
932 | |||
933 | return true; | ||
934 | } | ||
935 | |||
936 | static inline void | ||
937 | brcmf_chip_cr4_enterdl(struct brcmf_chip_priv *chip) | ||
938 | { | ||
939 | struct brcmf_core *core; | ||
940 | |||
941 | brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); | ||
942 | |||
943 | core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); | ||
944 | brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | | ||
945 | D11_BCMA_IOCTL_PHYCLOCKEN, | ||
946 | D11_BCMA_IOCTL_PHYCLOCKEN, | ||
947 | D11_BCMA_IOCTL_PHYCLOCKEN); | ||
948 | } | ||
949 | |||
950 | static bool brcmf_chip_cr4_exitdl(struct brcmf_chip_priv *chip, u32 rstvec) | ||
951 | { | ||
952 | struct brcmf_core *core; | ||
953 | |||
954 | chip->ops->exit_dl(chip->ctx, &chip->pub, rstvec); | ||
955 | |||
956 | /* restore ARM */ | ||
957 | core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4); | ||
958 | brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0); | ||
959 | |||
960 | return true; | ||
961 | } | ||
962 | |||
963 | void brcmf_chip_enter_download(struct brcmf_chip *pub) | ||
964 | { | ||
965 | struct brcmf_chip_priv *chip; | ||
966 | struct brcmf_core *arm; | ||
967 | |||
968 | brcmf_dbg(TRACE, "Enter\n"); | ||
969 | |||
970 | chip = container_of(pub, struct brcmf_chip_priv, pub); | ||
971 | arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); | ||
972 | if (arm) { | ||
973 | brcmf_chip_cr4_enterdl(chip); | ||
974 | return; | ||
975 | } | ||
976 | |||
977 | brcmf_chip_cm3_enterdl(chip); | ||
978 | } | ||
979 | |||
980 | bool brcmf_chip_exit_download(struct brcmf_chip *pub, u32 rstvec) | ||
981 | { | ||
982 | struct brcmf_chip_priv *chip; | ||
983 | struct brcmf_core *arm; | ||
984 | |||
985 | brcmf_dbg(TRACE, "Enter\n"); | ||
986 | |||
987 | chip = container_of(pub, struct brcmf_chip_priv, pub); | ||
988 | arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); | ||
989 | if (arm) | ||
990 | return brcmf_chip_cr4_exitdl(chip, rstvec); | ||
991 | |||
992 | return brcmf_chip_cm3_exitdl(chip); | ||
993 | } | ||
994 | |||
995 | bool brcmf_chip_sr_capable(struct brcmf_chip *pub) | ||
996 | { | ||
997 | u32 base, addr, reg, pmu_cc3_mask = ~0; | ||
998 | struct brcmf_chip_priv *chip; | ||
999 | |||
1000 | brcmf_dbg(TRACE, "Enter\n"); | ||
1001 | |||
1002 | /* old chips with PMU version less than 17 don't support save restore */ | ||
1003 | if (pub->pmurev < 17) | ||
1004 | return false; | ||
1005 | |||
1006 | base = brcmf_chip_get_chipcommon(pub)->base; | ||
1007 | chip = container_of(pub, struct brcmf_chip_priv, pub); | ||
1008 | |||
1009 | switch (pub->chip) { | ||
1010 | case BCM4354_CHIP_ID: | ||
1011 | /* explicitly check SR engine enable bit */ | ||
1012 | pmu_cc3_mask = BIT(2); | ||
1013 | /* fall-through */ | ||
1014 | case BCM43241_CHIP_ID: | ||
1015 | case BCM4335_CHIP_ID: | ||
1016 | case BCM4339_CHIP_ID: | ||
1017 | /* read PMU chipcontrol register 3 */ | ||
1018 | addr = CORE_CC_REG(base, chipcontrol_addr); | ||
1019 | chip->ops->write32(chip->ctx, addr, 3); | ||
1020 | addr = CORE_CC_REG(base, chipcontrol_data); | ||
1021 | reg = chip->ops->read32(chip->ctx, addr); | ||
1022 | return (reg & pmu_cc3_mask) != 0; | ||
1023 | default: | ||
1024 | addr = CORE_CC_REG(base, pmucapabilities_ext); | ||
1025 | reg = chip->ops->read32(chip->ctx, addr); | ||
1026 | if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) | ||
1027 | return false; | ||
1028 | |||
1029 | addr = CORE_CC_REG(base, retention_ctl); | ||
1030 | reg = chip->ops->read32(chip->ctx, addr); | ||
1031 | return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | | ||
1032 | PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; | ||
1033 | } | ||
1034 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/brcm80211/brcmfmac/chip.h new file mode 100644 index 000000000000..c32908da90c8 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 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 | #ifndef BRCMF_CHIP_H | ||
17 | #define BRCMF_CHIP_H | ||
18 | |||
19 | #include <linux/types.h> | ||
20 | |||
21 | #define CORE_CC_REG(base, field) \ | ||
22 | (base + offsetof(struct chipcregs, field)) | ||
23 | |||
24 | /** | ||
25 | * struct brcmf_chip - chip level information. | ||
26 | * | ||
27 | * @chip: chip identifier. | ||
28 | * @chiprev: chip revision. | ||
29 | * @cc_caps: chipcommon core capabilities. | ||
30 | * @pmucaps: PMU capabilities. | ||
31 | * @pmurev: PMU revision. | ||
32 | * @rambase: RAM base address (only applicable for ARM CR4 chips). | ||
33 | * @ramsize: amount of RAM on chip. | ||
34 | * @name: string representation of the chip identifier. | ||
35 | */ | ||
36 | struct brcmf_chip { | ||
37 | u32 chip; | ||
38 | u32 chiprev; | ||
39 | u32 cc_caps; | ||
40 | u32 pmucaps; | ||
41 | u32 pmurev; | ||
42 | u32 rambase; | ||
43 | u32 ramsize; | ||
44 | char name[8]; | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * struct brcmf_core - core related information. | ||
49 | * | ||
50 | * @id: core identifier. | ||
51 | * @rev: core revision. | ||
52 | * @base: base address of core register space. | ||
53 | */ | ||
54 | struct brcmf_core { | ||
55 | u16 id; | ||
56 | u16 rev; | ||
57 | u32 base; | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * struct brcmf_buscore_ops - buscore specific callbacks. | ||
62 | * | ||
63 | * @read32: read 32-bit value over bus. | ||
64 | * @write32: write 32-bit value over bus. | ||
65 | * @prepare: prepare bus for core configuration. | ||
66 | * @setup: bus-specific core setup. | ||
67 | * @exit_dl: exit download state. | ||
68 | * The callback should use the provided @rstvec when non-zero. | ||
69 | */ | ||
70 | struct brcmf_buscore_ops { | ||
71 | u32 (*read32)(void *ctx, u32 addr); | ||
72 | void (*write32)(void *ctx, u32 addr, u32 value); | ||
73 | int (*prepare)(void *ctx); | ||
74 | int (*setup)(void *ctx, struct brcmf_chip *chip); | ||
75 | void (*exit_dl)(void *ctx, struct brcmf_chip *chip, u32 rstvec); | ||
76 | }; | ||
77 | |||
78 | struct brcmf_chip *brcmf_chip_attach(void *ctx, | ||
79 | const struct brcmf_buscore_ops *ops); | ||
80 | void brcmf_chip_detach(struct brcmf_chip *chip); | ||
81 | struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); | ||
82 | struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); | ||
83 | bool brcmf_chip_iscoreup(struct brcmf_core *core); | ||
84 | void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); | ||
85 | void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, | ||
86 | u32 postreset); | ||
87 | void brcmf_chip_enter_download(struct brcmf_chip *ci); | ||
88 | bool brcmf_chip_exit_download(struct brcmf_chip *ci, u32 rstvec); | ||
89 | bool brcmf_chip_sr_capable(struct brcmf_chip *pub); | ||
90 | |||
91 | #endif /* BRCMF_AXIDMP_H */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index d4d966beb840..7d28cd385092 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -1040,12 +1040,12 @@ void brcmf_detach(struct device *dev) | |||
1040 | 1040 | ||
1041 | brcmf_cfg80211_detach(drvr->config); | 1041 | brcmf_cfg80211_detach(drvr->config); |
1042 | 1042 | ||
1043 | brcmf_fws_deinit(drvr); | ||
1044 | |||
1043 | brcmf_bus_detach(drvr); | 1045 | brcmf_bus_detach(drvr); |
1044 | 1046 | ||
1045 | brcmf_proto_detach(drvr); | 1047 | brcmf_proto_detach(drvr); |
1046 | 1048 | ||
1047 | brcmf_fws_deinit(drvr); | ||
1048 | |||
1049 | brcmf_debugfs_detach(drvr); | 1049 | brcmf_debugfs_detach(drvr); |
1050 | bus_if->drvr = NULL; | 1050 | bus_if->drvr = NULL; |
1051 | kfree(drvr); | 1051 | kfree(drvr); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index ddaa9efd053d..13c89a0c4ba7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
25 | #include <linux/mmc/sdio.h> | 25 | #include <linux/mmc/sdio.h> |
26 | #include <linux/mmc/sdio_ids.h> | ||
26 | #include <linux/mmc/sdio_func.h> | 27 | #include <linux/mmc/sdio_func.h> |
27 | #include <linux/mmc/card.h> | 28 | #include <linux/mmc/card.h> |
28 | #include <linux/semaphore.h> | 29 | #include <linux/semaphore.h> |
@@ -40,7 +41,7 @@ | |||
40 | #include <brcm_hw_ids.h> | 41 | #include <brcm_hw_ids.h> |
41 | #include <soc.h> | 42 | #include <soc.h> |
42 | #include "sdio_host.h" | 43 | #include "sdio_host.h" |
43 | #include "sdio_chip.h" | 44 | #include "chip.h" |
44 | #include "nvram.h" | 45 | #include "nvram.h" |
45 | 46 | ||
46 | #define DCMD_RESP_TIMEOUT 2000 /* In milli second */ | 47 | #define DCMD_RESP_TIMEOUT 2000 /* In milli second */ |
@@ -112,8 +113,6 @@ struct rte_console { | |||
112 | #define BRCMF_TXBOUND 20 /* Default for max tx frames in | 113 | #define BRCMF_TXBOUND 20 /* Default for max tx frames in |
113 | one scheduling */ | 114 | one scheduling */ |
114 | 115 | ||
115 | #define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */ | ||
116 | |||
117 | #define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ | 116 | #define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ |
118 | 117 | ||
119 | #define MEMBLOCK 2048 /* Block size used for downloading | 118 | #define MEMBLOCK 2048 /* Block size used for downloading |
@@ -156,6 +155,34 @@ struct rte_console { | |||
156 | /* manfid tuple length, include tuple, link bytes */ | 155 | /* manfid tuple length, include tuple, link bytes */ |
157 | #define SBSDIO_CIS_MANFID_TUPLE_LEN 6 | 156 | #define SBSDIO_CIS_MANFID_TUPLE_LEN 6 |
158 | 157 | ||
158 | #define CORE_BUS_REG(base, field) \ | ||
159 | (base + offsetof(struct sdpcmd_regs, field)) | ||
160 | |||
161 | /* SDIO function 1 register CHIPCLKCSR */ | ||
162 | /* Force ALP request to backplane */ | ||
163 | #define SBSDIO_FORCE_ALP 0x01 | ||
164 | /* Force HT request to backplane */ | ||
165 | #define SBSDIO_FORCE_HT 0x02 | ||
166 | /* Force ILP request to backplane */ | ||
167 | #define SBSDIO_FORCE_ILP 0x04 | ||
168 | /* Make ALP ready (power up xtal) */ | ||
169 | #define SBSDIO_ALP_AVAIL_REQ 0x08 | ||
170 | /* Make HT ready (power up PLL) */ | ||
171 | #define SBSDIO_HT_AVAIL_REQ 0x10 | ||
172 | /* Squelch clock requests from HW */ | ||
173 | #define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 | ||
174 | /* Status: ALP is ready */ | ||
175 | #define SBSDIO_ALP_AVAIL 0x40 | ||
176 | /* Status: HT is ready */ | ||
177 | #define SBSDIO_HT_AVAIL 0x80 | ||
178 | #define SBSDIO_CSR_MASK 0x1F | ||
179 | #define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) | ||
180 | #define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) | ||
181 | #define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) | ||
182 | #define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) | ||
183 | #define SBSDIO_CLKAV(regval, alponly) \ | ||
184 | (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) | ||
185 | |||
159 | /* intstatus */ | 186 | /* intstatus */ |
160 | #define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ | 187 | #define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ |
161 | #define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ | 188 | #define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ |
@@ -276,7 +303,6 @@ struct rte_console { | |||
276 | /* Flags for SDH calls */ | 303 | /* Flags for SDH calls */ |
277 | #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) | 304 | #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) |
278 | 305 | ||
279 | #define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */ | ||
280 | #define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change | 306 | #define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change |
281 | * when idle | 307 | * when idle |
282 | */ | 308 | */ |
@@ -433,10 +459,11 @@ struct brcmf_sdio { | |||
433 | bool alp_only; /* Don't use HT clock (ALP only) */ | 459 | bool alp_only; /* Don't use HT clock (ALP only) */ |
434 | 460 | ||
435 | u8 *ctrl_frame_buf; | 461 | u8 *ctrl_frame_buf; |
436 | u32 ctrl_frame_len; | 462 | u16 ctrl_frame_len; |
437 | bool ctrl_frame_stat; | 463 | bool ctrl_frame_stat; |
438 | 464 | ||
439 | spinlock_t txqlock; | 465 | spinlock_t txq_lock; /* protect bus->txq */ |
466 | struct semaphore tx_seq_lock; /* protect bus->tx_seq */ | ||
440 | wait_queue_head_t ctrl_wait; | 467 | wait_queue_head_t ctrl_wait; |
441 | wait_queue_head_t dcmd_resp_wait; | 468 | wait_queue_head_t dcmd_resp_wait; |
442 | 469 | ||
@@ -483,16 +510,58 @@ static const uint max_roundup = 512; | |||
483 | 510 | ||
484 | #define ALIGNMENT 4 | 511 | #define ALIGNMENT 4 |
485 | 512 | ||
486 | static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE; | ||
487 | module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0); | ||
488 | MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]"); | ||
489 | |||
490 | enum brcmf_sdio_frmtype { | 513 | enum brcmf_sdio_frmtype { |
491 | BRCMF_SDIO_FT_NORMAL, | 514 | BRCMF_SDIO_FT_NORMAL, |
492 | BRCMF_SDIO_FT_SUPER, | 515 | BRCMF_SDIO_FT_SUPER, |
493 | BRCMF_SDIO_FT_SUB, | 516 | BRCMF_SDIO_FT_SUB, |
494 | }; | 517 | }; |
495 | 518 | ||
519 | #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) | ||
520 | |||
521 | /* SDIO Pad drive strength to select value mappings */ | ||
522 | struct sdiod_drive_str { | ||
523 | u8 strength; /* Pad Drive Strength in mA */ | ||
524 | u8 sel; /* Chip-specific select value */ | ||
525 | }; | ||
526 | |||
527 | /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */ | ||
528 | static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = { | ||
529 | {32, 0x6}, | ||
530 | {26, 0x7}, | ||
531 | {22, 0x4}, | ||
532 | {16, 0x5}, | ||
533 | {12, 0x2}, | ||
534 | {8, 0x3}, | ||
535 | {4, 0x0}, | ||
536 | {0, 0x1} | ||
537 | }; | ||
538 | |||
539 | /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ | ||
540 | static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = { | ||
541 | {6, 0x7}, | ||
542 | {5, 0x6}, | ||
543 | {4, 0x5}, | ||
544 | {3, 0x4}, | ||
545 | {2, 0x2}, | ||
546 | {1, 0x1}, | ||
547 | {0, 0x0} | ||
548 | }; | ||
549 | |||
550 | /* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ | ||
551 | static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = { | ||
552 | {3, 0x3}, | ||
553 | {2, 0x2}, | ||
554 | {1, 0x1}, | ||
555 | {0, 0x0} }; | ||
556 | |||
557 | /* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */ | ||
558 | static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { | ||
559 | {16, 0x7}, | ||
560 | {12, 0x5}, | ||
561 | {8, 0x3}, | ||
562 | {4, 0x1} | ||
563 | }; | ||
564 | |||
496 | #define BCM43143_FIRMWARE_NAME "brcm/brcmfmac43143-sdio.bin" | 565 | #define BCM43143_FIRMWARE_NAME "brcm/brcmfmac43143-sdio.bin" |
497 | #define BCM43143_NVRAM_NAME "brcm/brcmfmac43143-sdio.txt" | 566 | #define BCM43143_NVRAM_NAME "brcm/brcmfmac43143-sdio.txt" |
498 | #define BCM43241B0_FIRMWARE_NAME "brcm/brcmfmac43241b0-sdio.bin" | 567 | #define BCM43241B0_FIRMWARE_NAME "brcm/brcmfmac43241b0-sdio.bin" |
@@ -511,6 +580,8 @@ enum brcmf_sdio_frmtype { | |||
511 | #define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt" | 580 | #define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt" |
512 | #define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" | 581 | #define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" |
513 | #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" | 582 | #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" |
583 | #define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin" | ||
584 | #define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt" | ||
514 | 585 | ||
515 | MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME); | 586 | MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME); |
516 | MODULE_FIRMWARE(BCM43143_NVRAM_NAME); | 587 | MODULE_FIRMWARE(BCM43143_NVRAM_NAME); |
@@ -530,6 +601,8 @@ MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); | |||
530 | MODULE_FIRMWARE(BCM43362_NVRAM_NAME); | 601 | MODULE_FIRMWARE(BCM43362_NVRAM_NAME); |
531 | MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); | 602 | MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); |
532 | MODULE_FIRMWARE(BCM4339_NVRAM_NAME); | 603 | MODULE_FIRMWARE(BCM4339_NVRAM_NAME); |
604 | MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME); | ||
605 | MODULE_FIRMWARE(BCM4354_NVRAM_NAME); | ||
533 | 606 | ||
534 | struct brcmf_firmware_names { | 607 | struct brcmf_firmware_names { |
535 | u32 chipid; | 608 | u32 chipid; |
@@ -555,7 +628,8 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { | |||
555 | { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, | 628 | { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, |
556 | { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, | 629 | { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, |
557 | { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, | 630 | { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, |
558 | { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) } | 631 | { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, |
632 | { BCM4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } | ||
559 | }; | 633 | }; |
560 | 634 | ||
561 | 635 | ||
@@ -618,27 +692,24 @@ static bool data_ok(struct brcmf_sdio *bus) | |||
618 | * Reads a register in the SDIO hardware block. This block occupies a series of | 692 | * Reads a register in the SDIO hardware block. This block occupies a series of |
619 | * adresses on the 32 bit backplane bus. | 693 | * adresses on the 32 bit backplane bus. |
620 | */ | 694 | */ |
621 | static int | 695 | static int r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset) |
622 | r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset) | ||
623 | { | 696 | { |
624 | u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); | 697 | struct brcmf_core *core; |
625 | int ret; | 698 | int ret; |
626 | 699 | ||
627 | *regvar = brcmf_sdiod_regrl(bus->sdiodev, | 700 | core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); |
628 | bus->ci->c_inf[idx].base + offset, &ret); | 701 | *regvar = brcmf_sdiod_regrl(bus->sdiodev, core->base + offset, &ret); |
629 | 702 | ||
630 | return ret; | 703 | return ret; |
631 | } | 704 | } |
632 | 705 | ||
633 | static int | 706 | static int w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset) |
634 | w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset) | ||
635 | { | 707 | { |
636 | u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); | 708 | struct brcmf_core *core; |
637 | int ret; | 709 | int ret; |
638 | 710 | ||
639 | brcmf_sdiod_regwl(bus->sdiodev, | 711 | core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); |
640 | bus->ci->c_inf[idx].base + reg_offset, | 712 | brcmf_sdiod_regwl(bus->sdiodev, core->base + reg_offset, regval, &ret); |
641 | regval, &ret); | ||
642 | 713 | ||
643 | return ret; | 714 | return ret; |
644 | } | 715 | } |
@@ -650,16 +721,12 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) | |||
650 | int err = 0; | 721 | int err = 0; |
651 | int try_cnt = 0; | 722 | int try_cnt = 0; |
652 | 723 | ||
653 | brcmf_dbg(TRACE, "Enter\n"); | 724 | brcmf_dbg(TRACE, "Enter: on=%d\n", on); |
654 | 725 | ||
655 | wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); | 726 | wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); |
656 | /* 1st KSO write goes to AOS wake up core if device is asleep */ | 727 | /* 1st KSO write goes to AOS wake up core if device is asleep */ |
657 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, | 728 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, |
658 | wr_val, &err); | 729 | wr_val, &err); |
659 | if (err) { | ||
660 | brcmf_err("SDIO_AOS KSO write error: %d\n", err); | ||
661 | return err; | ||
662 | } | ||
663 | 730 | ||
664 | if (on) { | 731 | if (on) { |
665 | /* device WAKEUP through KSO: | 732 | /* device WAKEUP through KSO: |
@@ -689,18 +756,22 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) | |||
689 | &err); | 756 | &err); |
690 | if (((rd_val & bmask) == cmp_val) && !err) | 757 | if (((rd_val & bmask) == cmp_val) && !err) |
691 | break; | 758 | break; |
692 | brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n", | 759 | |
693 | try_cnt, MAX_KSO_ATTEMPTS, err); | ||
694 | udelay(KSO_WAIT_US); | 760 | udelay(KSO_WAIT_US); |
695 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, | 761 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, |
696 | wr_val, &err); | 762 | wr_val, &err); |
697 | } while (try_cnt++ < MAX_KSO_ATTEMPTS); | 763 | } while (try_cnt++ < MAX_KSO_ATTEMPTS); |
698 | 764 | ||
765 | if (try_cnt > 2) | ||
766 | brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt, | ||
767 | rd_val, err); | ||
768 | |||
769 | if (try_cnt > MAX_KSO_ATTEMPTS) | ||
770 | brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err); | ||
771 | |||
699 | return err; | 772 | return err; |
700 | } | 773 | } |
701 | 774 | ||
702 | #define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) | ||
703 | |||
704 | #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) | 775 | #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) |
705 | 776 | ||
706 | /* Turn backplane clock on or off */ | 777 | /* Turn backplane clock on or off */ |
@@ -799,7 +870,6 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok) | |||
799 | } | 870 | } |
800 | #endif /* defined (DEBUG) */ | 871 | #endif /* defined (DEBUG) */ |
801 | 872 | ||
802 | bus->activity = true; | ||
803 | } else { | 873 | } else { |
804 | clkreq = 0; | 874 | clkreq = 0; |
805 | 875 | ||
@@ -899,8 +969,9 @@ static int | |||
899 | brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) | 969 | brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) |
900 | { | 970 | { |
901 | int err = 0; | 971 | int err = 0; |
902 | brcmf_dbg(TRACE, "Enter\n"); | 972 | u8 clkcsr; |
903 | brcmf_dbg(SDIO, "request %s currently %s\n", | 973 | |
974 | brcmf_dbg(SDIO, "Enter: request %s currently %s\n", | ||
904 | (sleep ? "SLEEP" : "WAKE"), | 975 | (sleep ? "SLEEP" : "WAKE"), |
905 | (bus->sleeping ? "SLEEP" : "WAKE")); | 976 | (bus->sleeping ? "SLEEP" : "WAKE")); |
906 | 977 | ||
@@ -917,8 +988,20 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) | |||
917 | atomic_read(&bus->ipend) > 0 || | 988 | atomic_read(&bus->ipend) > 0 || |
918 | (!atomic_read(&bus->fcstate) && | 989 | (!atomic_read(&bus->fcstate) && |
919 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && | 990 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && |
920 | data_ok(bus))) | 991 | data_ok(bus))) { |
921 | return -EBUSY; | 992 | err = -EBUSY; |
993 | goto done; | ||
994 | } | ||
995 | |||
996 | clkcsr = brcmf_sdiod_regrb(bus->sdiodev, | ||
997 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
998 | &err); | ||
999 | if ((clkcsr & SBSDIO_CSR_MASK) == 0) { | ||
1000 | brcmf_dbg(SDIO, "no clock, set ALP\n"); | ||
1001 | brcmf_sdiod_regwb(bus->sdiodev, | ||
1002 | SBSDIO_FUNC1_CHIPCLKCSR, | ||
1003 | SBSDIO_ALP_AVAIL_REQ, &err); | ||
1004 | } | ||
922 | err = brcmf_sdio_kso_control(bus, false); | 1005 | err = brcmf_sdio_kso_control(bus, false); |
923 | /* disable watchdog */ | 1006 | /* disable watchdog */ |
924 | if (!err) | 1007 | if (!err) |
@@ -935,7 +1018,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) | |||
935 | } else { | 1018 | } else { |
936 | brcmf_err("error while changing bus sleep state %d\n", | 1019 | brcmf_err("error while changing bus sleep state %d\n", |
937 | err); | 1020 | err); |
938 | return err; | 1021 | goto done; |
939 | } | 1022 | } |
940 | } | 1023 | } |
941 | 1024 | ||
@@ -947,11 +1030,92 @@ end: | |||
947 | } else { | 1030 | } else { |
948 | brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); | 1031 | brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); |
949 | } | 1032 | } |
950 | 1033 | done: | |
1034 | brcmf_dbg(SDIO, "Exit: err=%d\n", err); | ||
951 | return err; | 1035 | return err; |
952 | 1036 | ||
953 | } | 1037 | } |
954 | 1038 | ||
1039 | #ifdef DEBUG | ||
1040 | static inline bool brcmf_sdio_valid_shared_address(u32 addr) | ||
1041 | { | ||
1042 | return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)); | ||
1043 | } | ||
1044 | |||
1045 | static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | ||
1046 | struct sdpcm_shared *sh) | ||
1047 | { | ||
1048 | u32 addr; | ||
1049 | int rv; | ||
1050 | u32 shaddr = 0; | ||
1051 | struct sdpcm_shared_le sh_le; | ||
1052 | __le32 addr_le; | ||
1053 | |||
1054 | shaddr = bus->ci->rambase + bus->ramsize - 4; | ||
1055 | |||
1056 | /* | ||
1057 | * Read last word in socram to determine | ||
1058 | * address of sdpcm_shared structure | ||
1059 | */ | ||
1060 | sdio_claim_host(bus->sdiodev->func[1]); | ||
1061 | brcmf_sdio_bus_sleep(bus, false, false); | ||
1062 | rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4); | ||
1063 | sdio_release_host(bus->sdiodev->func[1]); | ||
1064 | if (rv < 0) | ||
1065 | return rv; | ||
1066 | |||
1067 | addr = le32_to_cpu(addr_le); | ||
1068 | |||
1069 | brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr); | ||
1070 | |||
1071 | /* | ||
1072 | * Check if addr is valid. | ||
1073 | * NVRAM length at the end of memory should have been overwritten. | ||
1074 | */ | ||
1075 | if (!brcmf_sdio_valid_shared_address(addr)) { | ||
1076 | brcmf_err("invalid sdpcm_shared address 0x%08X\n", | ||
1077 | addr); | ||
1078 | return -EINVAL; | ||
1079 | } | ||
1080 | |||
1081 | /* Read hndrte_shared structure */ | ||
1082 | rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le, | ||
1083 | sizeof(struct sdpcm_shared_le)); | ||
1084 | if (rv < 0) | ||
1085 | return rv; | ||
1086 | |||
1087 | /* Endianness */ | ||
1088 | sh->flags = le32_to_cpu(sh_le.flags); | ||
1089 | sh->trap_addr = le32_to_cpu(sh_le.trap_addr); | ||
1090 | sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr); | ||
1091 | sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr); | ||
1092 | sh->assert_line = le32_to_cpu(sh_le.assert_line); | ||
1093 | sh->console_addr = le32_to_cpu(sh_le.console_addr); | ||
1094 | sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr); | ||
1095 | |||
1096 | if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) { | ||
1097 | brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n", | ||
1098 | SDPCM_SHARED_VERSION, | ||
1099 | sh->flags & SDPCM_SHARED_VERSION_MASK); | ||
1100 | return -EPROTO; | ||
1101 | } | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) | ||
1107 | { | ||
1108 | struct sdpcm_shared sh; | ||
1109 | |||
1110 | if (brcmf_sdio_readshared(bus, &sh) == 0) | ||
1111 | bus->console_addr = sh.console_addr; | ||
1112 | } | ||
1113 | #else | ||
1114 | static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) | ||
1115 | { | ||
1116 | } | ||
1117 | #endif /* DEBUG */ | ||
1118 | |||
955 | static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) | 1119 | static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) |
956 | { | 1120 | { |
957 | u32 intstatus = 0; | 1121 | u32 intstatus = 0; |
@@ -995,6 +1159,12 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) | |||
995 | else | 1159 | else |
996 | brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n", | 1160 | brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n", |
997 | bus->sdpcm_ver); | 1161 | bus->sdpcm_ver); |
1162 | |||
1163 | /* | ||
1164 | * Retrieve console state address now that firmware should have | ||
1165 | * updated it. | ||
1166 | */ | ||
1167 | brcmf_sdio_get_console_addr(bus); | ||
998 | } | 1168 | } |
999 | 1169 | ||
1000 | /* | 1170 | /* |
@@ -1083,6 +1253,28 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) | |||
1083 | bus->cur_read.len = 0; | 1253 | bus->cur_read.len = 0; |
1084 | } | 1254 | } |
1085 | 1255 | ||
1256 | static void brcmf_sdio_txfail(struct brcmf_sdio *bus) | ||
1257 | { | ||
1258 | struct brcmf_sdio_dev *sdiodev = bus->sdiodev; | ||
1259 | u8 i, hi, lo; | ||
1260 | |||
1261 | /* On failure, abort the command and terminate the frame */ | ||
1262 | brcmf_err("sdio error, abort command and terminate frame\n"); | ||
1263 | bus->sdcnt.tx_sderrs++; | ||
1264 | |||
1265 | brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2); | ||
1266 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); | ||
1267 | bus->sdcnt.f1regdata++; | ||
1268 | |||
1269 | for (i = 0; i < 3; i++) { | ||
1270 | hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL); | ||
1271 | lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL); | ||
1272 | bus->sdcnt.f1regdata += 2; | ||
1273 | if ((hi == 0) && (lo == 0)) | ||
1274 | break; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1086 | /* return total length of buffer chain */ | 1278 | /* return total length of buffer chain */ |
1087 | static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus) | 1279 | static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus) |
1088 | { | 1280 | { |
@@ -1955,7 +2147,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, | |||
1955 | memcpy(pkt_pad->data, | 2147 | memcpy(pkt_pad->data, |
1956 | pkt->data + pkt->len - tail_chop, | 2148 | pkt->data + pkt->len - tail_chop, |
1957 | tail_chop); | 2149 | tail_chop); |
1958 | *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; | 2150 | *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; |
1959 | skb_trim(pkt, pkt->len - tail_chop); | 2151 | skb_trim(pkt, pkt->len - tail_chop); |
1960 | skb_trim(pkt_pad, tail_pad + tail_chop); | 2152 | skb_trim(pkt_pad, tail_pad + tail_chop); |
1961 | __skb_queue_after(pktq, pkt, pkt_pad); | 2153 | __skb_queue_after(pktq, pkt, pkt_pad); |
@@ -2003,7 +2195,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, | |||
2003 | * already properly aligned and does not | 2195 | * already properly aligned and does not |
2004 | * need an sdpcm header. | 2196 | * need an sdpcm header. |
2005 | */ | 2197 | */ |
2006 | if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG) | 2198 | if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG) |
2007 | continue; | 2199 | continue; |
2008 | 2200 | ||
2009 | /* align packet data pointer */ | 2201 | /* align packet data pointer */ |
@@ -2037,10 +2229,10 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, | |||
2037 | if (BRCMF_BYTES_ON() && | 2229 | if (BRCMF_BYTES_ON() && |
2038 | ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || | 2230 | ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || |
2039 | (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) | 2231 | (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) |
2040 | brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, | 2232 | brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len, |
2041 | "Tx Frame:\n"); | 2233 | "Tx Frame:\n"); |
2042 | else if (BRCMF_HDRS_ON()) | 2234 | else if (BRCMF_HDRS_ON()) |
2043 | brcmf_dbg_hex_dump(true, pkt_next, | 2235 | brcmf_dbg_hex_dump(true, pkt_next->data, |
2044 | head_pad + bus->tx_hdrlen, | 2236 | head_pad + bus->tx_hdrlen, |
2045 | "Tx Header:\n"); | 2237 | "Tx Header:\n"); |
2046 | } | 2238 | } |
@@ -2067,11 +2259,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq) | |||
2067 | u8 *hdr; | 2259 | u8 *hdr; |
2068 | u32 dat_offset; | 2260 | u32 dat_offset; |
2069 | u16 tail_pad; | 2261 | u16 tail_pad; |
2070 | u32 dummy_flags, chop_len; | 2262 | u16 dummy_flags, chop_len; |
2071 | struct sk_buff *pkt_next, *tmp, *pkt_prev; | 2263 | struct sk_buff *pkt_next, *tmp, *pkt_prev; |
2072 | 2264 | ||
2073 | skb_queue_walk_safe(pktq, pkt_next, tmp) { | 2265 | skb_queue_walk_safe(pktq, pkt_next, tmp) { |
2074 | dummy_flags = *(u32 *)(pkt_next->cb); | 2266 | dummy_flags = *(u16 *)(pkt_next->cb); |
2075 | if (dummy_flags & ALIGN_SKB_FLAG) { | 2267 | if (dummy_flags & ALIGN_SKB_FLAG) { |
2076 | chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK; | 2268 | chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK; |
2077 | if (chop_len) { | 2269 | if (chop_len) { |
@@ -2100,7 +2292,6 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq, | |||
2100 | uint chan) | 2292 | uint chan) |
2101 | { | 2293 | { |
2102 | int ret; | 2294 | int ret; |
2103 | int i; | ||
2104 | struct sk_buff *pkt_next, *tmp; | 2295 | struct sk_buff *pkt_next, *tmp; |
2105 | 2296 | ||
2106 | brcmf_dbg(TRACE, "Enter\n"); | 2297 | brcmf_dbg(TRACE, "Enter\n"); |
@@ -2113,28 +2304,9 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq, | |||
2113 | ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq); | 2304 | ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq); |
2114 | bus->sdcnt.f2txdata++; | 2305 | bus->sdcnt.f2txdata++; |
2115 | 2306 | ||
2116 | if (ret < 0) { | 2307 | if (ret < 0) |
2117 | /* On failure, abort the command and terminate the frame */ | 2308 | brcmf_sdio_txfail(bus); |
2118 | brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", | ||
2119 | ret); | ||
2120 | bus->sdcnt.tx_sderrs++; | ||
2121 | 2309 | ||
2122 | brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); | ||
2123 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, | ||
2124 | SFC_WF_TERM, NULL); | ||
2125 | bus->sdcnt.f1regdata++; | ||
2126 | |||
2127 | for (i = 0; i < 3; i++) { | ||
2128 | u8 hi, lo; | ||
2129 | hi = brcmf_sdiod_regrb(bus->sdiodev, | ||
2130 | SBSDIO_FUNC1_WFRAMEBCHI, NULL); | ||
2131 | lo = brcmf_sdiod_regrb(bus->sdiodev, | ||
2132 | SBSDIO_FUNC1_WFRAMEBCLO, NULL); | ||
2133 | bus->sdcnt.f1regdata += 2; | ||
2134 | if ((hi == 0) && (lo == 0)) | ||
2135 | break; | ||
2136 | } | ||
2137 | } | ||
2138 | sdio_release_host(bus->sdiodev->func[1]); | 2310 | sdio_release_host(bus->sdiodev->func[1]); |
2139 | 2311 | ||
2140 | done: | 2312 | done: |
@@ -2164,13 +2336,15 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
2164 | /* Send frames until the limit or some other event */ | 2336 | /* Send frames until the limit or some other event */ |
2165 | for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { | 2337 | for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { |
2166 | pkt_num = 1; | 2338 | pkt_num = 1; |
2167 | __skb_queue_head_init(&pktq); | 2339 | if (down_interruptible(&bus->tx_seq_lock)) |
2340 | return cnt; | ||
2168 | if (bus->txglom) | 2341 | if (bus->txglom) |
2169 | pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, | 2342 | pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, |
2170 | brcmf_sdio_txglomsz); | 2343 | bus->sdiodev->txglomsz); |
2171 | pkt_num = min_t(u32, pkt_num, | 2344 | pkt_num = min_t(u32, pkt_num, |
2172 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)); | 2345 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)); |
2173 | spin_lock_bh(&bus->txqlock); | 2346 | __skb_queue_head_init(&pktq); |
2347 | spin_lock_bh(&bus->txq_lock); | ||
2174 | for (i = 0; i < pkt_num; i++) { | 2348 | for (i = 0; i < pkt_num; i++) { |
2175 | pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, | 2349 | pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, |
2176 | &prec_out); | 2350 | &prec_out); |
@@ -2178,15 +2352,19 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
2178 | break; | 2352 | break; |
2179 | __skb_queue_tail(&pktq, pkt); | 2353 | __skb_queue_tail(&pktq, pkt); |
2180 | } | 2354 | } |
2181 | spin_unlock_bh(&bus->txqlock); | 2355 | spin_unlock_bh(&bus->txq_lock); |
2182 | if (i == 0) | 2356 | if (i == 0) { |
2357 | up(&bus->tx_seq_lock); | ||
2183 | break; | 2358 | break; |
2359 | } | ||
2184 | 2360 | ||
2185 | ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); | 2361 | ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); |
2362 | up(&bus->tx_seq_lock); | ||
2363 | |||
2186 | cnt += i; | 2364 | cnt += i; |
2187 | 2365 | ||
2188 | /* In poll mode, need to check for other events */ | 2366 | /* In poll mode, need to check for other events */ |
2189 | if (!bus->intr && cnt) { | 2367 | if (!bus->intr) { |
2190 | /* Check device status, signal pending interrupt */ | 2368 | /* Check device status, signal pending interrupt */ |
2191 | sdio_claim_host(bus->sdiodev->func[1]); | 2369 | sdio_claim_host(bus->sdiodev->func[1]); |
2192 | ret = r_sdreg32(bus, &intstatus, | 2370 | ret = r_sdreg32(bus, &intstatus, |
@@ -2211,6 +2389,68 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
2211 | return cnt; | 2389 | return cnt; |
2212 | } | 2390 | } |
2213 | 2391 | ||
2392 | static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len) | ||
2393 | { | ||
2394 | u8 doff; | ||
2395 | u16 pad; | ||
2396 | uint retries = 0; | ||
2397 | struct brcmf_sdio_hdrinfo hd_info = {0}; | ||
2398 | int ret; | ||
2399 | |||
2400 | brcmf_dbg(TRACE, "Enter\n"); | ||
2401 | |||
2402 | /* Back the pointer to make room for bus header */ | ||
2403 | frame -= bus->tx_hdrlen; | ||
2404 | len += bus->tx_hdrlen; | ||
2405 | |||
2406 | /* Add alignment padding (optional for ctl frames) */ | ||
2407 | doff = ((unsigned long)frame % bus->head_align); | ||
2408 | if (doff) { | ||
2409 | frame -= doff; | ||
2410 | len += doff; | ||
2411 | memset(frame + bus->tx_hdrlen, 0, doff); | ||
2412 | } | ||
2413 | |||
2414 | /* Round send length to next SDIO block */ | ||
2415 | pad = 0; | ||
2416 | if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { | ||
2417 | pad = bus->blocksize - (len % bus->blocksize); | ||
2418 | if ((pad > bus->roundup) || (pad >= bus->blocksize)) | ||
2419 | pad = 0; | ||
2420 | } else if (len % bus->head_align) { | ||
2421 | pad = bus->head_align - (len % bus->head_align); | ||
2422 | } | ||
2423 | len += pad; | ||
2424 | |||
2425 | hd_info.len = len - pad; | ||
2426 | hd_info.channel = SDPCM_CONTROL_CHANNEL; | ||
2427 | hd_info.dat_offset = doff + bus->tx_hdrlen; | ||
2428 | hd_info.seq_num = bus->tx_seq; | ||
2429 | hd_info.lastfrm = true; | ||
2430 | hd_info.tail_pad = pad; | ||
2431 | brcmf_sdio_hdpack(bus, frame, &hd_info); | ||
2432 | |||
2433 | if (bus->txglom) | ||
2434 | brcmf_sdio_update_hwhdr(frame, len); | ||
2435 | |||
2436 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), | ||
2437 | frame, len, "Tx Frame:\n"); | ||
2438 | brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && | ||
2439 | BRCMF_HDRS_ON(), | ||
2440 | frame, min_t(u16, len, 16), "TxHdr:\n"); | ||
2441 | |||
2442 | do { | ||
2443 | ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len); | ||
2444 | |||
2445 | if (ret < 0) | ||
2446 | brcmf_sdio_txfail(bus); | ||
2447 | else | ||
2448 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; | ||
2449 | } while (ret < 0 && retries++ < TXRETRIES); | ||
2450 | |||
2451 | return ret; | ||
2452 | } | ||
2453 | |||
2214 | static void brcmf_sdio_bus_stop(struct device *dev) | 2454 | static void brcmf_sdio_bus_stop(struct device *dev) |
2215 | { | 2455 | { |
2216 | u32 local_hostintmask; | 2456 | u32 local_hostintmask; |
@@ -2292,21 +2532,29 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) | |||
2292 | } | 2532 | } |
2293 | } | 2533 | } |
2294 | 2534 | ||
2535 | static void atomic_orr(int val, atomic_t *v) | ||
2536 | { | ||
2537 | int old_val; | ||
2538 | |||
2539 | old_val = atomic_read(v); | ||
2540 | while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) | ||
2541 | old_val = atomic_read(v); | ||
2542 | } | ||
2543 | |||
2295 | static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) | 2544 | static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) |
2296 | { | 2545 | { |
2297 | u8 idx; | 2546 | struct brcmf_core *buscore; |
2298 | u32 addr; | 2547 | u32 addr; |
2299 | unsigned long val; | 2548 | unsigned long val; |
2300 | int n, ret; | 2549 | int ret; |
2301 | 2550 | ||
2302 | idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); | 2551 | buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); |
2303 | addr = bus->ci->c_inf[idx].base + | 2552 | addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); |
2304 | offsetof(struct sdpcmd_regs, intstatus); | ||
2305 | 2553 | ||
2306 | val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); | 2554 | val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); |
2307 | bus->sdcnt.f1regdata++; | 2555 | bus->sdcnt.f1regdata++; |
2308 | if (ret != 0) | 2556 | if (ret != 0) |
2309 | val = 0; | 2557 | return ret; |
2310 | 2558 | ||
2311 | val &= bus->hostintmask; | 2559 | val &= bus->hostintmask; |
2312 | atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); | 2560 | atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); |
@@ -2315,13 +2563,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) | |||
2315 | if (val) { | 2563 | if (val) { |
2316 | brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); | 2564 | brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); |
2317 | bus->sdcnt.f1regdata++; | 2565 | bus->sdcnt.f1regdata++; |
2318 | } | 2566 | atomic_orr(val, &bus->intstatus); |
2319 | |||
2320 | if (ret) { | ||
2321 | atomic_set(&bus->intstatus, 0); | ||
2322 | } else if (val) { | ||
2323 | for_each_set_bit(n, &val, 32) | ||
2324 | set_bit(n, (unsigned long *)&bus->intstatus.counter); | ||
2325 | } | 2567 | } |
2326 | 2568 | ||
2327 | return ret; | 2569 | return ret; |
@@ -2331,10 +2573,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) | |||
2331 | { | 2573 | { |
2332 | u32 newstatus = 0; | 2574 | u32 newstatus = 0; |
2333 | unsigned long intstatus; | 2575 | unsigned long intstatus; |
2334 | uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ | ||
2335 | uint txlimit = bus->txbound; /* Tx frames to send before resched */ | 2576 | uint txlimit = bus->txbound; /* Tx frames to send before resched */ |
2336 | uint framecnt = 0; /* Temporary counter of tx/rx frames */ | 2577 | uint framecnt; /* Temporary counter of tx/rx frames */ |
2337 | int err = 0, n; | 2578 | int err = 0; |
2338 | 2579 | ||
2339 | brcmf_dbg(TRACE, "Enter\n"); | 2580 | brcmf_dbg(TRACE, "Enter\n"); |
2340 | 2581 | ||
@@ -2431,70 +2672,38 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) | |||
2431 | intstatus &= ~I_HMB_FRAME_IND; | 2672 | intstatus &= ~I_HMB_FRAME_IND; |
2432 | 2673 | ||
2433 | /* On frame indication, read available frames */ | 2674 | /* On frame indication, read available frames */ |
2434 | if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) { | 2675 | if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) { |
2435 | framecnt = brcmf_sdio_readframes(bus, rxlimit); | 2676 | brcmf_sdio_readframes(bus, bus->rxbound); |
2436 | if (!bus->rxpending) | 2677 | if (!bus->rxpending) |
2437 | intstatus &= ~I_HMB_FRAME_IND; | 2678 | intstatus &= ~I_HMB_FRAME_IND; |
2438 | rxlimit -= min(framecnt, rxlimit); | ||
2439 | } | 2679 | } |
2440 | 2680 | ||
2441 | /* Keep still-pending events for next scheduling */ | 2681 | /* Keep still-pending events for next scheduling */ |
2442 | if (intstatus) { | 2682 | if (intstatus) |
2443 | for_each_set_bit(n, &intstatus, 32) | 2683 | atomic_orr(intstatus, &bus->intstatus); |
2444 | set_bit(n, (unsigned long *)&bus->intstatus.counter); | ||
2445 | } | ||
2446 | 2684 | ||
2447 | brcmf_sdio_clrintr(bus); | 2685 | brcmf_sdio_clrintr(bus); |
2448 | 2686 | ||
2449 | if (data_ok(bus) && bus->ctrl_frame_stat && | 2687 | if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && |
2450 | (bus->clkstate == CLK_AVAIL)) { | 2688 | (down_interruptible(&bus->tx_seq_lock) == 0)) { |
2451 | int i; | 2689 | if (data_ok(bus)) { |
2452 | 2690 | sdio_claim_host(bus->sdiodev->func[1]); | |
2453 | sdio_claim_host(bus->sdiodev->func[1]); | 2691 | err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, |
2454 | err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf, | 2692 | bus->ctrl_frame_len); |
2455 | (u32)bus->ctrl_frame_len); | 2693 | sdio_release_host(bus->sdiodev->func[1]); |
2456 | |||
2457 | if (err < 0) { | ||
2458 | /* On failure, abort the command and | ||
2459 | terminate the frame */ | ||
2460 | brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", | ||
2461 | err); | ||
2462 | bus->sdcnt.tx_sderrs++; | ||
2463 | |||
2464 | brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); | ||
2465 | |||
2466 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, | ||
2467 | SFC_WF_TERM, &err); | ||
2468 | bus->sdcnt.f1regdata++; | ||
2469 | |||
2470 | for (i = 0; i < 3; i++) { | ||
2471 | u8 hi, lo; | ||
2472 | hi = brcmf_sdiod_regrb(bus->sdiodev, | ||
2473 | SBSDIO_FUNC1_WFRAMEBCHI, | ||
2474 | &err); | ||
2475 | lo = brcmf_sdiod_regrb(bus->sdiodev, | ||
2476 | SBSDIO_FUNC1_WFRAMEBCLO, | ||
2477 | &err); | ||
2478 | bus->sdcnt.f1regdata += 2; | ||
2479 | if ((hi == 0) && (lo == 0)) | ||
2480 | break; | ||
2481 | } | ||
2482 | 2694 | ||
2483 | } else { | 2695 | bus->ctrl_frame_stat = false; |
2484 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; | 2696 | brcmf_sdio_wait_event_wakeup(bus); |
2485 | } | 2697 | } |
2486 | sdio_release_host(bus->sdiodev->func[1]); | 2698 | up(&bus->tx_seq_lock); |
2487 | bus->ctrl_frame_stat = false; | ||
2488 | brcmf_sdio_wait_event_wakeup(bus); | ||
2489 | } | 2699 | } |
2490 | /* Send queued frames (limit 1 if rx may still be pending) */ | 2700 | /* Send queued frames (limit 1 if rx may still be pending) */ |
2491 | else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && | 2701 | if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && |
2492 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit | 2702 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && |
2493 | && data_ok(bus)) { | 2703 | data_ok(bus)) { |
2494 | framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : | 2704 | framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : |
2495 | txlimit; | 2705 | txlimit; |
2496 | framecnt = brcmf_sdio_sendfromq(bus, framecnt); | 2706 | brcmf_sdio_sendfromq(bus, framecnt); |
2497 | txlimit -= framecnt; | ||
2498 | } | 2707 | } |
2499 | 2708 | ||
2500 | if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) { | 2709 | if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) { |
@@ -2504,19 +2713,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) | |||
2504 | atomic_read(&bus->ipend) > 0 || | 2713 | atomic_read(&bus->ipend) > 0 || |
2505 | (!atomic_read(&bus->fcstate) && | 2714 | (!atomic_read(&bus->fcstate) && |
2506 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && | 2715 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && |
2507 | data_ok(bus)) || PKT_AVAILABLE()) { | 2716 | data_ok(bus))) { |
2508 | atomic_inc(&bus->dpc_tskcnt); | 2717 | atomic_inc(&bus->dpc_tskcnt); |
2509 | } | 2718 | } |
2510 | |||
2511 | /* If we're done for now, turn off clock request. */ | ||
2512 | if ((bus->clkstate != CLK_PENDING) | ||
2513 | && bus->idletime == BRCMF_IDLE_IMMEDIATE) { | ||
2514 | bus->activity = false; | ||
2515 | brcmf_dbg(SDIO, "idle state\n"); | ||
2516 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2517 | brcmf_sdio_bus_sleep(bus, true, false); | ||
2518 | sdio_release_host(bus->sdiodev->func[1]); | ||
2519 | } | ||
2520 | } | 2719 | } |
2521 | 2720 | ||
2522 | static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev) | 2721 | static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev) |
@@ -2531,15 +2730,12 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev) | |||
2531 | static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) | 2730 | static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) |
2532 | { | 2731 | { |
2533 | int ret = -EBADE; | 2732 | int ret = -EBADE; |
2534 | uint datalen, prec; | 2733 | uint prec; |
2535 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 2734 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
2536 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | 2735 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
2537 | struct brcmf_sdio *bus = sdiodev->bus; | 2736 | struct brcmf_sdio *bus = sdiodev->bus; |
2538 | ulong flags; | ||
2539 | 2737 | ||
2540 | brcmf_dbg(TRACE, "Enter\n"); | 2738 | brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len); |
2541 | |||
2542 | datalen = pkt->len; | ||
2543 | 2739 | ||
2544 | /* Add space for the header */ | 2740 | /* Add space for the header */ |
2545 | skb_push(pkt, bus->tx_hdrlen); | 2741 | skb_push(pkt, bus->tx_hdrlen); |
@@ -2553,7 +2749,9 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) | |||
2553 | bus->sdcnt.fcqueued++; | 2749 | bus->sdcnt.fcqueued++; |
2554 | 2750 | ||
2555 | /* Priority based enq */ | 2751 | /* Priority based enq */ |
2556 | spin_lock_irqsave(&bus->txqlock, flags); | 2752 | spin_lock_bh(&bus->txq_lock); |
2753 | /* reset bus_flags in packet cb */ | ||
2754 | *(u16 *)(pkt->cb) = 0; | ||
2557 | if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { | 2755 | if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { |
2558 | skb_pull(pkt, bus->tx_hdrlen); | 2756 | skb_pull(pkt, bus->tx_hdrlen); |
2559 | brcmf_err("out of bus->txq !!!\n"); | 2757 | brcmf_err("out of bus->txq !!!\n"); |
@@ -2566,7 +2764,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) | |||
2566 | bus->txoff = true; | 2764 | bus->txoff = true; |
2567 | brcmf_txflowblock(bus->sdiodev->dev, true); | 2765 | brcmf_txflowblock(bus->sdiodev->dev, true); |
2568 | } | 2766 | } |
2569 | spin_unlock_irqrestore(&bus->txqlock, flags); | 2767 | spin_unlock_bh(&bus->txq_lock); |
2570 | 2768 | ||
2571 | #ifdef DEBUG | 2769 | #ifdef DEBUG |
2572 | if (pktq_plen(&bus->txq, prec) > qcount[prec]) | 2770 | if (pktq_plen(&bus->txq, prec) > qcount[prec]) |
@@ -2661,110 +2859,27 @@ break2: | |||
2661 | } | 2859 | } |
2662 | #endif /* DEBUG */ | 2860 | #endif /* DEBUG */ |
2663 | 2861 | ||
2664 | static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) | ||
2665 | { | ||
2666 | int i; | ||
2667 | int ret; | ||
2668 | |||
2669 | bus->ctrl_frame_stat = false; | ||
2670 | ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len); | ||
2671 | |||
2672 | if (ret < 0) { | ||
2673 | /* On failure, abort the command and terminate the frame */ | ||
2674 | brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", | ||
2675 | ret); | ||
2676 | bus->sdcnt.tx_sderrs++; | ||
2677 | |||
2678 | brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); | ||
2679 | |||
2680 | brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, | ||
2681 | SFC_WF_TERM, NULL); | ||
2682 | bus->sdcnt.f1regdata++; | ||
2683 | |||
2684 | for (i = 0; i < 3; i++) { | ||
2685 | u8 hi, lo; | ||
2686 | hi = brcmf_sdiod_regrb(bus->sdiodev, | ||
2687 | SBSDIO_FUNC1_WFRAMEBCHI, NULL); | ||
2688 | lo = brcmf_sdiod_regrb(bus->sdiodev, | ||
2689 | SBSDIO_FUNC1_WFRAMEBCLO, NULL); | ||
2690 | bus->sdcnt.f1regdata += 2; | ||
2691 | if (hi == 0 && lo == 0) | ||
2692 | break; | ||
2693 | } | ||
2694 | return ret; | ||
2695 | } | ||
2696 | |||
2697 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; | ||
2698 | |||
2699 | return ret; | ||
2700 | } | ||
2701 | |||
2702 | static int | 2862 | static int |
2703 | brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) | 2863 | brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) |
2704 | { | 2864 | { |
2705 | u8 *frame; | ||
2706 | u16 len, pad; | ||
2707 | uint retries = 0; | ||
2708 | u8 doff = 0; | ||
2709 | int ret = -1; | ||
2710 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 2865 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
2711 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | 2866 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
2712 | struct brcmf_sdio *bus = sdiodev->bus; | 2867 | struct brcmf_sdio *bus = sdiodev->bus; |
2713 | struct brcmf_sdio_hdrinfo hd_info = {0}; | 2868 | int ret = -1; |
2714 | 2869 | ||
2715 | brcmf_dbg(TRACE, "Enter\n"); | 2870 | brcmf_dbg(TRACE, "Enter\n"); |
2716 | 2871 | ||
2717 | /* Back the pointer to make a room for bus header */ | 2872 | if (down_interruptible(&bus->tx_seq_lock)) |
2718 | frame = msg - bus->tx_hdrlen; | 2873 | return -EINTR; |
2719 | len = (msglen += bus->tx_hdrlen); | ||
2720 | |||
2721 | /* Add alignment padding (optional for ctl frames) */ | ||
2722 | doff = ((unsigned long)frame % bus->head_align); | ||
2723 | if (doff) { | ||
2724 | frame -= doff; | ||
2725 | len += doff; | ||
2726 | msglen += doff; | ||
2727 | memset(frame, 0, doff + bus->tx_hdrlen); | ||
2728 | } | ||
2729 | /* precondition: doff < bus->head_align */ | ||
2730 | doff += bus->tx_hdrlen; | ||
2731 | |||
2732 | /* Round send length to next SDIO block */ | ||
2733 | pad = 0; | ||
2734 | if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { | ||
2735 | pad = bus->blocksize - (len % bus->blocksize); | ||
2736 | if ((pad > bus->roundup) || (pad >= bus->blocksize)) | ||
2737 | pad = 0; | ||
2738 | } else if (len % bus->head_align) { | ||
2739 | pad = bus->head_align - (len % bus->head_align); | ||
2740 | } | ||
2741 | len += pad; | ||
2742 | |||
2743 | /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ | ||
2744 | |||
2745 | /* Make sure backplane clock is on */ | ||
2746 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2747 | brcmf_sdio_bus_sleep(bus, false, false); | ||
2748 | sdio_release_host(bus->sdiodev->func[1]); | ||
2749 | |||
2750 | hd_info.len = (u16)msglen; | ||
2751 | hd_info.channel = SDPCM_CONTROL_CHANNEL; | ||
2752 | hd_info.dat_offset = doff; | ||
2753 | hd_info.seq_num = bus->tx_seq; | ||
2754 | hd_info.lastfrm = true; | ||
2755 | hd_info.tail_pad = pad; | ||
2756 | brcmf_sdio_hdpack(bus, frame, &hd_info); | ||
2757 | |||
2758 | if (bus->txglom) | ||
2759 | brcmf_sdio_update_hwhdr(frame, len); | ||
2760 | 2874 | ||
2761 | if (!data_ok(bus)) { | 2875 | if (!data_ok(bus)) { |
2762 | brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", | 2876 | brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", |
2763 | bus->tx_max, bus->tx_seq); | 2877 | bus->tx_max, bus->tx_seq); |
2764 | bus->ctrl_frame_stat = true; | 2878 | up(&bus->tx_seq_lock); |
2765 | /* Send from dpc */ | 2879 | /* Send from dpc */ |
2766 | bus->ctrl_frame_buf = frame; | 2880 | bus->ctrl_frame_buf = msg; |
2767 | bus->ctrl_frame_len = len; | 2881 | bus->ctrl_frame_len = msglen; |
2882 | bus->ctrl_frame_stat = true; | ||
2768 | 2883 | ||
2769 | wait_event_interruptible_timeout(bus->ctrl_wait, | 2884 | wait_event_interruptible_timeout(bus->ctrl_wait, |
2770 | !bus->ctrl_frame_stat, | 2885 | !bus->ctrl_frame_stat, |
@@ -2775,31 +2890,18 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) | |||
2775 | ret = 0; | 2890 | ret = 0; |
2776 | } else { | 2891 | } else { |
2777 | brcmf_dbg(SDIO, "ctrl_frame_stat == true\n"); | 2892 | brcmf_dbg(SDIO, "ctrl_frame_stat == true\n"); |
2893 | bus->ctrl_frame_stat = false; | ||
2894 | if (down_interruptible(&bus->tx_seq_lock)) | ||
2895 | return -EINTR; | ||
2778 | ret = -1; | 2896 | ret = -1; |
2779 | } | 2897 | } |
2780 | } | 2898 | } |
2781 | |||
2782 | if (ret == -1) { | 2899 | if (ret == -1) { |
2783 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), | ||
2784 | frame, len, "Tx Frame:\n"); | ||
2785 | brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && | ||
2786 | BRCMF_HDRS_ON(), | ||
2787 | frame, min_t(u16, len, 16), "TxHdr:\n"); | ||
2788 | |||
2789 | do { | ||
2790 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2791 | ret = brcmf_sdio_tx_frame(bus, frame, len); | ||
2792 | sdio_release_host(bus->sdiodev->func[1]); | ||
2793 | } while (ret < 0 && retries++ < TXRETRIES); | ||
2794 | } | ||
2795 | |||
2796 | if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && | ||
2797 | atomic_read(&bus->dpc_tskcnt) == 0) { | ||
2798 | bus->activity = false; | ||
2799 | sdio_claim_host(bus->sdiodev->func[1]); | 2900 | sdio_claim_host(bus->sdiodev->func[1]); |
2800 | brcmf_dbg(INFO, "idle\n"); | 2901 | brcmf_sdio_bus_sleep(bus, false, false); |
2801 | brcmf_sdio_clkctl(bus, CLK_NONE, true); | 2902 | ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen); |
2802 | sdio_release_host(bus->sdiodev->func[1]); | 2903 | sdio_release_host(bus->sdiodev->func[1]); |
2904 | up(&bus->tx_seq_lock); | ||
2803 | } | 2905 | } |
2804 | 2906 | ||
2805 | if (ret) | 2907 | if (ret) |
@@ -2811,72 +2913,6 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) | |||
2811 | } | 2913 | } |
2812 | 2914 | ||
2813 | #ifdef DEBUG | 2915 | #ifdef DEBUG |
2814 | static inline bool brcmf_sdio_valid_shared_address(u32 addr) | ||
2815 | { | ||
2816 | return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)); | ||
2817 | } | ||
2818 | |||
2819 | static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | ||
2820 | struct sdpcm_shared *sh) | ||
2821 | { | ||
2822 | u32 addr; | ||
2823 | int rv; | ||
2824 | u32 shaddr = 0; | ||
2825 | struct sdpcm_shared_le sh_le; | ||
2826 | __le32 addr_le; | ||
2827 | |||
2828 | shaddr = bus->ci->rambase + bus->ramsize - 4; | ||
2829 | |||
2830 | /* | ||
2831 | * Read last word in socram to determine | ||
2832 | * address of sdpcm_shared structure | ||
2833 | */ | ||
2834 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2835 | brcmf_sdio_bus_sleep(bus, false, false); | ||
2836 | rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4); | ||
2837 | sdio_release_host(bus->sdiodev->func[1]); | ||
2838 | if (rv < 0) | ||
2839 | return rv; | ||
2840 | |||
2841 | addr = le32_to_cpu(addr_le); | ||
2842 | |||
2843 | brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr); | ||
2844 | |||
2845 | /* | ||
2846 | * Check if addr is valid. | ||
2847 | * NVRAM length at the end of memory should have been overwritten. | ||
2848 | */ | ||
2849 | if (!brcmf_sdio_valid_shared_address(addr)) { | ||
2850 | brcmf_err("invalid sdpcm_shared address 0x%08X\n", | ||
2851 | addr); | ||
2852 | return -EINVAL; | ||
2853 | } | ||
2854 | |||
2855 | /* Read hndrte_shared structure */ | ||
2856 | rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le, | ||
2857 | sizeof(struct sdpcm_shared_le)); | ||
2858 | if (rv < 0) | ||
2859 | return rv; | ||
2860 | |||
2861 | /* Endianness */ | ||
2862 | sh->flags = le32_to_cpu(sh_le.flags); | ||
2863 | sh->trap_addr = le32_to_cpu(sh_le.trap_addr); | ||
2864 | sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr); | ||
2865 | sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr); | ||
2866 | sh->assert_line = le32_to_cpu(sh_le.assert_line); | ||
2867 | sh->console_addr = le32_to_cpu(sh_le.console_addr); | ||
2868 | sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr); | ||
2869 | |||
2870 | if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) { | ||
2871 | brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n", | ||
2872 | SDPCM_SHARED_VERSION, | ||
2873 | sh->flags & SDPCM_SHARED_VERSION_MASK); | ||
2874 | return -EPROTO; | ||
2875 | } | ||
2876 | |||
2877 | return 0; | ||
2878 | } | ||
2879 | |||
2880 | static int brcmf_sdio_dump_console(struct brcmf_sdio *bus, | 2916 | static int brcmf_sdio_dump_console(struct brcmf_sdio *bus, |
2881 | struct sdpcm_shared *sh, char __user *data, | 2917 | struct sdpcm_shared *sh, char __user *data, |
2882 | size_t count) | 2918 | size_t count) |
@@ -3106,6 +3142,8 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) | |||
3106 | debugfs_create_file("forensics", S_IRUGO, dentry, bus, | 3142 | debugfs_create_file("forensics", S_IRUGO, dentry, bus, |
3107 | &brcmf_sdio_forensic_ops); | 3143 | &brcmf_sdio_forensic_ops); |
3108 | brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt); | 3144 | brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt); |
3145 | debugfs_create_u32("console_interval", 0644, dentry, | ||
3146 | &bus->console_interval); | ||
3109 | } | 3147 | } |
3110 | #else | 3148 | #else |
3111 | static int brcmf_sdio_checkdied(struct brcmf_sdio *bus) | 3149 | static int brcmf_sdio_checkdied(struct brcmf_sdio *bus) |
@@ -3224,32 +3262,17 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus, | |||
3224 | const struct firmware *fw) | 3262 | const struct firmware *fw) |
3225 | { | 3263 | { |
3226 | int err; | 3264 | int err; |
3227 | int offset; | ||
3228 | int address; | ||
3229 | int len; | ||
3230 | 3265 | ||
3231 | brcmf_dbg(TRACE, "Enter\n"); | 3266 | brcmf_dbg(TRACE, "Enter\n"); |
3232 | 3267 | ||
3233 | err = 0; | 3268 | err = brcmf_sdiod_ramrw(bus->sdiodev, true, bus->ci->rambase, |
3234 | offset = 0; | 3269 | (u8 *)fw->data, fw->size); |
3235 | address = bus->ci->rambase; | 3270 | if (err) |
3236 | while (offset < fw->size) { | 3271 | brcmf_err("error %d on writing %d membytes at 0x%08x\n", |
3237 | len = ((offset + MEMBLOCK) < fw->size) ? MEMBLOCK : | 3272 | err, (int)fw->size, bus->ci->rambase); |
3238 | fw->size - offset; | 3273 | else if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase, |
3239 | err = brcmf_sdiod_ramrw(bus->sdiodev, true, address, | 3274 | (u8 *)fw->data, fw->size)) |
3240 | (u8 *)&fw->data[offset], len); | 3275 | err = -EIO; |
3241 | if (err) { | ||
3242 | brcmf_err("error %d on writing %d membytes at 0x%08x\n", | ||
3243 | err, len, address); | ||
3244 | return err; | ||
3245 | } | ||
3246 | offset += len; | ||
3247 | address += len; | ||
3248 | } | ||
3249 | if (!err) | ||
3250 | if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase, | ||
3251 | (u8 *)fw->data, fw->size)) | ||
3252 | err = -EIO; | ||
3253 | 3276 | ||
3254 | return err; | 3277 | return err; |
3255 | } | 3278 | } |
@@ -3292,7 +3315,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus) | |||
3292 | brcmf_sdio_clkctl(bus, CLK_AVAIL, false); | 3315 | brcmf_sdio_clkctl(bus, CLK_AVAIL, false); |
3293 | 3316 | ||
3294 | /* Keep arm in reset */ | 3317 | /* Keep arm in reset */ |
3295 | brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci); | 3318 | brcmf_chip_enter_download(bus->ci); |
3296 | 3319 | ||
3297 | fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN); | 3320 | fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN); |
3298 | if (fw == NULL) { | 3321 | if (fw == NULL) { |
@@ -3324,7 +3347,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus) | |||
3324 | } | 3347 | } |
3325 | 3348 | ||
3326 | /* Take arm out of reset */ | 3349 | /* Take arm out of reset */ |
3327 | if (!brcmf_sdio_chip_exit_download(bus->sdiodev, bus->ci, rstvec)) { | 3350 | if (!brcmf_chip_exit_download(bus->ci, rstvec)) { |
3328 | brcmf_err("error getting out of ARM core reset\n"); | 3351 | brcmf_err("error getting out of ARM core reset\n"); |
3329 | goto err; | 3352 | goto err; |
3330 | } | 3353 | } |
@@ -3339,40 +3362,6 @@ err: | |||
3339 | return bcmerror; | 3362 | return bcmerror; |
3340 | } | 3363 | } |
3341 | 3364 | ||
3342 | static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus) | ||
3343 | { | ||
3344 | u32 addr, reg, pmu_cc3_mask = ~0; | ||
3345 | int err; | ||
3346 | |||
3347 | brcmf_dbg(TRACE, "Enter\n"); | ||
3348 | |||
3349 | /* old chips with PMU version less than 17 don't support save restore */ | ||
3350 | if (bus->ci->pmurev < 17) | ||
3351 | return false; | ||
3352 | |||
3353 | switch (bus->ci->chip) { | ||
3354 | case BCM43241_CHIP_ID: | ||
3355 | case BCM4335_CHIP_ID: | ||
3356 | case BCM4339_CHIP_ID: | ||
3357 | /* read PMU chipcontrol register 3 */ | ||
3358 | addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr); | ||
3359 | brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL); | ||
3360 | addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data); | ||
3361 | reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL); | ||
3362 | return (reg & pmu_cc3_mask) != 0; | ||
3363 | default: | ||
3364 | addr = CORE_CC_REG(bus->ci->c_inf[0].base, pmucapabilities_ext); | ||
3365 | reg = brcmf_sdiod_regrl(bus->sdiodev, addr, &err); | ||
3366 | if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) | ||
3367 | return false; | ||
3368 | |||
3369 | addr = CORE_CC_REG(bus->ci->c_inf[0].base, retention_ctl); | ||
3370 | reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL); | ||
3371 | return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | | ||
3372 | PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; | ||
3373 | } | ||
3374 | } | ||
3375 | |||
3376 | static void brcmf_sdio_sr_init(struct brcmf_sdio *bus) | 3365 | static void brcmf_sdio_sr_init(struct brcmf_sdio *bus) |
3377 | { | 3366 | { |
3378 | int err = 0; | 3367 | int err = 0; |
@@ -3424,7 +3413,7 @@ static int brcmf_sdio_kso_init(struct brcmf_sdio *bus) | |||
3424 | brcmf_dbg(TRACE, "Enter\n"); | 3413 | brcmf_dbg(TRACE, "Enter\n"); |
3425 | 3414 | ||
3426 | /* KSO bit added in SDIO core rev 12 */ | 3415 | /* KSO bit added in SDIO core rev 12 */ |
3427 | if (bus->ci->c_inf[1].rev < 12) | 3416 | if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) |
3428 | return 0; | 3417 | return 0; |
3429 | 3418 | ||
3430 | val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err); | 3419 | val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err); |
@@ -3455,15 +3444,13 @@ static int brcmf_sdio_bus_preinit(struct device *dev) | |||
3455 | struct brcmf_sdio *bus = sdiodev->bus; | 3444 | struct brcmf_sdio *bus = sdiodev->bus; |
3456 | uint pad_size; | 3445 | uint pad_size; |
3457 | u32 value; | 3446 | u32 value; |
3458 | u8 idx; | ||
3459 | int err; | 3447 | int err; |
3460 | 3448 | ||
3461 | /* the commands below use the terms tx and rx from | 3449 | /* the commands below use the terms tx and rx from |
3462 | * a device perspective, ie. bus:txglom affects the | 3450 | * a device perspective, ie. bus:txglom affects the |
3463 | * bus transfers from device to host. | 3451 | * bus transfers from device to host. |
3464 | */ | 3452 | */ |
3465 | idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); | 3453 | if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) { |
3466 | if (bus->ci->c_inf[idx].rev < 12) { | ||
3467 | /* for sdio core rev < 12, disable txgloming */ | 3454 | /* for sdio core rev < 12, disable txgloming */ |
3468 | value = 0; | 3455 | value = 0; |
3469 | err = brcmf_iovar_data_set(dev, "bus:txglom", &value, | 3456 | err = brcmf_iovar_data_set(dev, "bus:txglom", &value, |
@@ -3570,7 +3557,7 @@ static int brcmf_sdio_bus_init(struct device *dev) | |||
3570 | ret = -ENODEV; | 3557 | ret = -ENODEV; |
3571 | } | 3558 | } |
3572 | 3559 | ||
3573 | if (brcmf_sdio_sr_capable(bus)) { | 3560 | if (brcmf_chip_sr_capable(bus->ci)) { |
3574 | brcmf_sdio_sr_init(bus); | 3561 | brcmf_sdio_sr_init(bus); |
3575 | } else { | 3562 | } else { |
3576 | /* Restore previous clock setting */ | 3563 | /* Restore previous clock setting */ |
@@ -3714,11 +3701,175 @@ static void brcmf_sdio_dataworker(struct work_struct *work) | |||
3714 | datawork); | 3701 | datawork); |
3715 | 3702 | ||
3716 | while (atomic_read(&bus->dpc_tskcnt)) { | 3703 | while (atomic_read(&bus->dpc_tskcnt)) { |
3704 | atomic_set(&bus->dpc_tskcnt, 0); | ||
3717 | brcmf_sdio_dpc(bus); | 3705 | brcmf_sdio_dpc(bus); |
3718 | atomic_dec(&bus->dpc_tskcnt); | ||
3719 | } | 3706 | } |
3720 | } | 3707 | } |
3721 | 3708 | ||
3709 | static void | ||
3710 | brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, | ||
3711 | struct brcmf_chip *ci, u32 drivestrength) | ||
3712 | { | ||
3713 | const struct sdiod_drive_str *str_tab = NULL; | ||
3714 | u32 str_mask; | ||
3715 | u32 str_shift; | ||
3716 | u32 base; | ||
3717 | u32 i; | ||
3718 | u32 drivestrength_sel = 0; | ||
3719 | u32 cc_data_temp; | ||
3720 | u32 addr; | ||
3721 | |||
3722 | if (!(ci->cc_caps & CC_CAP_PMU)) | ||
3723 | return; | ||
3724 | |||
3725 | switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { | ||
3726 | case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): | ||
3727 | str_tab = sdiod_drvstr_tab1_1v8; | ||
3728 | str_mask = 0x00003800; | ||
3729 | str_shift = 11; | ||
3730 | break; | ||
3731 | case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): | ||
3732 | str_tab = sdiod_drvstr_tab6_1v8; | ||
3733 | str_mask = 0x00001800; | ||
3734 | str_shift = 11; | ||
3735 | break; | ||
3736 | case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): | ||
3737 | /* note: 43143 does not support tristate */ | ||
3738 | i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1; | ||
3739 | if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) { | ||
3740 | str_tab = sdiod_drvstr_tab2_3v3; | ||
3741 | str_mask = 0x00000007; | ||
3742 | str_shift = 0; | ||
3743 | } else | ||
3744 | brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n", | ||
3745 | ci->name, drivestrength); | ||
3746 | break; | ||
3747 | case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): | ||
3748 | str_tab = sdiod_drive_strength_tab5_1v8; | ||
3749 | str_mask = 0x00003800; | ||
3750 | str_shift = 11; | ||
3751 | break; | ||
3752 | default: | ||
3753 | brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", | ||
3754 | ci->name, ci->chiprev, ci->pmurev); | ||
3755 | break; | ||
3756 | } | ||
3757 | |||
3758 | if (str_tab != NULL) { | ||
3759 | for (i = 0; str_tab[i].strength != 0; i++) { | ||
3760 | if (drivestrength >= str_tab[i].strength) { | ||
3761 | drivestrength_sel = str_tab[i].sel; | ||
3762 | break; | ||
3763 | } | ||
3764 | } | ||
3765 | base = brcmf_chip_get_chipcommon(ci)->base; | ||
3766 | addr = CORE_CC_REG(base, chipcontrol_addr); | ||
3767 | brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); | ||
3768 | cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); | ||
3769 | cc_data_temp &= ~str_mask; | ||
3770 | drivestrength_sel <<= str_shift; | ||
3771 | cc_data_temp |= drivestrength_sel; | ||
3772 | brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL); | ||
3773 | |||
3774 | brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n", | ||
3775 | str_tab[i].strength, drivestrength, cc_data_temp); | ||
3776 | } | ||
3777 | } | ||
3778 | |||
3779 | static int brcmf_sdio_buscoreprep(void *ctx) | ||
3780 | { | ||
3781 | struct brcmf_sdio_dev *sdiodev = ctx; | ||
3782 | int err = 0; | ||
3783 | u8 clkval, clkset; | ||
3784 | |||
3785 | /* Try forcing SDIO core to do ALPAvail request only */ | ||
3786 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; | ||
3787 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | ||
3788 | if (err) { | ||
3789 | brcmf_err("error writing for HT off\n"); | ||
3790 | return err; | ||
3791 | } | ||
3792 | |||
3793 | /* If register supported, wait for ALPAvail and then force ALP */ | ||
3794 | /* This may take up to 15 milliseconds */ | ||
3795 | clkval = brcmf_sdiod_regrb(sdiodev, | ||
3796 | SBSDIO_FUNC1_CHIPCLKCSR, NULL); | ||
3797 | |||
3798 | if ((clkval & ~SBSDIO_AVBITS) != clkset) { | ||
3799 | brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n", | ||
3800 | clkset, clkval); | ||
3801 | return -EACCES; | ||
3802 | } | ||
3803 | |||
3804 | SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev, | ||
3805 | SBSDIO_FUNC1_CHIPCLKCSR, NULL)), | ||
3806 | !SBSDIO_ALPAV(clkval)), | ||
3807 | PMU_MAX_TRANSITION_DLY); | ||
3808 | if (!SBSDIO_ALPAV(clkval)) { | ||
3809 | brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n", | ||
3810 | clkval); | ||
3811 | return -EBUSY; | ||
3812 | } | ||
3813 | |||
3814 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; | ||
3815 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | ||
3816 | udelay(65); | ||
3817 | |||
3818 | /* Also, disable the extra SDIO pull-ups */ | ||
3819 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); | ||
3820 | |||
3821 | return 0; | ||
3822 | } | ||
3823 | |||
3824 | static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip, | ||
3825 | u32 rstvec) | ||
3826 | { | ||
3827 | struct brcmf_sdio_dev *sdiodev = ctx; | ||
3828 | struct brcmf_core *core; | ||
3829 | u32 reg_addr; | ||
3830 | |||
3831 | /* clear all interrupts */ | ||
3832 | core = brcmf_chip_get_core(chip, BCMA_CORE_SDIO_DEV); | ||
3833 | reg_addr = core->base + offsetof(struct sdpcmd_regs, intstatus); | ||
3834 | brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); | ||
3835 | |||
3836 | if (rstvec) | ||
3837 | /* Write reset vector to address 0 */ | ||
3838 | brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec, | ||
3839 | sizeof(rstvec)); | ||
3840 | } | ||
3841 | |||
3842 | static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) | ||
3843 | { | ||
3844 | struct brcmf_sdio_dev *sdiodev = ctx; | ||
3845 | u32 val, rev; | ||
3846 | |||
3847 | val = brcmf_sdiod_regrl(sdiodev, addr, NULL); | ||
3848 | if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 && | ||
3849 | addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) { | ||
3850 | rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; | ||
3851 | if (rev >= 2) { | ||
3852 | val &= ~CID_ID_MASK; | ||
3853 | val |= BCM4339_CHIP_ID; | ||
3854 | } | ||
3855 | } | ||
3856 | return val; | ||
3857 | } | ||
3858 | |||
3859 | static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val) | ||
3860 | { | ||
3861 | struct brcmf_sdio_dev *sdiodev = ctx; | ||
3862 | |||
3863 | brcmf_sdiod_regwl(sdiodev, addr, val, NULL); | ||
3864 | } | ||
3865 | |||
3866 | static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { | ||
3867 | .prepare = brcmf_sdio_buscoreprep, | ||
3868 | .exit_dl = brcmf_sdio_buscore_exitdl, | ||
3869 | .read32 = brcmf_sdio_buscore_read32, | ||
3870 | .write32 = brcmf_sdio_buscore_write32, | ||
3871 | }; | ||
3872 | |||
3722 | static bool | 3873 | static bool |
3723 | brcmf_sdio_probe_attach(struct brcmf_sdio *bus) | 3874 | brcmf_sdio_probe_attach(struct brcmf_sdio *bus) |
3724 | { | 3875 | { |
@@ -3734,7 +3885,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) | |||
3734 | brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); | 3885 | brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); |
3735 | 3886 | ||
3736 | /* | 3887 | /* |
3737 | * Force PLL off until brcmf_sdio_chip_attach() | 3888 | * Force PLL off until brcmf_chip_attach() |
3738 | * programs PLL control regs | 3889 | * programs PLL control regs |
3739 | */ | 3890 | */ |
3740 | 3891 | ||
@@ -3755,8 +3906,10 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) | |||
3755 | */ | 3906 | */ |
3756 | brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN); | 3907 | brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN); |
3757 | 3908 | ||
3758 | if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci)) { | 3909 | bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops); |
3759 | brcmf_err("brcmf_sdio_chip_attach failed!\n"); | 3910 | if (IS_ERR(bus->ci)) { |
3911 | brcmf_err("brcmf_chip_attach failed!\n"); | ||
3912 | bus->ci = NULL; | ||
3760 | goto fail; | 3913 | goto fail; |
3761 | } | 3914 | } |
3762 | 3915 | ||
@@ -3769,7 +3922,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) | |||
3769 | drivestrength = bus->sdiodev->pdata->drive_strength; | 3922 | drivestrength = bus->sdiodev->pdata->drive_strength; |
3770 | else | 3923 | else |
3771 | drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; | 3924 | drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; |
3772 | brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength); | 3925 | brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength); |
3773 | 3926 | ||
3774 | /* Get info on the SOCRAM cores... */ | 3927 | /* Get info on the SOCRAM cores... */ |
3775 | bus->ramsize = bus->ci->ramsize; | 3928 | bus->ramsize = bus->ci->ramsize; |
@@ -3792,24 +3945,18 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) | |||
3792 | goto fail; | 3945 | goto fail; |
3793 | 3946 | ||
3794 | /* set PMUControl so a backplane reset does PMU state reload */ | 3947 | /* set PMUControl so a backplane reset does PMU state reload */ |
3795 | reg_addr = CORE_CC_REG(bus->ci->c_inf[0].base, | 3948 | reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base, |
3796 | pmucontrol); | 3949 | pmucontrol); |
3797 | reg_val = brcmf_sdiod_regrl(bus->sdiodev, | 3950 | reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); |
3798 | reg_addr, | ||
3799 | &err); | ||
3800 | if (err) | 3951 | if (err) |
3801 | goto fail; | 3952 | goto fail; |
3802 | 3953 | ||
3803 | reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT); | 3954 | reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT); |
3804 | 3955 | ||
3805 | brcmf_sdiod_regwl(bus->sdiodev, | 3956 | brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err); |
3806 | reg_addr, | ||
3807 | reg_val, | ||
3808 | &err); | ||
3809 | if (err) | 3957 | if (err) |
3810 | goto fail; | 3958 | goto fail; |
3811 | 3959 | ||
3812 | |||
3813 | sdio_release_host(bus->sdiodev->func[1]); | 3960 | sdio_release_host(bus->sdiodev->func[1]); |
3814 | 3961 | ||
3815 | brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); | 3962 | brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); |
@@ -3849,6 +3996,7 @@ brcmf_sdio_watchdog_thread(void *data) | |||
3849 | brcmf_sdio_bus_watchdog(bus); | 3996 | brcmf_sdio_bus_watchdog(bus); |
3850 | /* Count the tick for reference */ | 3997 | /* Count the tick for reference */ |
3851 | bus->sdcnt.tickcnt++; | 3998 | bus->sdcnt.tickcnt++; |
3999 | reinit_completion(&bus->watchdog_wait); | ||
3852 | } else | 4000 | } else |
3853 | break; | 4001 | break; |
3854 | } | 4002 | } |
@@ -3925,7 +4073,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) | |||
3925 | } | 4073 | } |
3926 | 4074 | ||
3927 | spin_lock_init(&bus->rxctl_lock); | 4075 | spin_lock_init(&bus->rxctl_lock); |
3928 | spin_lock_init(&bus->txqlock); | 4076 | spin_lock_init(&bus->txq_lock); |
4077 | sema_init(&bus->tx_seq_lock, 1); | ||
3929 | init_waitqueue_head(&bus->ctrl_wait); | 4078 | init_waitqueue_head(&bus->ctrl_wait); |
3930 | init_waitqueue_head(&bus->dcmd_resp_wait); | 4079 | init_waitqueue_head(&bus->dcmd_resp_wait); |
3931 | 4080 | ||
@@ -4024,14 +4173,14 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) | |||
4024 | /* De-register interrupt handler */ | 4173 | /* De-register interrupt handler */ |
4025 | brcmf_sdiod_intr_unregister(bus->sdiodev); | 4174 | brcmf_sdiod_intr_unregister(bus->sdiodev); |
4026 | 4175 | ||
4027 | cancel_work_sync(&bus->datawork); | ||
4028 | if (bus->brcmf_wq) | ||
4029 | destroy_workqueue(bus->brcmf_wq); | ||
4030 | |||
4031 | if (bus->sdiodev->bus_if->drvr) { | 4176 | if (bus->sdiodev->bus_if->drvr) { |
4032 | brcmf_detach(bus->sdiodev->dev); | 4177 | brcmf_detach(bus->sdiodev->dev); |
4033 | } | 4178 | } |
4034 | 4179 | ||
4180 | cancel_work_sync(&bus->datawork); | ||
4181 | if (bus->brcmf_wq) | ||
4182 | destroy_workqueue(bus->brcmf_wq); | ||
4183 | |||
4035 | if (bus->ci) { | 4184 | if (bus->ci) { |
4036 | if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { | 4185 | if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { |
4037 | sdio_claim_host(bus->sdiodev->func[1]); | 4186 | sdio_claim_host(bus->sdiodev->func[1]); |
@@ -4042,12 +4191,11 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) | |||
4042 | * all necessary cores. | 4191 | * all necessary cores. |
4043 | */ | 4192 | */ |
4044 | msleep(20); | 4193 | msleep(20); |
4045 | brcmf_sdio_chip_enter_download(bus->sdiodev, | 4194 | brcmf_chip_enter_download(bus->ci); |
4046 | bus->ci); | ||
4047 | brcmf_sdio_clkctl(bus, CLK_NONE, false); | 4195 | brcmf_sdio_clkctl(bus, CLK_NONE, false); |
4048 | sdio_release_host(bus->sdiodev->func[1]); | 4196 | sdio_release_host(bus->sdiodev->func[1]); |
4049 | } | 4197 | } |
4050 | brcmf_sdio_chip_detach(&bus->ci); | 4198 | brcmf_chip_detach(bus->ci); |
4051 | } | 4199 | } |
4052 | 4200 | ||
4053 | kfree(bus->rxbuf); | 4201 | kfree(bus->rxbuf); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 22adbe311d20..59a5af5bf994 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c | |||
@@ -124,7 +124,8 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) | |||
124 | } | 124 | } |
125 | 125 | ||
126 | static u32 | 126 | static u32 |
127 | brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen) | 127 | brcmf_create_iovar(char *name, const char *data, u32 datalen, |
128 | char *buf, u32 buflen) | ||
128 | { | 129 | { |
129 | u32 len; | 130 | u32 len; |
130 | 131 | ||
@@ -144,7 +145,7 @@ brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen) | |||
144 | 145 | ||
145 | 146 | ||
146 | s32 | 147 | s32 |
147 | brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, | 148 | brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, |
148 | u32 len) | 149 | u32 len) |
149 | { | 150 | { |
150 | struct brcmf_pub *drvr = ifp->drvr; | 151 | struct brcmf_pub *drvr = ifp->drvr; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index 77eae86e55c2..a30be683f4a1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h | |||
@@ -83,7 +83,7 @@ s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); | |||
83 | s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); | 83 | s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); |
84 | s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); | 84 | s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); |
85 | 85 | ||
86 | s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, | 86 | s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, |
87 | u32 len); | 87 | u32 len); |
88 | s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, | 88 | s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, |
89 | u32 len); | 89 | u32 len); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index af17a5bc8b83..614e4888504f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h | |||
@@ -48,6 +48,11 @@ | |||
48 | 48 | ||
49 | #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ | 49 | #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ |
50 | 50 | ||
51 | /* OBSS Coex Auto/On/Off */ | ||
52 | #define BRCMF_OBSS_COEX_AUTO (-1) | ||
53 | #define BRCMF_OBSS_COEX_OFF 0 | ||
54 | #define BRCMF_OBSS_COEX_ON 1 | ||
55 | |||
51 | enum brcmf_fil_p2p_if_types { | 56 | enum brcmf_fil_p2p_if_types { |
52 | BRCMF_FIL_P2P_IF_CLIENT, | 57 | BRCMF_FIL_P2P_IF_CLIENT, |
53 | BRCMF_FIL_P2P_IF_GO, | 58 | BRCMF_FIL_P2P_IF_GO, |
@@ -87,6 +92,11 @@ struct brcmf_fil_bss_enable_le { | |||
87 | __le32 enable; | 92 | __le32 enable; |
88 | }; | 93 | }; |
89 | 94 | ||
95 | struct brcmf_fil_bwcap_le { | ||
96 | __le32 band; | ||
97 | __le32 bw_cap; | ||
98 | }; | ||
99 | |||
90 | /** | 100 | /** |
91 | * struct tdls_iovar - common structure for tdls iovars. | 101 | * struct tdls_iovar - common structure for tdls iovars. |
92 | * | 102 | * |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index fc4f98b275d7..f3445ac627e4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |||
@@ -797,7 +797,8 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, | |||
797 | /* SOCIAL CHANNELS 1, 6, 11 */ | 797 | /* SOCIAL CHANNELS 1, 6, 11 */ |
798 | search_state = WL_P2P_DISC_ST_SEARCH; | 798 | search_state = WL_P2P_DISC_ST_SEARCH; |
799 | brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); | 799 | brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); |
800 | } else if (dev != NULL && vif->mode == WL_MODE_AP) { | 800 | } else if (dev != NULL && |
801 | vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { | ||
801 | /* If you are already a GO, then do SEARCH only */ | 802 | /* If you are already a GO, then do SEARCH only */ |
802 | brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n"); | 803 | brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n"); |
803 | search_state = WL_P2P_DISC_ST_SEARCH; | 804 | search_state = WL_P2P_DISC_ST_SEARCH; |
@@ -2256,7 +2257,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | |||
2256 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | 2257 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); |
2257 | struct brcmf_cfg80211_vif *vif; | 2258 | struct brcmf_cfg80211_vif *vif; |
2258 | enum brcmf_fil_p2p_if_types iftype; | 2259 | enum brcmf_fil_p2p_if_types iftype; |
2259 | enum wl_mode mode; | ||
2260 | int err; | 2260 | int err; |
2261 | 2261 | ||
2262 | if (brcmf_cfg80211_vif_event_armed(cfg)) | 2262 | if (brcmf_cfg80211_vif_event_armed(cfg)) |
@@ -2267,11 +2267,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | |||
2267 | switch (type) { | 2267 | switch (type) { |
2268 | case NL80211_IFTYPE_P2P_CLIENT: | 2268 | case NL80211_IFTYPE_P2P_CLIENT: |
2269 | iftype = BRCMF_FIL_P2P_IF_CLIENT; | 2269 | iftype = BRCMF_FIL_P2P_IF_CLIENT; |
2270 | mode = WL_MODE_BSS; | ||
2271 | break; | 2270 | break; |
2272 | case NL80211_IFTYPE_P2P_GO: | 2271 | case NL80211_IFTYPE_P2P_GO: |
2273 | iftype = BRCMF_FIL_P2P_IF_GO; | 2272 | iftype = BRCMF_FIL_P2P_IF_GO; |
2274 | mode = WL_MODE_AP; | ||
2275 | break; | 2273 | break; |
2276 | case NL80211_IFTYPE_P2P_DEVICE: | 2274 | case NL80211_IFTYPE_P2P_DEVICE: |
2277 | return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy, | 2275 | return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy, |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c deleted file mode 100644 index 82bf3c5d3cdc..000000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ /dev/null | |||
@@ -1,972 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 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 interface chip backplane handle functions ***** */ | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/mmc/card.h> | ||
21 | #include <linux/mmc/sdio_func.h> | ||
22 | #include <linux/mmc/sdio_ids.h> | ||
23 | #include <linux/ssb/ssb_regs.h> | ||
24 | #include <linux/bcma/bcma.h> | ||
25 | |||
26 | #include <chipcommon.h> | ||
27 | #include <brcm_hw_ids.h> | ||
28 | #include <brcmu_wifi.h> | ||
29 | #include <brcmu_utils.h> | ||
30 | #include <soc.h> | ||
31 | #include "dhd_dbg.h" | ||
32 | #include "sdio_host.h" | ||
33 | #include "sdio_chip.h" | ||
34 | |||
35 | /* chip core base & ramsize */ | ||
36 | /* bcm4329 */ | ||
37 | /* SDIO device core, ID 0x829 */ | ||
38 | #define BCM4329_CORE_BUS_BASE 0x18011000 | ||
39 | /* internal memory core, ID 0x80e */ | ||
40 | #define BCM4329_CORE_SOCRAM_BASE 0x18003000 | ||
41 | /* ARM Cortex M3 core, ID 0x82a */ | ||
42 | #define BCM4329_CORE_ARM_BASE 0x18002000 | ||
43 | #define BCM4329_RAMSIZE 0x48000 | ||
44 | |||
45 | /* bcm43143 */ | ||
46 | /* SDIO device core */ | ||
47 | #define BCM43143_CORE_BUS_BASE 0x18002000 | ||
48 | /* internal memory core */ | ||
49 | #define BCM43143_CORE_SOCRAM_BASE 0x18004000 | ||
50 | /* ARM Cortex M3 core, ID 0x82a */ | ||
51 | #define BCM43143_CORE_ARM_BASE 0x18003000 | ||
52 | #define BCM43143_RAMSIZE 0x70000 | ||
53 | |||
54 | /* All D11 cores, ID 0x812 */ | ||
55 | #define BCM43xx_CORE_D11_BASE 0x18001000 | ||
56 | |||
57 | #define SBCOREREV(sbidh) \ | ||
58 | ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ | ||
59 | ((sbidh) & SSB_IDHIGH_RCLO)) | ||
60 | |||
61 | /* SOC Interconnect types (aka chip types) */ | ||
62 | #define SOCI_SB 0 | ||
63 | #define SOCI_AI 1 | ||
64 | |||
65 | /* EROM CompIdentB */ | ||
66 | #define CIB_REV_MASK 0xff000000 | ||
67 | #define CIB_REV_SHIFT 24 | ||
68 | |||
69 | /* ARM CR4 core specific control flag bits */ | ||
70 | #define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020 | ||
71 | |||
72 | /* D11 core specific control flag bits */ | ||
73 | #define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004 | ||
74 | #define D11_BCMA_IOCTL_PHYRESET 0x0008 | ||
75 | |||
76 | #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) | ||
77 | /* SDIO Pad drive strength to select value mappings */ | ||
78 | struct sdiod_drive_str { | ||
79 | u8 strength; /* Pad Drive Strength in mA */ | ||
80 | u8 sel; /* Chip-specific select value */ | ||
81 | }; | ||
82 | /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */ | ||
83 | static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = { | ||
84 | {32, 0x6}, | ||
85 | {26, 0x7}, | ||
86 | {22, 0x4}, | ||
87 | {16, 0x5}, | ||
88 | {12, 0x2}, | ||
89 | {8, 0x3}, | ||
90 | {4, 0x0}, | ||
91 | {0, 0x1} | ||
92 | }; | ||
93 | |||
94 | /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ | ||
95 | static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = { | ||
96 | {6, 0x7}, | ||
97 | {5, 0x6}, | ||
98 | {4, 0x5}, | ||
99 | {3, 0x4}, | ||
100 | {2, 0x2}, | ||
101 | {1, 0x1}, | ||
102 | {0, 0x0} | ||
103 | }; | ||
104 | |||
105 | /* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ | ||
106 | static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = { | ||
107 | {3, 0x3}, | ||
108 | {2, 0x2}, | ||
109 | {1, 0x1}, | ||
110 | {0, 0x0} }; | ||
111 | |||
112 | /* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */ | ||
113 | static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { | ||
114 | {16, 0x7}, | ||
115 | {12, 0x5}, | ||
116 | {8, 0x3}, | ||
117 | {4, 0x1} | ||
118 | }; | ||
119 | |||
120 | u8 | ||
121 | brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid) | ||
122 | { | ||
123 | u8 idx; | ||
124 | |||
125 | for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++) | ||
126 | if (coreid == ci->c_inf[idx].id) | ||
127 | return idx; | ||
128 | |||
129 | return BRCMF_MAX_CORENUM; | ||
130 | } | ||
131 | |||
132 | static u32 | ||
133 | brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev, | ||
134 | struct brcmf_chip *ci, u16 coreid) | ||
135 | { | ||
136 | u32 regdata; | ||
137 | u8 idx; | ||
138 | |||
139 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
140 | |||
141 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
142 | CORE_SB(ci->c_inf[idx].base, sbidhigh), | ||
143 | NULL); | ||
144 | return SBCOREREV(regdata); | ||
145 | } | ||
146 | |||
147 | static u32 | ||
148 | brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev, | ||
149 | struct brcmf_chip *ci, u16 coreid) | ||
150 | { | ||
151 | u8 idx; | ||
152 | |||
153 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
154 | |||
155 | return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT; | ||
156 | } | ||
157 | |||
158 | static bool | ||
159 | brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev, | ||
160 | struct brcmf_chip *ci, u16 coreid) | ||
161 | { | ||
162 | u32 regdata; | ||
163 | u8 idx; | ||
164 | |||
165 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
166 | if (idx == BRCMF_MAX_CORENUM) | ||
167 | return false; | ||
168 | |||
169 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
170 | CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
171 | NULL); | ||
172 | regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | | ||
173 | SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); | ||
174 | return (SSB_TMSLOW_CLOCK == regdata); | ||
175 | } | ||
176 | |||
177 | static bool | ||
178 | brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev, | ||
179 | struct brcmf_chip *ci, u16 coreid) | ||
180 | { | ||
181 | u32 regdata; | ||
182 | u8 idx; | ||
183 | bool ret; | ||
184 | |||
185 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
186 | if (idx == BRCMF_MAX_CORENUM) | ||
187 | return false; | ||
188 | |||
189 | regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, | ||
190 | NULL); | ||
191 | ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; | ||
192 | |||
193 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
194 | ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, | ||
195 | NULL); | ||
196 | ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); | ||
197 | |||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static void | ||
202 | brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev, | ||
203 | struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, | ||
204 | u32 in_resetbits) | ||
205 | { | ||
206 | u32 regdata, base; | ||
207 | u8 idx; | ||
208 | |||
209 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
210 | base = ci->c_inf[idx].base; | ||
211 | |||
212 | regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); | ||
213 | if (regdata & SSB_TMSLOW_RESET) | ||
214 | return; | ||
215 | |||
216 | regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); | ||
217 | if ((regdata & SSB_TMSLOW_CLOCK) != 0) { | ||
218 | /* | ||
219 | * set target reject and spin until busy is clear | ||
220 | * (preserve core-specific bits) | ||
221 | */ | ||
222 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
223 | CORE_SB(base, sbtmstatelow), NULL); | ||
224 | brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow), | ||
225 | regdata | SSB_TMSLOW_REJECT, NULL); | ||
226 | |||
227 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
228 | CORE_SB(base, sbtmstatelow), NULL); | ||
229 | udelay(1); | ||
230 | SPINWAIT((brcmf_sdiod_regrl(sdiodev, | ||
231 | CORE_SB(base, sbtmstatehigh), | ||
232 | NULL) & | ||
233 | SSB_TMSHIGH_BUSY), 100000); | ||
234 | |||
235 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
236 | CORE_SB(base, sbtmstatehigh), | ||
237 | NULL); | ||
238 | if (regdata & SSB_TMSHIGH_BUSY) | ||
239 | brcmf_err("core state still busy\n"); | ||
240 | |||
241 | regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow), | ||
242 | NULL); | ||
243 | if (regdata & SSB_IDLOW_INITIATOR) { | ||
244 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
245 | CORE_SB(base, sbimstate), | ||
246 | NULL); | ||
247 | regdata |= SSB_IMSTATE_REJECT; | ||
248 | brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate), | ||
249 | regdata, NULL); | ||
250 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
251 | CORE_SB(base, sbimstate), | ||
252 | NULL); | ||
253 | udelay(1); | ||
254 | SPINWAIT((brcmf_sdiod_regrl(sdiodev, | ||
255 | CORE_SB(base, sbimstate), | ||
256 | NULL) & | ||
257 | SSB_IMSTATE_BUSY), 100000); | ||
258 | } | ||
259 | |||
260 | /* set reset and reject while enabling the clocks */ | ||
261 | regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | | ||
262 | SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; | ||
263 | brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow), | ||
264 | regdata, NULL); | ||
265 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
266 | CORE_SB(base, sbtmstatelow), NULL); | ||
267 | udelay(10); | ||
268 | |||
269 | /* clear the initiator reject bit */ | ||
270 | regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow), | ||
271 | NULL); | ||
272 | if (regdata & SSB_IDLOW_INITIATOR) { | ||
273 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
274 | CORE_SB(base, sbimstate), | ||
275 | NULL); | ||
276 | regdata &= ~SSB_IMSTATE_REJECT; | ||
277 | brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate), | ||
278 | regdata, NULL); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /* leave reset and reject asserted */ | ||
283 | brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow), | ||
284 | (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL); | ||
285 | udelay(1); | ||
286 | } | ||
287 | |||
288 | static void | ||
289 | brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev, | ||
290 | struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, | ||
291 | u32 in_resetbits) | ||
292 | { | ||
293 | u8 idx; | ||
294 | u32 regdata; | ||
295 | u32 wrapbase; | ||
296 | |||
297 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
298 | if (idx == BRCMF_MAX_CORENUM) | ||
299 | return; | ||
300 | |||
301 | wrapbase = ci->c_inf[idx].wrapbase; | ||
302 | |||
303 | /* if core is already in reset, just return */ | ||
304 | regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL); | ||
305 | if ((regdata & BCMA_RESET_CTL_RESET) != 0) | ||
306 | return; | ||
307 | |||
308 | /* configure reset */ | ||
309 | brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits | | ||
310 | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL); | ||
311 | regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL); | ||
312 | |||
313 | /* put in reset */ | ||
314 | brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, | ||
315 | BCMA_RESET_CTL_RESET, NULL); | ||
316 | usleep_range(10, 20); | ||
317 | |||
318 | /* wait till reset is 1 */ | ||
319 | SPINWAIT(brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) != | ||
320 | BCMA_RESET_CTL_RESET, 300); | ||
321 | |||
322 | /* post reset configure */ | ||
323 | brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits | | ||
324 | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL); | ||
325 | regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL); | ||
326 | } | ||
327 | |||
328 | static void | ||
329 | brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev, | ||
330 | struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, | ||
331 | u32 in_resetbits, u32 post_resetbits) | ||
332 | { | ||
333 | u32 regdata; | ||
334 | u8 idx; | ||
335 | |||
336 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
337 | if (idx == BRCMF_MAX_CORENUM) | ||
338 | return; | ||
339 | |||
340 | /* | ||
341 | * Must do the disable sequence first to work for | ||
342 | * arbitrary current core state. | ||
343 | */ | ||
344 | brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, pre_resetbits, | ||
345 | in_resetbits); | ||
346 | |||
347 | /* | ||
348 | * Now do the initialization sequence. | ||
349 | * set reset while enabling the clock and | ||
350 | * forcing them on throughout the core | ||
351 | */ | ||
352 | brcmf_sdiod_regwl(sdiodev, | ||
353 | CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
354 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET, | ||
355 | NULL); | ||
356 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
357 | CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
358 | NULL); | ||
359 | udelay(1); | ||
360 | |||
361 | /* clear any serror */ | ||
362 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
363 | CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), | ||
364 | NULL); | ||
365 | if (regdata & SSB_TMSHIGH_SERR) | ||
366 | brcmf_sdiod_regwl(sdiodev, | ||
367 | CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), | ||
368 | 0, NULL); | ||
369 | |||
370 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
371 | CORE_SB(ci->c_inf[idx].base, sbimstate), | ||
372 | NULL); | ||
373 | if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) | ||
374 | brcmf_sdiod_regwl(sdiodev, | ||
375 | CORE_SB(ci->c_inf[idx].base, sbimstate), | ||
376 | regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO), | ||
377 | NULL); | ||
378 | |||
379 | /* clear reset and allow it to propagate throughout the core */ | ||
380 | brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
381 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL); | ||
382 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
383 | CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
384 | NULL); | ||
385 | udelay(1); | ||
386 | |||
387 | /* leave clock enabled */ | ||
388 | brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
389 | SSB_TMSLOW_CLOCK, NULL); | ||
390 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
391 | CORE_SB(ci->c_inf[idx].base, sbtmstatelow), | ||
392 | NULL); | ||
393 | udelay(1); | ||
394 | } | ||
395 | |||
396 | static void | ||
397 | brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev, | ||
398 | struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, | ||
399 | u32 in_resetbits, u32 post_resetbits) | ||
400 | { | ||
401 | u8 idx; | ||
402 | u32 regdata; | ||
403 | u32 wrapbase; | ||
404 | |||
405 | idx = brcmf_sdio_chip_getinfidx(ci, coreid); | ||
406 | if (idx == BRCMF_MAX_CORENUM) | ||
407 | return; | ||
408 | |||
409 | wrapbase = ci->c_inf[idx].wrapbase; | ||
410 | |||
411 | /* must disable first to work for arbitrary current core state */ | ||
412 | brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, pre_resetbits, | ||
413 | in_resetbits); | ||
414 | |||
415 | while (brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) & | ||
416 | BCMA_RESET_CTL_RESET) { | ||
417 | brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, 0, NULL); | ||
418 | usleep_range(40, 60); | ||
419 | } | ||
420 | |||
421 | brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, post_resetbits | | ||
422 | BCMA_IOCTL_CLK, NULL); | ||
423 | regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL); | ||
424 | } | ||
425 | |||
426 | #ifdef DEBUG | ||
427 | /* safety check for chipinfo */ | ||
428 | static int brcmf_sdio_chip_cichk(struct brcmf_chip *ci) | ||
429 | { | ||
430 | u8 core_idx; | ||
431 | |||
432 | /* check RAM core presence for ARM CM3 core */ | ||
433 | core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); | ||
434 | if (BRCMF_MAX_CORENUM != core_idx) { | ||
435 | core_idx = brcmf_sdio_chip_getinfidx(ci, | ||
436 | BCMA_CORE_INTERNAL_MEM); | ||
437 | if (BRCMF_MAX_CORENUM == core_idx) { | ||
438 | brcmf_err("RAM core not provided with ARM CM3 core\n"); | ||
439 | return -ENODEV; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | /* check RAM base for ARM CR4 core */ | ||
444 | core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4); | ||
445 | if (BRCMF_MAX_CORENUM != core_idx) { | ||
446 | if (ci->rambase == 0) { | ||
447 | brcmf_err("RAM base not provided with ARM CR4 core\n"); | ||
448 | return -ENOMEM; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | #else /* DEBUG */ | ||
455 | static inline int brcmf_sdio_chip_cichk(struct brcmf_chip *ci) | ||
456 | { | ||
457 | return 0; | ||
458 | } | ||
459 | #endif | ||
460 | |||
461 | static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, | ||
462 | struct brcmf_chip *ci) | ||
463 | { | ||
464 | u32 regdata; | ||
465 | u32 socitype; | ||
466 | |||
467 | /* Get CC core rev | ||
468 | * Chipid is assume to be at offset 0 from SI_ENUM_BASE | ||
469 | * For different chiptypes or old sdio hosts w/o chipcommon, | ||
470 | * other ways of recognition should be added here. | ||
471 | */ | ||
472 | regdata = brcmf_sdiod_regrl(sdiodev, | ||
473 | CORE_CC_REG(SI_ENUM_BASE, chipid), | ||
474 | NULL); | ||
475 | ci->chip = regdata & CID_ID_MASK; | ||
476 | ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; | ||
477 | if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 && | ||
478 | ci->chiprev >= 2) | ||
479 | ci->chip = BCM4339_CHIP_ID; | ||
480 | socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; | ||
481 | |||
482 | brcmf_dbg(INFO, "found %s chip: id=0x%x, rev=%d\n", | ||
483 | socitype == SOCI_SB ? "SB" : "AXI", ci->chip, ci->chiprev); | ||
484 | |||
485 | if (socitype == SOCI_SB) { | ||
486 | if (ci->chip != BCM4329_CHIP_ID) { | ||
487 | brcmf_err("SB chip is not supported\n"); | ||
488 | return -ENODEV; | ||
489 | } | ||
490 | ci->iscoreup = brcmf_sdio_sb_iscoreup; | ||
491 | ci->corerev = brcmf_sdio_sb_corerev; | ||
492 | ci->coredisable = brcmf_sdio_sb_coredisable; | ||
493 | ci->resetcore = brcmf_sdio_sb_resetcore; | ||
494 | |||
495 | ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON; | ||
496 | ci->c_inf[0].base = SI_ENUM_BASE; | ||
497 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
498 | ci->c_inf[1].base = BCM4329_CORE_BUS_BASE; | ||
499 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | ||
500 | ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE; | ||
501 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | ||
502 | ci->c_inf[3].base = BCM4329_CORE_ARM_BASE; | ||
503 | ci->c_inf[4].id = BCMA_CORE_80211; | ||
504 | ci->c_inf[4].base = BCM43xx_CORE_D11_BASE; | ||
505 | ci->ramsize = BCM4329_RAMSIZE; | ||
506 | } else if (socitype == SOCI_AI) { | ||
507 | ci->iscoreup = brcmf_sdio_ai_iscoreup; | ||
508 | ci->corerev = brcmf_sdio_ai_corerev; | ||
509 | ci->coredisable = brcmf_sdio_ai_coredisable; | ||
510 | ci->resetcore = brcmf_sdio_ai_resetcore; | ||
511 | |||
512 | ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON; | ||
513 | ci->c_inf[0].base = SI_ENUM_BASE; | ||
514 | |||
515 | /* Address of cores for new chips should be added here */ | ||
516 | switch (ci->chip) { | ||
517 | case BCM43143_CHIP_ID: | ||
518 | ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000; | ||
519 | ci->c_inf[0].cib = 0x2b000000; | ||
520 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
521 | ci->c_inf[1].base = BCM43143_CORE_BUS_BASE; | ||
522 | ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000; | ||
523 | ci->c_inf[1].cib = 0x18000000; | ||
524 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | ||
525 | ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE; | ||
526 | ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000; | ||
527 | ci->c_inf[2].cib = 0x14000000; | ||
528 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | ||
529 | ci->c_inf[3].base = BCM43143_CORE_ARM_BASE; | ||
530 | ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000; | ||
531 | ci->c_inf[3].cib = 0x07000000; | ||
532 | ci->c_inf[4].id = BCMA_CORE_80211; | ||
533 | ci->c_inf[4].base = BCM43xx_CORE_D11_BASE; | ||
534 | ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000; | ||
535 | ci->ramsize = BCM43143_RAMSIZE; | ||
536 | break; | ||
537 | case BCM43241_CHIP_ID: | ||
538 | ci->c_inf[0].wrapbase = 0x18100000; | ||
539 | ci->c_inf[0].cib = 0x2a084411; | ||
540 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
541 | ci->c_inf[1].base = 0x18002000; | ||
542 | ci->c_inf[1].wrapbase = 0x18102000; | ||
543 | ci->c_inf[1].cib = 0x0e004211; | ||
544 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | ||
545 | ci->c_inf[2].base = 0x18004000; | ||
546 | ci->c_inf[2].wrapbase = 0x18104000; | ||
547 | ci->c_inf[2].cib = 0x14080401; | ||
548 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | ||
549 | ci->c_inf[3].base = 0x18003000; | ||
550 | ci->c_inf[3].wrapbase = 0x18103000; | ||
551 | ci->c_inf[3].cib = 0x07004211; | ||
552 | ci->c_inf[4].id = BCMA_CORE_80211; | ||
553 | ci->c_inf[4].base = BCM43xx_CORE_D11_BASE; | ||
554 | ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000; | ||
555 | ci->ramsize = 0x90000; | ||
556 | break; | ||
557 | case BCM4330_CHIP_ID: | ||
558 | ci->c_inf[0].wrapbase = 0x18100000; | ||
559 | ci->c_inf[0].cib = 0x27004211; | ||
560 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
561 | ci->c_inf[1].base = 0x18002000; | ||
562 | ci->c_inf[1].wrapbase = 0x18102000; | ||
563 | ci->c_inf[1].cib = 0x07004211; | ||
564 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | ||
565 | ci->c_inf[2].base = 0x18004000; | ||
566 | ci->c_inf[2].wrapbase = 0x18104000; | ||
567 | ci->c_inf[2].cib = 0x0d080401; | ||
568 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | ||
569 | ci->c_inf[3].base = 0x18003000; | ||
570 | ci->c_inf[3].wrapbase = 0x18103000; | ||
571 | ci->c_inf[3].cib = 0x03004211; | ||
572 | ci->c_inf[4].id = BCMA_CORE_80211; | ||
573 | ci->c_inf[4].base = BCM43xx_CORE_D11_BASE; | ||
574 | ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000; | ||
575 | ci->ramsize = 0x48000; | ||
576 | break; | ||
577 | case BCM4334_CHIP_ID: | ||
578 | ci->c_inf[0].wrapbase = 0x18100000; | ||
579 | ci->c_inf[0].cib = 0x29004211; | ||
580 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
581 | ci->c_inf[1].base = 0x18002000; | ||
582 | ci->c_inf[1].wrapbase = 0x18102000; | ||
583 | ci->c_inf[1].cib = 0x0d004211; | ||
584 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | ||
585 | ci->c_inf[2].base = 0x18004000; | ||
586 | ci->c_inf[2].wrapbase = 0x18104000; | ||
587 | ci->c_inf[2].cib = 0x13080401; | ||
588 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | ||
589 | ci->c_inf[3].base = 0x18003000; | ||
590 | ci->c_inf[3].wrapbase = 0x18103000; | ||
591 | ci->c_inf[3].cib = 0x07004211; | ||
592 | ci->c_inf[4].id = BCMA_CORE_80211; | ||
593 | ci->c_inf[4].base = BCM43xx_CORE_D11_BASE; | ||
594 | ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000; | ||
595 | ci->ramsize = 0x80000; | ||
596 | break; | ||
597 | case BCM4335_CHIP_ID: | ||
598 | ci->c_inf[0].wrapbase = 0x18100000; | ||
599 | ci->c_inf[0].cib = 0x2b084411; | ||
600 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
601 | ci->c_inf[1].base = 0x18005000; | ||
602 | ci->c_inf[1].wrapbase = 0x18105000; | ||
603 | ci->c_inf[1].cib = 0x0f004211; | ||
604 | ci->c_inf[2].id = BCMA_CORE_ARM_CR4; | ||
605 | ci->c_inf[2].base = 0x18002000; | ||
606 | ci->c_inf[2].wrapbase = 0x18102000; | ||
607 | ci->c_inf[2].cib = 0x01084411; | ||
608 | ci->c_inf[3].id = BCMA_CORE_80211; | ||
609 | ci->c_inf[3].base = BCM43xx_CORE_D11_BASE; | ||
610 | ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000; | ||
611 | ci->ramsize = 0xc0000; | ||
612 | ci->rambase = 0x180000; | ||
613 | break; | ||
614 | case BCM43362_CHIP_ID: | ||
615 | ci->c_inf[0].wrapbase = 0x18100000; | ||
616 | ci->c_inf[0].cib = 0x27004211; | ||
617 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
618 | ci->c_inf[1].base = 0x18002000; | ||
619 | ci->c_inf[1].wrapbase = 0x18102000; | ||
620 | ci->c_inf[1].cib = 0x0a004211; | ||
621 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | ||
622 | ci->c_inf[2].base = 0x18004000; | ||
623 | ci->c_inf[2].wrapbase = 0x18104000; | ||
624 | ci->c_inf[2].cib = 0x08080401; | ||
625 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | ||
626 | ci->c_inf[3].base = 0x18003000; | ||
627 | ci->c_inf[3].wrapbase = 0x18103000; | ||
628 | ci->c_inf[3].cib = 0x03004211; | ||
629 | ci->c_inf[4].id = BCMA_CORE_80211; | ||
630 | ci->c_inf[4].base = BCM43xx_CORE_D11_BASE; | ||
631 | ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000; | ||
632 | ci->ramsize = 0x3C000; | ||
633 | break; | ||
634 | case BCM4339_CHIP_ID: | ||
635 | ci->c_inf[0].wrapbase = 0x18100000; | ||
636 | ci->c_inf[0].cib = 0x2e084411; | ||
637 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; | ||
638 | ci->c_inf[1].base = 0x18005000; | ||
639 | ci->c_inf[1].wrapbase = 0x18105000; | ||
640 | ci->c_inf[1].cib = 0x15004211; | ||
641 | ci->c_inf[2].id = BCMA_CORE_ARM_CR4; | ||
642 | ci->c_inf[2].base = 0x18002000; | ||
643 | ci->c_inf[2].wrapbase = 0x18102000; | ||
644 | ci->c_inf[2].cib = 0x04084411; | ||
645 | ci->c_inf[3].id = BCMA_CORE_80211; | ||
646 | ci->c_inf[3].base = BCM43xx_CORE_D11_BASE; | ||
647 | ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000; | ||
648 | ci->ramsize = 0xc0000; | ||
649 | ci->rambase = 0x180000; | ||
650 | break; | ||
651 | default: | ||
652 | brcmf_err("AXI chip is not supported\n"); | ||
653 | return -ENODEV; | ||
654 | } | ||
655 | } else { | ||
656 | brcmf_err("chip backplane type %u is not supported\n", | ||
657 | socitype); | ||
658 | return -ENODEV; | ||
659 | } | ||
660 | |||
661 | return brcmf_sdio_chip_cichk(ci); | ||
662 | } | ||
663 | |||
664 | static int | ||
665 | brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) | ||
666 | { | ||
667 | int err = 0; | ||
668 | u8 clkval, clkset; | ||
669 | |||
670 | /* Try forcing SDIO core to do ALPAvail request only */ | ||
671 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; | ||
672 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | ||
673 | if (err) { | ||
674 | brcmf_err("error writing for HT off\n"); | ||
675 | return err; | ||
676 | } | ||
677 | |||
678 | /* If register supported, wait for ALPAvail and then force ALP */ | ||
679 | /* This may take up to 15 milliseconds */ | ||
680 | clkval = brcmf_sdiod_regrb(sdiodev, | ||
681 | SBSDIO_FUNC1_CHIPCLKCSR, NULL); | ||
682 | |||
683 | if ((clkval & ~SBSDIO_AVBITS) != clkset) { | ||
684 | brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n", | ||
685 | clkset, clkval); | ||
686 | return -EACCES; | ||
687 | } | ||
688 | |||
689 | SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev, | ||
690 | SBSDIO_FUNC1_CHIPCLKCSR, NULL)), | ||
691 | !SBSDIO_ALPAV(clkval)), | ||
692 | PMU_MAX_TRANSITION_DLY); | ||
693 | if (!SBSDIO_ALPAV(clkval)) { | ||
694 | brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n", | ||
695 | clkval); | ||
696 | return -EBUSY; | ||
697 | } | ||
698 | |||
699 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; | ||
700 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | ||
701 | udelay(65); | ||
702 | |||
703 | /* Also, disable the extra SDIO pull-ups */ | ||
704 | brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static void | ||
710 | brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, | ||
711 | struct brcmf_chip *ci) | ||
712 | { | ||
713 | u32 base = ci->c_inf[0].base; | ||
714 | |||
715 | /* get chipcommon rev */ | ||
716 | ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id); | ||
717 | |||
718 | /* get chipcommon capabilites */ | ||
719 | ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev, | ||
720 | CORE_CC_REG(base, capabilities), | ||
721 | NULL); | ||
722 | |||
723 | /* get pmu caps & rev */ | ||
724 | if (ci->c_inf[0].caps & CC_CAP_PMU) { | ||
725 | ci->pmucaps = | ||
726 | brcmf_sdiod_regrl(sdiodev, | ||
727 | CORE_CC_REG(base, pmucapabilities), | ||
728 | NULL); | ||
729 | ci->pmurev = ci->pmucaps & PCAP_REV_MASK; | ||
730 | } | ||
731 | |||
732 | ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id); | ||
733 | |||
734 | brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", | ||
735 | ci->c_inf[0].rev, ci->pmurev, | ||
736 | ci->c_inf[1].rev, ci->c_inf[1].id); | ||
737 | |||
738 | /* | ||
739 | * Make sure any on-chip ARM is off (in case strapping is wrong), | ||
740 | * or downloaded code was already running. | ||
741 | */ | ||
742 | ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0); | ||
743 | } | ||
744 | |||
745 | int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, | ||
746 | struct brcmf_chip **ci_ptr) | ||
747 | { | ||
748 | int ret; | ||
749 | struct brcmf_chip *ci; | ||
750 | |||
751 | brcmf_dbg(TRACE, "Enter\n"); | ||
752 | |||
753 | ci = kzalloc(sizeof(*ci), GFP_ATOMIC); | ||
754 | if (!ci) | ||
755 | return -ENOMEM; | ||
756 | |||
757 | ret = brcmf_sdio_chip_buscoreprep(sdiodev); | ||
758 | if (ret != 0) | ||
759 | goto err; | ||
760 | |||
761 | ret = brcmf_sdio_chip_recognition(sdiodev, ci); | ||
762 | if (ret != 0) | ||
763 | goto err; | ||
764 | |||
765 | brcmf_sdio_chip_buscoresetup(sdiodev, ci); | ||
766 | |||
767 | brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup), | ||
768 | 0, NULL); | ||
769 | brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), | ||
770 | 0, NULL); | ||
771 | |||
772 | *ci_ptr = ci; | ||
773 | return 0; | ||
774 | |||
775 | err: | ||
776 | kfree(ci); | ||
777 | return ret; | ||
778 | } | ||
779 | |||
780 | void | ||
781 | brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr) | ||
782 | { | ||
783 | brcmf_dbg(TRACE, "Enter\n"); | ||
784 | |||
785 | kfree(*ci_ptr); | ||
786 | *ci_ptr = NULL; | ||
787 | } | ||
788 | |||
789 | static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len) | ||
790 | { | ||
791 | const char *fmt; | ||
792 | |||
793 | fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; | ||
794 | snprintf(buf, len, fmt, chipid); | ||
795 | return buf; | ||
796 | } | ||
797 | |||
798 | void | ||
799 | brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, | ||
800 | struct brcmf_chip *ci, u32 drivestrength) | ||
801 | { | ||
802 | const struct sdiod_drive_str *str_tab = NULL; | ||
803 | u32 str_mask; | ||
804 | u32 str_shift; | ||
805 | char chn[8]; | ||
806 | u32 base = ci->c_inf[0].base; | ||
807 | u32 i; | ||
808 | u32 drivestrength_sel = 0; | ||
809 | u32 cc_data_temp; | ||
810 | u32 addr; | ||
811 | |||
812 | if (!(ci->c_inf[0].caps & CC_CAP_PMU)) | ||
813 | return; | ||
814 | |||
815 | switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { | ||
816 | case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): | ||
817 | str_tab = sdiod_drvstr_tab1_1v8; | ||
818 | str_mask = 0x00003800; | ||
819 | str_shift = 11; | ||
820 | break; | ||
821 | case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): | ||
822 | str_tab = sdiod_drvstr_tab6_1v8; | ||
823 | str_mask = 0x00001800; | ||
824 | str_shift = 11; | ||
825 | break; | ||
826 | case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): | ||
827 | /* note: 43143 does not support tristate */ | ||
828 | i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1; | ||
829 | if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) { | ||
830 | str_tab = sdiod_drvstr_tab2_3v3; | ||
831 | str_mask = 0x00000007; | ||
832 | str_shift = 0; | ||
833 | } else | ||
834 | brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n", | ||
835 | brcmf_sdio_chip_name(ci->chip, chn, 8), | ||
836 | drivestrength); | ||
837 | break; | ||
838 | case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): | ||
839 | str_tab = sdiod_drive_strength_tab5_1v8; | ||
840 | str_mask = 0x00003800; | ||
841 | str_shift = 11; | ||
842 | break; | ||
843 | default: | ||
844 | brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", | ||
845 | brcmf_sdio_chip_name(ci->chip, chn, 8), | ||
846 | ci->chiprev, ci->pmurev); | ||
847 | break; | ||
848 | } | ||
849 | |||
850 | if (str_tab != NULL) { | ||
851 | for (i = 0; str_tab[i].strength != 0; i++) { | ||
852 | if (drivestrength >= str_tab[i].strength) { | ||
853 | drivestrength_sel = str_tab[i].sel; | ||
854 | break; | ||
855 | } | ||
856 | } | ||
857 | addr = CORE_CC_REG(base, chipcontrol_addr); | ||
858 | brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); | ||
859 | cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); | ||
860 | cc_data_temp &= ~str_mask; | ||
861 | drivestrength_sel <<= str_shift; | ||
862 | cc_data_temp |= drivestrength_sel; | ||
863 | brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL); | ||
864 | |||
865 | brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n", | ||
866 | str_tab[i].strength, drivestrength, cc_data_temp); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | static void | ||
871 | brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev, | ||
872 | struct brcmf_chip *ci) | ||
873 | { | ||
874 | ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0); | ||
875 | ci->resetcore(sdiodev, ci, BCMA_CORE_80211, | ||
876 | D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN, | ||
877 | D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN); | ||
878 | ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0, 0, 0); | ||
879 | } | ||
880 | |||
881 | static bool brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, | ||
882 | struct brcmf_chip *ci) | ||
883 | { | ||
884 | u8 core_idx; | ||
885 | u32 reg_addr; | ||
886 | |||
887 | if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) { | ||
888 | brcmf_err("SOCRAM core is down after reset?\n"); | ||
889 | return false; | ||
890 | } | ||
891 | |||
892 | /* clear all interrupts */ | ||
893 | core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV); | ||
894 | reg_addr = ci->c_inf[core_idx].base; | ||
895 | reg_addr += offsetof(struct sdpcmd_regs, intstatus); | ||
896 | brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); | ||
897 | |||
898 | ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0, 0); | ||
899 | |||
900 | return true; | ||
901 | } | ||
902 | |||
903 | static inline void | ||
904 | brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev, | ||
905 | struct brcmf_chip *ci) | ||
906 | { | ||
907 | u8 idx; | ||
908 | u32 regdata; | ||
909 | u32 wrapbase; | ||
910 | idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4); | ||
911 | |||
912 | if (idx == BRCMF_MAX_CORENUM) | ||
913 | return; | ||
914 | |||
915 | wrapbase = ci->c_inf[idx].wrapbase; | ||
916 | regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL); | ||
917 | regdata &= ARMCR4_BCMA_IOCTL_CPUHALT; | ||
918 | ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, regdata, | ||
919 | ARMCR4_BCMA_IOCTL_CPUHALT, ARMCR4_BCMA_IOCTL_CPUHALT); | ||
920 | ci->resetcore(sdiodev, ci, BCMA_CORE_80211, | ||
921 | D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN, | ||
922 | D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN); | ||
923 | } | ||
924 | |||
925 | static bool brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, | ||
926 | struct brcmf_chip *ci, u32 rstvec) | ||
927 | { | ||
928 | u8 core_idx; | ||
929 | u32 reg_addr; | ||
930 | |||
931 | /* clear all interrupts */ | ||
932 | core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV); | ||
933 | reg_addr = ci->c_inf[core_idx].base; | ||
934 | reg_addr += offsetof(struct sdpcmd_regs, intstatus); | ||
935 | brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); | ||
936 | |||
937 | /* Write reset vector to address 0 */ | ||
938 | brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec, | ||
939 | sizeof(rstvec)); | ||
940 | |||
941 | /* restore ARM */ | ||
942 | ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT, | ||
943 | 0, 0); | ||
944 | |||
945 | return true; | ||
946 | } | ||
947 | |||
948 | void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev, | ||
949 | struct brcmf_chip *ci) | ||
950 | { | ||
951 | u8 arm_core_idx; | ||
952 | |||
953 | arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); | ||
954 | if (BRCMF_MAX_CORENUM != arm_core_idx) { | ||
955 | brcmf_sdio_chip_cm3_enterdl(sdiodev, ci); | ||
956 | return; | ||
957 | } | ||
958 | |||
959 | brcmf_sdio_chip_cr4_enterdl(sdiodev, ci); | ||
960 | } | ||
961 | |||
962 | bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, | ||
963 | struct brcmf_chip *ci, u32 rstvec) | ||
964 | { | ||
965 | u8 arm_core_idx; | ||
966 | |||
967 | arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); | ||
968 | if (BRCMF_MAX_CORENUM != arm_core_idx) | ||
969 | return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci); | ||
970 | |||
971 | return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, rstvec); | ||
972 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h deleted file mode 100644 index fb0614329ede..000000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h +++ /dev/null | |||
@@ -1,231 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 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 | |||
17 | #ifndef _BRCMFMAC_SDIO_CHIP_H_ | ||
18 | #define _BRCMFMAC_SDIO_CHIP_H_ | ||
19 | |||
20 | /* | ||
21 | * Core reg address translation. | ||
22 | * Both macro's returns a 32 bits byte address on the backplane bus. | ||
23 | */ | ||
24 | #define CORE_CC_REG(base, field) \ | ||
25 | (base + offsetof(struct chipcregs, field)) | ||
26 | #define CORE_BUS_REG(base, field) \ | ||
27 | (base + offsetof(struct sdpcmd_regs, field)) | ||
28 | #define CORE_SB(base, field) \ | ||
29 | (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) | ||
30 | |||
31 | /* SDIO function 1 register CHIPCLKCSR */ | ||
32 | /* Force ALP request to backplane */ | ||
33 | #define SBSDIO_FORCE_ALP 0x01 | ||
34 | /* Force HT request to backplane */ | ||
35 | #define SBSDIO_FORCE_HT 0x02 | ||
36 | /* Force ILP request to backplane */ | ||
37 | #define SBSDIO_FORCE_ILP 0x04 | ||
38 | /* Make ALP ready (power up xtal) */ | ||
39 | #define SBSDIO_ALP_AVAIL_REQ 0x08 | ||
40 | /* Make HT ready (power up PLL) */ | ||
41 | #define SBSDIO_HT_AVAIL_REQ 0x10 | ||
42 | /* Squelch clock requests from HW */ | ||
43 | #define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 | ||
44 | /* Status: ALP is ready */ | ||
45 | #define SBSDIO_ALP_AVAIL 0x40 | ||
46 | /* Status: HT is ready */ | ||
47 | #define SBSDIO_HT_AVAIL 0x80 | ||
48 | #define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) | ||
49 | #define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) | ||
50 | #define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) | ||
51 | #define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) | ||
52 | #define SBSDIO_CLKAV(regval, alponly) \ | ||
53 | (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) | ||
54 | |||
55 | #define BRCMF_MAX_CORENUM 6 | ||
56 | |||
57 | struct brcmf_core { | ||
58 | u16 id; | ||
59 | u16 rev; | ||
60 | u32 base; | ||
61 | u32 wrapbase; | ||
62 | u32 caps; | ||
63 | u32 cib; | ||
64 | }; | ||
65 | |||
66 | struct brcmf_chip { | ||
67 | u32 chip; | ||
68 | u32 chiprev; | ||
69 | /* core info */ | ||
70 | /* always put chipcommon core at 0, bus core at 1 */ | ||
71 | struct brcmf_core c_inf[BRCMF_MAX_CORENUM]; | ||
72 | u32 pmurev; | ||
73 | u32 pmucaps; | ||
74 | u32 ramsize; | ||
75 | u32 rambase; | ||
76 | u32 rst_vec; /* reset vertor for ARM CR4 core */ | ||
77 | |||
78 | bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci, | ||
79 | u16 coreid); | ||
80 | u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci, | ||
81 | u16 coreid); | ||
82 | void (*coredisable)(struct brcmf_sdio_dev *sdiodev, | ||
83 | struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, | ||
84 | u32 in_resetbits); | ||
85 | void (*resetcore)(struct brcmf_sdio_dev *sdiodev, | ||
86 | struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits, | ||
87 | u32 in_resetbits, u32 post_resetbits); | ||
88 | }; | ||
89 | |||
90 | struct sbconfig { | ||
91 | u32 PAD[2]; | ||
92 | u32 sbipsflag; /* initiator port ocp slave flag */ | ||
93 | u32 PAD[3]; | ||
94 | u32 sbtpsflag; /* target port ocp slave flag */ | ||
95 | u32 PAD[11]; | ||
96 | u32 sbtmerrloga; /* (sonics >= 2.3) */ | ||
97 | u32 PAD; | ||
98 | u32 sbtmerrlog; /* (sonics >= 2.3) */ | ||
99 | u32 PAD[3]; | ||
100 | u32 sbadmatch3; /* address match3 */ | ||
101 | u32 PAD; | ||
102 | u32 sbadmatch2; /* address match2 */ | ||
103 | u32 PAD; | ||
104 | u32 sbadmatch1; /* address match1 */ | ||
105 | u32 PAD[7]; | ||
106 | u32 sbimstate; /* initiator agent state */ | ||
107 | u32 sbintvec; /* interrupt mask */ | ||
108 | u32 sbtmstatelow; /* target state */ | ||
109 | u32 sbtmstatehigh; /* target state */ | ||
110 | u32 sbbwa0; /* bandwidth allocation table0 */ | ||
111 | u32 PAD; | ||
112 | u32 sbimconfiglow; /* initiator configuration */ | ||
113 | u32 sbimconfighigh; /* initiator configuration */ | ||
114 | u32 sbadmatch0; /* address match0 */ | ||
115 | u32 PAD; | ||
116 | u32 sbtmconfiglow; /* target configuration */ | ||
117 | u32 sbtmconfighigh; /* target configuration */ | ||
118 | u32 sbbconfig; /* broadcast configuration */ | ||
119 | u32 PAD; | ||
120 | u32 sbbstate; /* broadcast state */ | ||
121 | u32 PAD[3]; | ||
122 | u32 sbactcnfg; /* activate configuration */ | ||
123 | u32 PAD[3]; | ||
124 | u32 sbflagst; /* current sbflags */ | ||
125 | u32 PAD[3]; | ||
126 | u32 sbidlow; /* identification */ | ||
127 | u32 sbidhigh; /* identification */ | ||
128 | }; | ||
129 | |||
130 | /* sdio core registers */ | ||
131 | struct sdpcmd_regs { | ||
132 | u32 corecontrol; /* 0x00, rev8 */ | ||
133 | u32 corestatus; /* rev8 */ | ||
134 | u32 PAD[1]; | ||
135 | u32 biststatus; /* rev8 */ | ||
136 | |||
137 | /* PCMCIA access */ | ||
138 | u16 pcmciamesportaladdr; /* 0x010, rev8 */ | ||
139 | u16 PAD[1]; | ||
140 | u16 pcmciamesportalmask; /* rev8 */ | ||
141 | u16 PAD[1]; | ||
142 | u16 pcmciawrframebc; /* rev8 */ | ||
143 | u16 PAD[1]; | ||
144 | u16 pcmciaunderflowtimer; /* rev8 */ | ||
145 | u16 PAD[1]; | ||
146 | |||
147 | /* interrupt */ | ||
148 | u32 intstatus; /* 0x020, rev8 */ | ||
149 | u32 hostintmask; /* rev8 */ | ||
150 | u32 intmask; /* rev8 */ | ||
151 | u32 sbintstatus; /* rev8 */ | ||
152 | u32 sbintmask; /* rev8 */ | ||
153 | u32 funcintmask; /* rev4 */ | ||
154 | u32 PAD[2]; | ||
155 | u32 tosbmailbox; /* 0x040, rev8 */ | ||
156 | u32 tohostmailbox; /* rev8 */ | ||
157 | u32 tosbmailboxdata; /* rev8 */ | ||
158 | u32 tohostmailboxdata; /* rev8 */ | ||
159 | |||
160 | /* synchronized access to registers in SDIO clock domain */ | ||
161 | u32 sdioaccess; /* 0x050, rev8 */ | ||
162 | u32 PAD[3]; | ||
163 | |||
164 | /* PCMCIA frame control */ | ||
165 | u8 pcmciaframectrl; /* 0x060, rev8 */ | ||
166 | u8 PAD[3]; | ||
167 | u8 pcmciawatermark; /* rev8 */ | ||
168 | u8 PAD[155]; | ||
169 | |||
170 | /* interrupt batching control */ | ||
171 | u32 intrcvlazy; /* 0x100, rev8 */ | ||
172 | u32 PAD[3]; | ||
173 | |||
174 | /* counters */ | ||
175 | u32 cmd52rd; /* 0x110, rev8 */ | ||
176 | u32 cmd52wr; /* rev8 */ | ||
177 | u32 cmd53rd; /* rev8 */ | ||
178 | u32 cmd53wr; /* rev8 */ | ||
179 | u32 abort; /* rev8 */ | ||
180 | u32 datacrcerror; /* rev8 */ | ||
181 | u32 rdoutofsync; /* rev8 */ | ||
182 | u32 wroutofsync; /* rev8 */ | ||
183 | u32 writebusy; /* rev8 */ | ||
184 | u32 readwait; /* rev8 */ | ||
185 | u32 readterm; /* rev8 */ | ||
186 | u32 writeterm; /* rev8 */ | ||
187 | u32 PAD[40]; | ||
188 | u32 clockctlstatus; /* rev8 */ | ||
189 | u32 PAD[7]; | ||
190 | |||
191 | u32 PAD[128]; /* DMA engines */ | ||
192 | |||
193 | /* SDIO/PCMCIA CIS region */ | ||
194 | char cis[512]; /* 0x400-0x5ff, rev6 */ | ||
195 | |||
196 | /* PCMCIA function control registers */ | ||
197 | char pcmciafcr[256]; /* 0x600-6ff, rev6 */ | ||
198 | u16 PAD[55]; | ||
199 | |||
200 | /* PCMCIA backplane access */ | ||
201 | u16 backplanecsr; /* 0x76E, rev6 */ | ||
202 | u16 backplaneaddr0; /* rev6 */ | ||
203 | u16 backplaneaddr1; /* rev6 */ | ||
204 | u16 backplaneaddr2; /* rev6 */ | ||
205 | u16 backplaneaddr3; /* rev6 */ | ||
206 | u16 backplanedata0; /* rev6 */ | ||
207 | u16 backplanedata1; /* rev6 */ | ||
208 | u16 backplanedata2; /* rev6 */ | ||
209 | u16 backplanedata3; /* rev6 */ | ||
210 | u16 PAD[31]; | ||
211 | |||
212 | /* sprom "size" & "blank" info */ | ||
213 | u16 spromstatus; /* 0x7BE, rev2 */ | ||
214 | u32 PAD[464]; | ||
215 | |||
216 | u16 PAD[0x80]; | ||
217 | }; | ||
218 | |||
219 | int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, | ||
220 | struct brcmf_chip **ci_ptr); | ||
221 | void brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr); | ||
222 | void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, | ||
223 | struct brcmf_chip *ci, | ||
224 | u32 drivestrength); | ||
225 | u8 brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid); | ||
226 | void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev, | ||
227 | struct brcmf_chip *ci); | ||
228 | bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, | ||
229 | struct brcmf_chip *ci, u32 rstvec); | ||
230 | |||
231 | #endif /* _BRCMFMAC_SDIO_CHIP_H_ */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 092e9c824992..3deab7959a0d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h | |||
@@ -180,6 +180,97 @@ struct brcmf_sdio_dev { | |||
180 | uint max_request_size; | 180 | uint max_request_size; |
181 | ushort max_segment_count; | 181 | ushort max_segment_count; |
182 | uint max_segment_size; | 182 | uint max_segment_size; |
183 | uint txglomsz; | ||
184 | struct sg_table sgtable; | ||
185 | }; | ||
186 | |||
187 | /* sdio core registers */ | ||
188 | struct sdpcmd_regs { | ||
189 | u32 corecontrol; /* 0x00, rev8 */ | ||
190 | u32 corestatus; /* rev8 */ | ||
191 | u32 PAD[1]; | ||
192 | u32 biststatus; /* rev8 */ | ||
193 | |||
194 | /* PCMCIA access */ | ||
195 | u16 pcmciamesportaladdr; /* 0x010, rev8 */ | ||
196 | u16 PAD[1]; | ||
197 | u16 pcmciamesportalmask; /* rev8 */ | ||
198 | u16 PAD[1]; | ||
199 | u16 pcmciawrframebc; /* rev8 */ | ||
200 | u16 PAD[1]; | ||
201 | u16 pcmciaunderflowtimer; /* rev8 */ | ||
202 | u16 PAD[1]; | ||
203 | |||
204 | /* interrupt */ | ||
205 | u32 intstatus; /* 0x020, rev8 */ | ||
206 | u32 hostintmask; /* rev8 */ | ||
207 | u32 intmask; /* rev8 */ | ||
208 | u32 sbintstatus; /* rev8 */ | ||
209 | u32 sbintmask; /* rev8 */ | ||
210 | u32 funcintmask; /* rev4 */ | ||
211 | u32 PAD[2]; | ||
212 | u32 tosbmailbox; /* 0x040, rev8 */ | ||
213 | u32 tohostmailbox; /* rev8 */ | ||
214 | u32 tosbmailboxdata; /* rev8 */ | ||
215 | u32 tohostmailboxdata; /* rev8 */ | ||
216 | |||
217 | /* synchronized access to registers in SDIO clock domain */ | ||
218 | u32 sdioaccess; /* 0x050, rev8 */ | ||
219 | u32 PAD[3]; | ||
220 | |||
221 | /* PCMCIA frame control */ | ||
222 | u8 pcmciaframectrl; /* 0x060, rev8 */ | ||
223 | u8 PAD[3]; | ||
224 | u8 pcmciawatermark; /* rev8 */ | ||
225 | u8 PAD[155]; | ||
226 | |||
227 | /* interrupt batching control */ | ||
228 | u32 intrcvlazy; /* 0x100, rev8 */ | ||
229 | u32 PAD[3]; | ||
230 | |||
231 | /* counters */ | ||
232 | u32 cmd52rd; /* 0x110, rev8 */ | ||
233 | u32 cmd52wr; /* rev8 */ | ||
234 | u32 cmd53rd; /* rev8 */ | ||
235 | u32 cmd53wr; /* rev8 */ | ||
236 | u32 abort; /* rev8 */ | ||
237 | u32 datacrcerror; /* rev8 */ | ||
238 | u32 rdoutofsync; /* rev8 */ | ||
239 | u32 wroutofsync; /* rev8 */ | ||
240 | u32 writebusy; /* rev8 */ | ||
241 | u32 readwait; /* rev8 */ | ||
242 | u32 readterm; /* rev8 */ | ||
243 | u32 writeterm; /* rev8 */ | ||
244 | u32 PAD[40]; | ||
245 | u32 clockctlstatus; /* rev8 */ | ||
246 | u32 PAD[7]; | ||
247 | |||
248 | u32 PAD[128]; /* DMA engines */ | ||
249 | |||
250 | /* SDIO/PCMCIA CIS region */ | ||
251 | char cis[512]; /* 0x400-0x5ff, rev6 */ | ||
252 | |||
253 | /* PCMCIA function control registers */ | ||
254 | char pcmciafcr[256]; /* 0x600-6ff, rev6 */ | ||
255 | u16 PAD[55]; | ||
256 | |||
257 | /* PCMCIA backplane access */ | ||
258 | u16 backplanecsr; /* 0x76E, rev6 */ | ||
259 | u16 backplaneaddr0; /* rev6 */ | ||
260 | u16 backplaneaddr1; /* rev6 */ | ||
261 | u16 backplaneaddr2; /* rev6 */ | ||
262 | u16 backplaneaddr3; /* rev6 */ | ||
263 | u16 backplanedata0; /* rev6 */ | ||
264 | u16 backplanedata1; /* rev6 */ | ||
265 | u16 backplanedata2; /* rev6 */ | ||
266 | u16 backplanedata3; /* rev6 */ | ||
267 | u16 PAD[31]; | ||
268 | |||
269 | /* sprom "size" & "blank" info */ | ||
270 | u16 spromstatus; /* 0x7BE, rev2 */ | ||
271 | u32 PAD[464]; | ||
272 | |||
273 | u16 PAD[0x80]; | ||
183 | }; | 274 | }; |
184 | 275 | ||
185 | /* Register/deregister interrupt handler. */ | 276 | /* Register/deregister interrupt handler. */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d7718a5fa2f0..e0e649aab8db 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/module.h> | ||
21 | #include <net/cfg80211.h> | 22 | #include <net/cfg80211.h> |
22 | #include <net/netlink.h> | 23 | #include <net/netlink.h> |
23 | 24 | ||
@@ -190,6 +191,7 @@ static struct ieee80211_supported_band __wl_band_2ghz = { | |||
190 | .n_channels = ARRAY_SIZE(__wl_2ghz_channels), | 191 | .n_channels = ARRAY_SIZE(__wl_2ghz_channels), |
191 | .bitrates = wl_g_rates, | 192 | .bitrates = wl_g_rates, |
192 | .n_bitrates = wl_g_rates_size, | 193 | .n_bitrates = wl_g_rates_size, |
194 | .ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true}, | ||
193 | }; | 195 | }; |
194 | 196 | ||
195 | static struct ieee80211_supported_band __wl_band_5ghz_a = { | 197 | static struct ieee80211_supported_band __wl_band_5ghz_a = { |
@@ -251,6 +253,10 @@ struct parsed_vndr_ies { | |||
251 | struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; | 253 | struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; |
252 | }; | 254 | }; |
253 | 255 | ||
256 | static int brcmf_roamoff; | ||
257 | module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR); | ||
258 | MODULE_PARM_DESC(roamoff, "do not use internal roaming engine"); | ||
259 | |||
254 | /* Quarter dBm units to mW | 260 | /* Quarter dBm units to mW |
255 | * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 | 261 | * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 |
256 | * Table is offset so the last entry is largest mW value that fits in | 262 | * Table is offset so the last entry is largest mW value that fits in |
@@ -351,13 +357,11 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, | |||
351 | * triples, returning a pointer to the substring whose first element | 357 | * triples, returning a pointer to the substring whose first element |
352 | * matches tag | 358 | * matches tag |
353 | */ | 359 | */ |
354 | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) | 360 | const struct brcmf_tlv * |
361 | brcmf_parse_tlvs(const void *buf, int buflen, uint key) | ||
355 | { | 362 | { |
356 | struct brcmf_tlv *elt; | 363 | const struct brcmf_tlv *elt = buf; |
357 | int totlen; | 364 | int totlen = buflen; |
358 | |||
359 | elt = (struct brcmf_tlv *)buf; | ||
360 | totlen = buflen; | ||
361 | 365 | ||
362 | /* find tagged parameter */ | 366 | /* find tagged parameter */ |
363 | while (totlen >= TLV_HDR_LEN) { | 367 | while (totlen >= TLV_HDR_LEN) { |
@@ -378,8 +382,8 @@ struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) | |||
378 | * not update the tlvs buffer pointer/length. | 382 | * not update the tlvs buffer pointer/length. |
379 | */ | 383 | */ |
380 | static bool | 384 | static bool |
381 | brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, | 385 | brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, |
382 | u8 *oui, u32 oui_len, u8 type) | 386 | const u8 *oui, u32 oui_len, u8 type) |
383 | { | 387 | { |
384 | /* If the contents match the OUI and the type */ | 388 | /* If the contents match the OUI and the type */ |
385 | if (ie[TLV_LEN_OFF] >= oui_len + 1 && | 389 | if (ie[TLV_LEN_OFF] >= oui_len + 1 && |
@@ -401,12 +405,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, | |||
401 | } | 405 | } |
402 | 406 | ||
403 | static struct brcmf_vs_tlv * | 407 | static struct brcmf_vs_tlv * |
404 | brcmf_find_wpaie(u8 *parse, u32 len) | 408 | brcmf_find_wpaie(const u8 *parse, u32 len) |
405 | { | 409 | { |
406 | struct brcmf_tlv *ie; | 410 | const struct brcmf_tlv *ie; |
407 | 411 | ||
408 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | 412 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { |
409 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | 413 | if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len, |
410 | WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) | 414 | WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) |
411 | return (struct brcmf_vs_tlv *)ie; | 415 | return (struct brcmf_vs_tlv *)ie; |
412 | } | 416 | } |
@@ -414,9 +418,9 @@ brcmf_find_wpaie(u8 *parse, u32 len) | |||
414 | } | 418 | } |
415 | 419 | ||
416 | static struct brcmf_vs_tlv * | 420 | static struct brcmf_vs_tlv * |
417 | brcmf_find_wpsie(u8 *parse, u32 len) | 421 | brcmf_find_wpsie(const u8 *parse, u32 len) |
418 | { | 422 | { |
419 | struct brcmf_tlv *ie; | 423 | const struct brcmf_tlv *ie; |
420 | 424 | ||
421 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | 425 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { |
422 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | 426 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, |
@@ -491,6 +495,19 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) | |||
491 | return err; | 495 | return err; |
492 | } | 496 | } |
493 | 497 | ||
498 | static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) | ||
499 | { | ||
500 | enum nl80211_iftype iftype; | ||
501 | |||
502 | iftype = vif->wdev.iftype; | ||
503 | return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO; | ||
504 | } | ||
505 | |||
506 | static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) | ||
507 | { | ||
508 | return vif->wdev.iftype == NL80211_IFTYPE_ADHOC; | ||
509 | } | ||
510 | |||
494 | static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, | 511 | static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, |
495 | const char *name, | 512 | const char *name, |
496 | enum nl80211_iftype type, | 513 | enum nl80211_iftype type, |
@@ -651,7 +668,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
651 | type); | 668 | type); |
652 | return -EOPNOTSUPP; | 669 | return -EOPNOTSUPP; |
653 | case NL80211_IFTYPE_ADHOC: | 670 | case NL80211_IFTYPE_ADHOC: |
654 | vif->mode = WL_MODE_IBSS; | ||
655 | infra = 0; | 671 | infra = 0; |
656 | break; | 672 | break; |
657 | case NL80211_IFTYPE_STATION: | 673 | case NL80211_IFTYPE_STATION: |
@@ -667,12 +683,10 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
667 | */ | 683 | */ |
668 | return 0; | 684 | return 0; |
669 | } | 685 | } |
670 | vif->mode = WL_MODE_BSS; | ||
671 | infra = 1; | 686 | infra = 1; |
672 | break; | 687 | break; |
673 | case NL80211_IFTYPE_AP: | 688 | case NL80211_IFTYPE_AP: |
674 | case NL80211_IFTYPE_P2P_GO: | 689 | case NL80211_IFTYPE_P2P_GO: |
675 | vif->mode = WL_MODE_AP; | ||
676 | ap = 1; | 690 | ap = 1; |
677 | break; | 691 | break; |
678 | default: | 692 | default: |
@@ -696,7 +710,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
696 | err = -EAGAIN; | 710 | err = -EAGAIN; |
697 | goto done; | 711 | goto done; |
698 | } | 712 | } |
699 | brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ? | 713 | brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ? |
700 | "Adhoc" : "Infra"); | 714 | "Adhoc" : "Infra"); |
701 | } | 715 | } |
702 | ndev->ieee80211_ptr->iftype = type; | 716 | ndev->ieee80211_ptr->iftype = type; |
@@ -1562,9 +1576,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1562 | struct ieee80211_channel *chan = sme->channel; | 1576 | struct ieee80211_channel *chan = sme->channel; |
1563 | struct brcmf_join_params join_params; | 1577 | struct brcmf_join_params join_params; |
1564 | size_t join_params_size; | 1578 | size_t join_params_size; |
1565 | struct brcmf_tlv *rsn_ie; | 1579 | const struct brcmf_tlv *rsn_ie; |
1566 | struct brcmf_vs_tlv *wpa_ie; | 1580 | const struct brcmf_vs_tlv *wpa_ie; |
1567 | void *ie; | 1581 | const void *ie; |
1568 | u32 ie_len; | 1582 | u32 ie_len; |
1569 | struct brcmf_ext_join_params_le *ext_join_params; | 1583 | struct brcmf_ext_join_params_le *ext_join_params; |
1570 | u16 chanspec; | 1584 | u16 chanspec; |
@@ -1591,7 +1605,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1591 | ie_len = wpa_ie->len + TLV_HDR_LEN; | 1605 | ie_len = wpa_ie->len + TLV_HDR_LEN; |
1592 | } else { | 1606 | } else { |
1593 | /* find the RSN_IE */ | 1607 | /* find the RSN_IE */ |
1594 | rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len, | 1608 | rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, |
1609 | sme->ie_len, | ||
1595 | WLAN_EID_RSN); | 1610 | WLAN_EID_RSN); |
1596 | if (rsn_ie) { | 1611 | if (rsn_ie) { |
1597 | ie = rsn_ie; | 1612 | ie = rsn_ie; |
@@ -1678,22 +1693,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1678 | ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); | 1693 | ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); |
1679 | memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, | 1694 | memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, |
1680 | profile->ssid.SSID_len); | 1695 | profile->ssid.SSID_len); |
1681 | /*increase dwell time to receive probe response or detect Beacon | 1696 | |
1682 | * from target AP at a noisy air only during connect command | ||
1683 | */ | ||
1684 | ext_join_params->scan_le.active_time = | ||
1685 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); | ||
1686 | ext_join_params->scan_le.passive_time = | ||
1687 | cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); | ||
1688 | /* Set up join scan parameters */ | 1697 | /* Set up join scan parameters */ |
1689 | ext_join_params->scan_le.scan_type = -1; | 1698 | ext_join_params->scan_le.scan_type = -1; |
1690 | /* to sync with presence period of VSDB GO. | ||
1691 | * Send probe request more frequently. Probe request will be stopped | ||
1692 | * when it gets probe response from target AP/GO. | ||
1693 | */ | ||
1694 | ext_join_params->scan_le.nprobes = | ||
1695 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / | ||
1696 | BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); | ||
1697 | ext_join_params->scan_le.home_time = cpu_to_le32(-1); | 1699 | ext_join_params->scan_le.home_time = cpu_to_le32(-1); |
1698 | 1700 | ||
1699 | if (sme->bssid) | 1701 | if (sme->bssid) |
@@ -1706,6 +1708,25 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1706 | 1708 | ||
1707 | ext_join_params->assoc_le.chanspec_list[0] = | 1709 | ext_join_params->assoc_le.chanspec_list[0] = |
1708 | cpu_to_le16(chanspec); | 1710 | cpu_to_le16(chanspec); |
1711 | /* Increase dwell time to receive probe response or detect | ||
1712 | * beacon from target AP at a noisy air only during connect | ||
1713 | * command. | ||
1714 | */ | ||
1715 | ext_join_params->scan_le.active_time = | ||
1716 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); | ||
1717 | ext_join_params->scan_le.passive_time = | ||
1718 | cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); | ||
1719 | /* To sync with presence period of VSDB GO send probe request | ||
1720 | * more frequently. Probe request will be stopped when it gets | ||
1721 | * probe response from target AP/GO. | ||
1722 | */ | ||
1723 | ext_join_params->scan_le.nprobes = | ||
1724 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / | ||
1725 | BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); | ||
1726 | } else { | ||
1727 | ext_join_params->scan_le.active_time = cpu_to_le32(-1); | ||
1728 | ext_join_params->scan_le.passive_time = cpu_to_le32(-1); | ||
1729 | ext_join_params->scan_le.nprobes = cpu_to_le32(-1); | ||
1709 | } | 1730 | } |
1710 | 1731 | ||
1711 | err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, | 1732 | err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, |
@@ -1913,7 +1934,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, | |||
1913 | brcmf_dbg(CONN, "Setting the key index %d\n", key.index); | 1934 | brcmf_dbg(CONN, "Setting the key index %d\n", key.index); |
1914 | memcpy(key.data, params->key, key.len); | 1935 | memcpy(key.data, params->key, key.len); |
1915 | 1936 | ||
1916 | if ((ifp->vif->mode != WL_MODE_AP) && | 1937 | if (!brcmf_is_apmode(ifp->vif) && |
1917 | (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { | 1938 | (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { |
1918 | brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); | 1939 | brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); |
1919 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); | 1940 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); |
@@ -1981,7 +2002,9 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1981 | if (!check_vif_up(ifp->vif)) | 2002 | if (!check_vif_up(ifp->vif)) |
1982 | return -EIO; | 2003 | return -EIO; |
1983 | 2004 | ||
1984 | if (mac_addr) { | 2005 | if (mac_addr && |
2006 | (params->cipher != WLAN_CIPHER_SUITE_WEP40) && | ||
2007 | (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { | ||
1985 | brcmf_dbg(TRACE, "Exit"); | 2008 | brcmf_dbg(TRACE, "Exit"); |
1986 | return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); | 2009 | return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); |
1987 | } | 2010 | } |
@@ -2010,7 +2033,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
2010 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); | 2033 | brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); |
2011 | break; | 2034 | break; |
2012 | case WLAN_CIPHER_SUITE_TKIP: | 2035 | case WLAN_CIPHER_SUITE_TKIP: |
2013 | if (ifp->vif->mode != WL_MODE_AP) { | 2036 | if (!brcmf_is_apmode(ifp->vif)) { |
2014 | brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); | 2037 | brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); |
2015 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); | 2038 | memcpy(keybuf, &key.data[24], sizeof(keybuf)); |
2016 | memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); | 2039 | memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); |
@@ -2164,12 +2187,14 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | |||
2164 | s32 err = 0; | 2187 | s32 err = 0; |
2165 | u8 *bssid = profile->bssid; | 2188 | u8 *bssid = profile->bssid; |
2166 | struct brcmf_sta_info_le sta_info_le; | 2189 | struct brcmf_sta_info_le sta_info_le; |
2190 | u32 beacon_period; | ||
2191 | u32 dtim_period; | ||
2167 | 2192 | ||
2168 | brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); | 2193 | brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); |
2169 | if (!check_vif_up(ifp->vif)) | 2194 | if (!check_vif_up(ifp->vif)) |
2170 | return -EIO; | 2195 | return -EIO; |
2171 | 2196 | ||
2172 | if (ifp->vif->mode == WL_MODE_AP) { | 2197 | if (brcmf_is_apmode(ifp->vif)) { |
2173 | memcpy(&sta_info_le, mac, ETH_ALEN); | 2198 | memcpy(&sta_info_le, mac, ETH_ALEN); |
2174 | err = brcmf_fil_iovar_data_get(ifp, "sta_info", | 2199 | err = brcmf_fil_iovar_data_get(ifp, "sta_info", |
2175 | &sta_info_le, | 2200 | &sta_info_le, |
@@ -2186,7 +2211,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | |||
2186 | } | 2211 | } |
2187 | brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", | 2212 | brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", |
2188 | sinfo->inactive_time, sinfo->connected_time); | 2213 | sinfo->inactive_time, sinfo->connected_time); |
2189 | } else if (ifp->vif->mode == WL_MODE_BSS) { | 2214 | } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) { |
2190 | if (memcmp(mac, bssid, ETH_ALEN)) { | 2215 | if (memcmp(mac, bssid, ETH_ALEN)) { |
2191 | brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", | 2216 | brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", |
2192 | mac, bssid); | 2217 | mac, bssid); |
@@ -2218,6 +2243,30 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | |||
2218 | sinfo->signal = rssi; | 2243 | sinfo->signal = rssi; |
2219 | brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); | 2244 | brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); |
2220 | } | 2245 | } |
2246 | err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD, | ||
2247 | &beacon_period); | ||
2248 | if (err) { | ||
2249 | brcmf_err("Could not get beacon period (%d)\n", | ||
2250 | err); | ||
2251 | goto done; | ||
2252 | } else { | ||
2253 | sinfo->bss_param.beacon_interval = | ||
2254 | beacon_period; | ||
2255 | brcmf_dbg(CONN, "Beacon peroid %d\n", | ||
2256 | beacon_period); | ||
2257 | } | ||
2258 | err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD, | ||
2259 | &dtim_period); | ||
2260 | if (err) { | ||
2261 | brcmf_err("Could not get DTIM period (%d)\n", | ||
2262 | err); | ||
2263 | goto done; | ||
2264 | } else { | ||
2265 | sinfo->bss_param.dtim_period = dtim_period; | ||
2266 | brcmf_dbg(CONN, "DTIM peroid %d\n", | ||
2267 | dtim_period); | ||
2268 | } | ||
2269 | sinfo->filled |= STATION_INFO_BSS_PARAM; | ||
2221 | } | 2270 | } |
2222 | } else | 2271 | } else |
2223 | err = -EPERM; | 2272 | err = -EPERM; |
@@ -2444,18 +2493,13 @@ CleanUp: | |||
2444 | return err; | 2493 | return err; |
2445 | } | 2494 | } |
2446 | 2495 | ||
2447 | static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) | ||
2448 | { | ||
2449 | return vif->mode == WL_MODE_IBSS; | ||
2450 | } | ||
2451 | |||
2452 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, | 2496 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, |
2453 | struct brcmf_if *ifp) | 2497 | struct brcmf_if *ifp) |
2454 | { | 2498 | { |
2455 | struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); | 2499 | struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); |
2456 | struct brcmf_bss_info_le *bi; | 2500 | struct brcmf_bss_info_le *bi; |
2457 | struct brcmf_ssid *ssid; | 2501 | struct brcmf_ssid *ssid; |
2458 | struct brcmf_tlv *tim; | 2502 | const struct brcmf_tlv *tim; |
2459 | u16 beacon_interval; | 2503 | u16 beacon_interval; |
2460 | u8 dtim_period; | 2504 | u8 dtim_period; |
2461 | size_t ie_len; | 2505 | size_t ie_len; |
@@ -3220,8 +3264,9 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) | |||
3220 | } | 3264 | } |
3221 | 3265 | ||
3222 | static s32 | 3266 | static s32 |
3223 | brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, | 3267 | brcmf_configure_wpaie(struct net_device *ndev, |
3224 | bool is_rsn_ie) | 3268 | const struct brcmf_vs_tlv *wpa_ie, |
3269 | bool is_rsn_ie) | ||
3225 | { | 3270 | { |
3226 | struct brcmf_if *ifp = netdev_priv(ndev); | 3271 | struct brcmf_if *ifp = netdev_priv(ndev); |
3227 | u32 auth = 0; /* d11 open authentication */ | 3272 | u32 auth = 0; /* d11 open authentication */ |
@@ -3707,11 +3752,11 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3707 | s32 ie_offset; | 3752 | s32 ie_offset; |
3708 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 3753 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
3709 | struct brcmf_if *ifp = netdev_priv(ndev); | 3754 | struct brcmf_if *ifp = netdev_priv(ndev); |
3710 | struct brcmf_tlv *ssid_ie; | 3755 | const struct brcmf_tlv *ssid_ie; |
3711 | struct brcmf_ssid_le ssid_le; | 3756 | struct brcmf_ssid_le ssid_le; |
3712 | s32 err = -EPERM; | 3757 | s32 err = -EPERM; |
3713 | struct brcmf_tlv *rsn_ie; | 3758 | const struct brcmf_tlv *rsn_ie; |
3714 | struct brcmf_vs_tlv *wpa_ie; | 3759 | const struct brcmf_vs_tlv *wpa_ie; |
3715 | struct brcmf_join_params join_params; | 3760 | struct brcmf_join_params join_params; |
3716 | enum nl80211_iftype dev_role; | 3761 | enum nl80211_iftype dev_role; |
3717 | struct brcmf_fil_bss_enable_le bss_enable; | 3762 | struct brcmf_fil_bss_enable_le bss_enable; |
@@ -4220,32 +4265,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { | |||
4220 | CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) | 4265 | CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) |
4221 | }; | 4266 | }; |
4222 | 4267 | ||
4223 | static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) | ||
4224 | { | ||
4225 | switch (type) { | ||
4226 | case NL80211_IFTYPE_AP_VLAN: | ||
4227 | case NL80211_IFTYPE_WDS: | ||
4228 | case NL80211_IFTYPE_MONITOR: | ||
4229 | case NL80211_IFTYPE_MESH_POINT: | ||
4230 | return -ENOTSUPP; | ||
4231 | case NL80211_IFTYPE_ADHOC: | ||
4232 | return WL_MODE_IBSS; | ||
4233 | case NL80211_IFTYPE_STATION: | ||
4234 | case NL80211_IFTYPE_P2P_CLIENT: | ||
4235 | return WL_MODE_BSS; | ||
4236 | case NL80211_IFTYPE_AP: | ||
4237 | case NL80211_IFTYPE_P2P_GO: | ||
4238 | return WL_MODE_AP; | ||
4239 | case NL80211_IFTYPE_P2P_DEVICE: | ||
4240 | return WL_MODE_P2P; | ||
4241 | case NL80211_IFTYPE_UNSPECIFIED: | ||
4242 | default: | ||
4243 | break; | ||
4244 | } | ||
4245 | |||
4246 | return -EINVAL; | ||
4247 | } | ||
4248 | |||
4249 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | 4268 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) |
4250 | { | 4269 | { |
4251 | /* scheduled scan settings */ | 4270 | /* scheduled scan settings */ |
@@ -4370,7 +4389,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | |||
4370 | vif->wdev.wiphy = cfg->wiphy; | 4389 | vif->wdev.wiphy = cfg->wiphy; |
4371 | vif->wdev.iftype = type; | 4390 | vif->wdev.iftype = type; |
4372 | 4391 | ||
4373 | vif->mode = brcmf_nl80211_iftype_to_mode(type); | ||
4374 | vif->pm_block = pm_block; | 4392 | vif->pm_block = pm_block; |
4375 | vif->roam_off = -1; | 4393 | vif->roam_off = -1; |
4376 | 4394 | ||
@@ -4416,7 +4434,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e) | |||
4416 | u32 event = e->event_code; | 4434 | u32 event = e->event_code; |
4417 | u16 flags = e->flags; | 4435 | u16 flags = e->flags; |
4418 | 4436 | ||
4419 | if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { | 4437 | if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) || |
4438 | (event == BRCMF_E_DISASSOC_IND) || | ||
4439 | ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) { | ||
4420 | brcmf_dbg(CONN, "Processing link down\n"); | 4440 | brcmf_dbg(CONN, "Processing link down\n"); |
4421 | return true; | 4441 | return true; |
4422 | } | 4442 | } |
@@ -4658,16 +4678,19 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, | |||
4658 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | 4678 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; |
4659 | struct net_device *ndev = ifp->ndev; | 4679 | struct net_device *ndev = ifp->ndev; |
4660 | struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; | 4680 | struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; |
4681 | struct ieee80211_channel *chan; | ||
4661 | s32 err = 0; | 4682 | s32 err = 0; |
4683 | u16 reason; | ||
4662 | 4684 | ||
4663 | if (ifp->vif->mode == WL_MODE_AP) { | 4685 | if (brcmf_is_apmode(ifp->vif)) { |
4664 | err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); | 4686 | err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); |
4665 | } else if (brcmf_is_linkup(e)) { | 4687 | } else if (brcmf_is_linkup(e)) { |
4666 | brcmf_dbg(CONN, "Linkup\n"); | 4688 | brcmf_dbg(CONN, "Linkup\n"); |
4667 | if (brcmf_is_ibssmode(ifp->vif)) { | 4689 | if (brcmf_is_ibssmode(ifp->vif)) { |
4690 | chan = ieee80211_get_channel(cfg->wiphy, cfg->channel); | ||
4668 | memcpy(profile->bssid, e->addr, ETH_ALEN); | 4691 | memcpy(profile->bssid, e->addr, ETH_ALEN); |
4669 | wl_inform_ibss(cfg, ndev, e->addr); | 4692 | wl_inform_ibss(cfg, ndev, e->addr); |
4670 | cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); | 4693 | cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL); |
4671 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, | 4694 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, |
4672 | &ifp->vif->sme_state); | 4695 | &ifp->vif->sme_state); |
4673 | set_bit(BRCMF_VIF_STATUS_CONNECTED, | 4696 | set_bit(BRCMF_VIF_STATUS_CONNECTED, |
@@ -4679,9 +4702,15 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, | |||
4679 | if (!brcmf_is_ibssmode(ifp->vif)) { | 4702 | if (!brcmf_is_ibssmode(ifp->vif)) { |
4680 | brcmf_bss_connect_done(cfg, ndev, e, false); | 4703 | brcmf_bss_connect_done(cfg, ndev, e, false); |
4681 | if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, | 4704 | if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, |
4682 | &ifp->vif->sme_state)) | 4705 | &ifp->vif->sme_state)) { |
4683 | cfg80211_disconnected(ndev, 0, NULL, 0, | 4706 | reason = 0; |
4707 | if (((e->event_code == BRCMF_E_DEAUTH_IND) || | ||
4708 | (e->event_code == BRCMF_E_DISASSOC_IND)) && | ||
4709 | (e->reason != WLAN_REASON_UNSPECIFIED)) | ||
4710 | reason = e->reason; | ||
4711 | cfg80211_disconnected(ndev, reason, NULL, 0, | ||
4684 | GFP_KERNEL); | 4712 | GFP_KERNEL); |
4713 | } | ||
4685 | } | 4714 | } |
4686 | brcmf_link_down(ifp->vif); | 4715 | brcmf_link_down(ifp->vif); |
4687 | brcmf_init_prof(ndev_to_prof(ndev)); | 4716 | brcmf_init_prof(ndev_to_prof(ndev)); |
@@ -4875,11 +4904,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) | |||
4875 | 4904 | ||
4876 | cfg->scan_request = NULL; | 4905 | cfg->scan_request = NULL; |
4877 | cfg->pwr_save = true; | 4906 | cfg->pwr_save = true; |
4878 | cfg->roam_on = true; /* roam on & off switch. | 4907 | cfg->active_scan = true; /* we do active scan per default */ |
4879 | we enable roam per default */ | 4908 | cfg->dongle_up = false; /* dongle is not up yet */ |
4880 | cfg->active_scan = true; /* we do active scan for | ||
4881 | specific scan per default */ | ||
4882 | cfg->dongle_up = false; /* dongle is not up yet */ | ||
4883 | err = brcmf_init_priv_mem(cfg); | 4909 | err = brcmf_init_priv_mem(cfg); |
4884 | if (err) | 4910 | if (err) |
4885 | return err; | 4911 | return err; |
@@ -4904,6 +4930,30 @@ static void init_vif_event(struct brcmf_cfg80211_vif_event *event) | |||
4904 | mutex_init(&event->vif_event_lock); | 4930 | mutex_init(&event->vif_event_lock); |
4905 | } | 4931 | } |
4906 | 4932 | ||
4933 | static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) | ||
4934 | { | ||
4935 | struct brcmf_fil_bwcap_le band_bwcap; | ||
4936 | u32 val; | ||
4937 | int err; | ||
4938 | |||
4939 | /* verify support for bw_cap command */ | ||
4940 | val = WLC_BAND_5G; | ||
4941 | err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val); | ||
4942 | |||
4943 | if (!err) { | ||
4944 | /* only set 2G bandwidth using bw_cap command */ | ||
4945 | band_bwcap.band = cpu_to_le32(WLC_BAND_2G); | ||
4946 | band_bwcap.bw_cap = cpu_to_le32(WLC_BW_40MHZ_BIT); | ||
4947 | err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap, | ||
4948 | sizeof(band_bwcap)); | ||
4949 | } else { | ||
4950 | brcmf_dbg(INFO, "fallback to mimo_bw_cap\n"); | ||
4951 | val = WLC_N_BW_40ALL; | ||
4952 | err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val); | ||
4953 | } | ||
4954 | return err; | ||
4955 | } | ||
4956 | |||
4907 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, | 4957 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, |
4908 | struct device *busdev) | 4958 | struct device *busdev) |
4909 | { | 4959 | { |
@@ -4961,6 +5011,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, | |||
4961 | goto cfg80211_p2p_attach_out; | 5011 | goto cfg80211_p2p_attach_out; |
4962 | } | 5012 | } |
4963 | 5013 | ||
5014 | /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(), | ||
5015 | * setup 40MHz in 2GHz band and enable OBSS scanning. | ||
5016 | */ | ||
5017 | if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap & | ||
5018 | IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
5019 | err = brcmf_enable_bw40_2g(ifp); | ||
5020 | if (!err) | ||
5021 | err = brcmf_fil_iovar_int_set(ifp, "obss_coex", | ||
5022 | BRCMF_OBSS_COEX_AUTO); | ||
5023 | } | ||
5024 | |||
4964 | err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); | 5025 | err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); |
4965 | if (err) { | 5026 | if (err) { |
4966 | brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); | 5027 | brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); |
@@ -4999,7 +5060,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) | |||
4999 | } | 5060 | } |
5000 | 5061 | ||
5001 | static s32 | 5062 | static s32 |
5002 | brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) | 5063 | brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout) |
5003 | { | 5064 | { |
5004 | s32 err = 0; | 5065 | s32 err = 0; |
5005 | __le32 roamtrigger[2]; | 5066 | __le32 roamtrigger[2]; |
@@ -5009,7 +5070,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) | |||
5009 | * Setup timeout if Beacons are lost and roam is | 5070 | * Setup timeout if Beacons are lost and roam is |
5010 | * off to report link down | 5071 | * off to report link down |
5011 | */ | 5072 | */ |
5012 | if (roamvar) { | 5073 | if (brcmf_roamoff) { |
5013 | err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout); | 5074 | err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout); |
5014 | if (err) { | 5075 | if (err) { |
5015 | brcmf_err("bcn_timeout error (%d)\n", err); | 5076 | brcmf_err("bcn_timeout error (%d)\n", err); |
@@ -5021,8 +5082,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) | |||
5021 | * Enable/Disable built-in roaming to allow supplicant | 5082 | * Enable/Disable built-in roaming to allow supplicant |
5022 | * to take care of roaming | 5083 | * to take care of roaming |
5023 | */ | 5084 | */ |
5024 | brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On"); | 5085 | brcmf_dbg(INFO, "Internal Roaming = %s\n", |
5025 | err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar); | 5086 | brcmf_roamoff ? "Off" : "On"); |
5087 | err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff)); | ||
5026 | if (err) { | 5088 | if (err) { |
5027 | brcmf_err("roam_off error (%d)\n", err); | 5089 | brcmf_err("roam_off error (%d)\n", err); |
5028 | goto dongle_rom_out; | 5090 | goto dongle_rom_out; |
@@ -5164,9 +5226,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, | |||
5164 | ieee80211_channel_to_frequency(ch.chnum, band); | 5226 | ieee80211_channel_to_frequency(ch.chnum, band); |
5165 | band_chan_arr[index].hw_value = ch.chnum; | 5227 | band_chan_arr[index].hw_value = ch.chnum; |
5166 | 5228 | ||
5167 | brcmf_err("channel %d: f=%d bw=%d sb=%d\n", | ||
5168 | ch.chnum, band_chan_arr[index].center_freq, | ||
5169 | ch.bw, ch.sb); | ||
5170 | if (ch.bw == BRCMU_CHAN_BW_40) { | 5229 | if (ch.bw == BRCMU_CHAN_BW_40) { |
5171 | /* assuming the order is HT20, HT40 Upper, | 5230 | /* assuming the order is HT20, HT40 Upper, |
5172 | * HT40 lower from chanspecs | 5231 | * HT40 lower from chanspecs |
@@ -5267,6 +5326,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) | |||
5267 | u32 band_list[3]; | 5326 | u32 band_list[3]; |
5268 | u32 nmode; | 5327 | u32 nmode; |
5269 | u32 bw_cap[2] = { 0, 0 }; | 5328 | u32 bw_cap[2] = { 0, 0 }; |
5329 | u32 rxchain; | ||
5330 | u32 nchain; | ||
5270 | s8 phy; | 5331 | s8 phy; |
5271 | s32 err; | 5332 | s32 err; |
5272 | u32 nband; | 5333 | u32 nband; |
@@ -5303,6 +5364,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) | |||
5303 | brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode, | 5364 | brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode, |
5304 | bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]); | 5365 | bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]); |
5305 | 5366 | ||
5367 | err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); | ||
5368 | if (err) { | ||
5369 | brcmf_err("rxchain error (%d)\n", err); | ||
5370 | nchain = 1; | ||
5371 | } else { | ||
5372 | for (nchain = 0; rxchain; nchain++) | ||
5373 | rxchain = rxchain & (rxchain - 1); | ||
5374 | } | ||
5375 | brcmf_dbg(INFO, "nchain=%d\n", nchain); | ||
5376 | |||
5306 | err = brcmf_construct_reginfo(cfg, bw_cap); | 5377 | err = brcmf_construct_reginfo(cfg, bw_cap); |
5307 | if (err) { | 5378 | if (err) { |
5308 | brcmf_err("brcmf_construct_reginfo failed (%d)\n", err); | 5379 | brcmf_err("brcmf_construct_reginfo failed (%d)\n", err); |
@@ -5331,10 +5402,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) | |||
5331 | band->ht_cap.ht_supported = true; | 5402 | band->ht_cap.ht_supported = true; |
5332 | band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | 5403 | band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; |
5333 | band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; | 5404 | band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; |
5334 | /* An HT shall support all EQM rates for one spatial | 5405 | memset(band->ht_cap.mcs.rx_mask, 0xff, nchain); |
5335 | * stream | ||
5336 | */ | ||
5337 | band->ht_cap.mcs.rx_mask[0] = 0xff; | ||
5338 | band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | 5406 | band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
5339 | bands[band->band] = band; | 5407 | bands[band->band] = band; |
5340 | } | 5408 | } |
@@ -5381,7 +5449,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) | |||
5381 | brcmf_dbg(INFO, "power save set to %s\n", | 5449 | brcmf_dbg(INFO, "power save set to %s\n", |
5382 | (power_mode ? "enabled" : "disabled")); | 5450 | (power_mode ? "enabled" : "disabled")); |
5383 | 5451 | ||
5384 | err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT); | 5452 | err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT); |
5385 | if (err) | 5453 | if (err) |
5386 | goto default_conf_out; | 5454 | goto default_conf_out; |
5387 | err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, | 5455 | err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 2dc6a074e8ed..283c525a44f7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -89,21 +89,6 @@ enum brcmf_scan_status { | |||
89 | BRCMF_SCAN_STATUS_SUPPRESS, | 89 | BRCMF_SCAN_STATUS_SUPPRESS, |
90 | }; | 90 | }; |
91 | 91 | ||
92 | /** | ||
93 | * enum wl_mode - driver mode of virtual interface. | ||
94 | * | ||
95 | * @WL_MODE_BSS: connects to BSS. | ||
96 | * @WL_MODE_IBSS: operate as ad-hoc. | ||
97 | * @WL_MODE_AP: operate as access-point. | ||
98 | * @WL_MODE_P2P: provide P2P discovery. | ||
99 | */ | ||
100 | enum wl_mode { | ||
101 | WL_MODE_BSS, | ||
102 | WL_MODE_IBSS, | ||
103 | WL_MODE_AP, | ||
104 | WL_MODE_P2P | ||
105 | }; | ||
106 | |||
107 | /* dongle configuration */ | 92 | /* dongle configuration */ |
108 | struct brcmf_cfg80211_conf { | 93 | struct brcmf_cfg80211_conf { |
109 | u32 frag_threshold; | 94 | u32 frag_threshold; |
@@ -193,7 +178,6 @@ struct vif_saved_ie { | |||
193 | * @ifp: lower layer interface pointer | 178 | * @ifp: lower layer interface pointer |
194 | * @wdev: wireless device. | 179 | * @wdev: wireless device. |
195 | * @profile: profile information. | 180 | * @profile: profile information. |
196 | * @mode: operating mode. | ||
197 | * @roam_off: roaming state. | 181 | * @roam_off: roaming state. |
198 | * @sme_state: SME state using enum brcmf_vif_status bits. | 182 | * @sme_state: SME state using enum brcmf_vif_status bits. |
199 | * @pm_block: power-management blocked. | 183 | * @pm_block: power-management blocked. |
@@ -204,7 +188,6 @@ struct brcmf_cfg80211_vif { | |||
204 | struct brcmf_if *ifp; | 188 | struct brcmf_if *ifp; |
205 | struct wireless_dev wdev; | 189 | struct wireless_dev wdev; |
206 | struct brcmf_cfg80211_profile profile; | 190 | struct brcmf_cfg80211_profile profile; |
207 | s32 mode; | ||
208 | s32 roam_off; | 191 | s32 roam_off; |
209 | unsigned long sme_state; | 192 | unsigned long sme_state; |
210 | bool pm_block; | 193 | bool pm_block; |
@@ -402,7 +385,6 @@ struct brcmf_cfg80211_info { | |||
402 | bool ibss_starter; | 385 | bool ibss_starter; |
403 | bool pwr_save; | 386 | bool pwr_save; |
404 | bool dongle_up; | 387 | bool dongle_up; |
405 | bool roam_on; | ||
406 | bool scan_tried; | 388 | bool scan_tried; |
407 | u8 *dcmd_buf; | 389 | u8 *dcmd_buf; |
408 | u8 *extra_buf; | 390 | u8 *extra_buf; |
@@ -491,7 +473,8 @@ void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); | |||
491 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | 473 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, |
492 | const u8 *vndr_ie_buf, u32 vndr_ie_len); | 474 | const u8 *vndr_ie_buf, u32 vndr_ie_len); |
493 | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); | 475 | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); |
494 | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); | 476 | const struct brcmf_tlv * |
477 | brcmf_parse_tlvs(const void *buf, int buflen, uint key); | ||
495 | u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, | 478 | u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, |
496 | struct ieee80211_channel *ch); | 479 | struct ieee80211_channel *ch); |
497 | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); | 480 | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 925034b80e9c..8c5fa4e58139 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80211_hw *hw) | |||
426 | bool blocked; | 426 | bool blocked; |
427 | int err; | 427 | int err; |
428 | 428 | ||
429 | if (!wl->ucode.bcm43xx_bomminor) { | ||
430 | err = brcms_request_fw(wl, wl->wlc->hw->d11core); | ||
431 | if (err) | ||
432 | return -ENOENT; | ||
433 | } | ||
434 | |||
429 | ieee80211_wake_queues(hw); | 435 | ieee80211_wake_queues(hw); |
430 | spin_lock_bh(&wl->lock); | 436 | spin_lock_bh(&wl->lock); |
431 | blocked = brcms_rfkill_set_hw_state(wl); | 437 | blocked = brcms_rfkill_set_hw_state(wl); |
@@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw) | |||
433 | if (!blocked) | 439 | if (!blocked) |
434 | wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); | 440 | wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); |
435 | 441 | ||
436 | if (!wl->ucode.bcm43xx_bomminor) { | ||
437 | err = brcms_request_fw(wl, wl->wlc->hw->d11core); | ||
438 | if (err) { | ||
439 | brcms_remove(wl->wlc->hw->d11core); | ||
440 | return -ENOENT; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | spin_lock_bh(&wl->lock); | 442 | spin_lock_bh(&wl->lock); |
445 | /* avoid acknowledging frames before a non-monitor device is added */ | 443 | /* avoid acknowledging frames before a non-monitor device is added */ |
446 | wl->mute_tx = true; | 444 | wl->mute_tx = true; |
@@ -1094,12 +1092,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw) | |||
1094 | * Attach to the WL device identified by vendor and device parameters. | 1092 | * Attach to the WL device identified by vendor and device parameters. |
1095 | * regs is a host accessible memory address pointing to WL device registers. | 1093 | * regs is a host accessible memory address pointing to WL device registers. |
1096 | * | 1094 | * |
1097 | * brcms_attach is not defined as static because in the case where no bus | ||
1098 | * is defined, wl_attach will never be called, and thus, gcc will issue | ||
1099 | * a warning that this function is defined but not used if we declare | ||
1100 | * it as static. | ||
1101 | * | ||
1102 | * | ||
1103 | * is called in brcms_bcma_probe() context, therefore no locking required. | 1095 | * is called in brcms_bcma_probe() context, therefore no locking required. |
1104 | */ | 1096 | */ |
1105 | static struct brcms_info *brcms_attach(struct bcma_device *pdev) | 1097 | static struct brcms_info *brcms_attach(struct bcma_device *pdev) |
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 6fa5d4863782..d816270db3be 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h | |||
@@ -43,5 +43,6 @@ | |||
43 | #define BCM4335_CHIP_ID 0x4335 | 43 | #define BCM4335_CHIP_ID 0x4335 |
44 | #define BCM43362_CHIP_ID 43362 | 44 | #define BCM43362_CHIP_ID 43362 |
45 | #define BCM4339_CHIP_ID 0x4339 | 45 | #define BCM4339_CHIP_ID 0x4339 |
46 | #define BCM4354_CHIP_ID 0x4354 | ||
46 | 47 | ||
47 | #endif /* _BRCM_HW_IDS_H_ */ | 48 | #endif /* _BRCM_HW_IDS_H_ */ |