diff options
Diffstat (limited to 'drivers/staging/brcm80211/brcmfmac')
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/Makefile | 33 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/bcmchip.h | 32 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/bcmsdh.c | 371 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 625 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd.h | 773 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_bus.h | 57 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 498 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_common.c | 872 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_dbg.h | 58 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 1354 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_proto.h | 60 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 4581 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/sdio_host.h | 252 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 3730 | ||||
-rw-r--r-- | drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h | 375 |
15 files changed, 0 insertions, 13671 deletions
diff --git a/drivers/staging/brcm80211/brcmfmac/Makefile b/drivers/staging/brcm80211/brcmfmac/Makefile deleted file mode 100644 index a1b7637dce31..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# Makefile fragment for Broadcom 802.11n Networking Device Driver -# -# Copyright (c) 2010 Broadcom Corporation -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -ccflags-y += \ - -Idrivers/staging/brcm80211/brcmfmac \ - -Idrivers/staging/brcm80211/include - -DHDOFILES = \ - wl_cfg80211.o \ - dhd_cdc.o \ - dhd_common.o \ - dhd_sdio.o \ - dhd_linux.o \ - bcmsdh.o \ - bcmsdh_sdmmc.o - -obj-$(CONFIG_BRCMFMAC) += brcmfmac.o -brcmfmac-objs += $(DHDOFILES) -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/staging/brcm80211/brcmfmac/bcmchip.h b/drivers/staging/brcm80211/brcmfmac/bcmchip.h deleted file mode 100644 index d7d3afd5a10f..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/bcmchip.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2011 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _bcmchip_h_ -#define _bcmchip_h_ - -/* bcm4329 */ -/* SDIO device core, ID 0x829 */ -#define BCM4329_CORE_BUS_BASE 0x18011000 -/* internal memory core, ID 0x80e */ -#define BCM4329_CORE_SOCRAM_BASE 0x18003000 -/* ARM Cortex M3 core, ID 0x82a */ -#define BCM4329_CORE_ARM_BASE 0x18002000 -#define BCM4329_RAMSIZE 0x48000 -/* firmware name */ -#define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin" -#define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt" - -#endif /* _bcmchip_h_ */ diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c deleted file mode 100644 index bff9dcd6fadc..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* ****************** SDIO CARD Interface Functions **************************/ - -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/pci.h> -#include <linux/pci_ids.h> -#include <linux/sched.h> -#include <linux/completion.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/card.h> - -#include <defs.h> -#include <brcm_hw_ids.h> -#include <brcmu_utils.h> -#include <brcmu_wifi.h> -#include <soc.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" -#include "sdio_host.h" - -#define SDIOH_API_ACCESS_RETRY_LIMIT 2 - -static void brcmf_sdioh_irqhandler(struct sdio_func *func) -{ - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); - - brcmf_dbg(TRACE, "***IRQHandler\n"); - - sdio_release_host(func); - - brcmf_sdbrcm_isr(sdiodev->bus); - - sdio_claim_host(func); -} - -int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev) -{ - brcmf_dbg(TRACE, "Entering\n"); - - sdio_claim_host(sdiodev->func[1]); - sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler); - sdio_release_host(sdiodev->func[1]); - - return 0; -} - -int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev) -{ - brcmf_dbg(TRACE, "Entering\n"); - - sdio_claim_host(sdiodev->func[1]); - sdio_release_irq(sdiodev->func[1]); - sdio_release_host(sdiodev->func[1]); - - return 0; -} - -u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, - int *err) -{ - int status; - s32 retry = 0; - u8 data = 0; - - do { - if (retry) /* wait for 1 ms till bus get settled down */ - udelay(1000); - status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num, - addr, (u8 *) &data); - } while (status != 0 - && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); - if (err) - *err = status; - - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", - fnc_num, addr, data); - - return data; -} - -void -brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, - u8 data, int *err) -{ - int status; - s32 retry = 0; - - do { - if (retry) /* wait for 1 ms till bus get settled down */ - udelay(1000); - status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num, - addr, (u8 *) &data); - } while (status != 0 - && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); - if (err) - *err = status; - - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", - fnc_num, addr, data); -} - -int -brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) -{ - int err = 0; - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, - &err); - if (!err) - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, - &err); - - return err; -} - -u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size) -{ - int status; - u32 word = 0; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; - - brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr); - - if (bar0 != sdiodev->sbwad) { - if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0)) - return 0xFFFFFFFF; - - sdiodev->sbwad = bar0; - } - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1, - addr, &word, size); - - sdiodev->regfail = (status != 0); - - brcmf_dbg(INFO, "u32data = 0x%x\n", word); - - /* if ok, return appropriately masked word */ - if (status == 0) { - switch (size) { - case sizeof(u8): - return word & 0xff; - case sizeof(u16): - return word & 0xffff; - case sizeof(u32): - return word; - default: - sdiodev->regfail = true; - - } - } - - /* otherwise, bad sdio access or invalid size */ - brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size); - return 0xFFFFFFFF; -} - -u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, - u32 data) -{ - int status; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; - int err = 0; - - brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", - addr, size * 8, data); - - if (bar0 != sdiodev->sbwad) { - err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); - if (err) - return err; - - sdiodev->sbwad = bar0; - } - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - status = - brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1, - addr, &data, size); - sdiodev->regfail = (status != 0); - - if (status == 0) - return 0; - - brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n", - data, addr, size); - return 0xFFFFFFFF; -} - -bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev) -{ - return sdiodev->regfail; -} - -int -brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, - u8 *buf, uint nbytes, struct sk_buff *pkt) -{ - int status; - uint incr_fix; - uint width; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; - int err = 0; - - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); - - /* Async not implemented yet */ - if (flags & SDIO_REQ_ASYNC) - return -ENOTSUPP; - - if (bar0 != sdiodev->sbwad) { - err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); - if (err) - return err; - - sdiodev->sbwad = bar0; - } - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - - incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; - width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; - if (width == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, - fn, addr, width, nbytes, buf, pkt); - - return status; -} - -int -brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt) -{ - uint incr_fix; - uint width; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; - int err = 0; - - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); - - /* Async not implemented yet */ - if (flags & SDIO_REQ_ASYNC) - return -ENOTSUPP; - - if (bar0 != sdiodev->sbwad) { - err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); - if (err) - return err; - - sdiodev->sbwad = bar0; - } - - addr &= SBSDIO_SB_OFT_ADDR_MASK; - - incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; - width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; - if (width == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, - addr, width, nbytes, buf, pkt); -} - -int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, - u8 *buf, uint nbytes) -{ - addr &= SBSDIO_SB_OFT_ADDR_MASK; - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - - return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, - (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, - addr, 4, nbytes, buf, NULL); -} - -int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) -{ - char t_func = (char)fn; - brcmf_dbg(TRACE, "Enter\n"); - - /* issue abort cmd52 command through F0 */ - brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, - SDIO_CCCR_ABORT, &t_func); - - brcmf_dbg(TRACE, "Exit\n"); - return 0; -} - -int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) -{ - u32 regs = 0; - int ret = 0; - - ret = brcmf_sdioh_attach(sdiodev); - if (ret) - goto out; - - regs = SI_ENUM_BASE; - - /* Report the BAR, to fix if needed */ - sdiodev->sbwad = SI_ENUM_BASE; - - /* try to attach to the target device */ - sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev); - if (!sdiodev->bus) { - brcmf_dbg(ERROR, "device attach failed\n"); - ret = -ENODEV; - goto out; - } - -out: - if (ret) - brcmf_sdio_remove(sdiodev); - - return ret; -} -EXPORT_SYMBOL(brcmf_sdio_probe); - -int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) -{ - if (sdiodev->bus) { - brcmf_sdbrcm_disconnect(sdiodev->bus); - sdiodev->bus = NULL; - } - - brcmf_sdioh_detach(sdiodev); - - sdiodev->sbwad = 0; - - return 0; -} -EXPORT_SYMBOL(brcmf_sdio_remove); - -void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable) -{ - if (enable) - brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); - else - brcmf_sdbrcm_wd_timer(sdiodev->bus, 0); -} diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c deleted file mode 100644 index e919de210f70..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ /dev/null @@ -1,625 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/core.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/mmc/card.h> -#include <linux/suspend.h> -#include <linux/errno.h> -#include <linux/sched.h> /* request_irq() */ -#include <net/cfg80211.h> - -#include <defs.h> -#include <brcm_hw_ids.h> -#include <brcmu_utils.h> -#include <brcmu_wifi.h> -#include "sdio_host.h" -#include "dhd.h" -#include "dhd_dbg.h" -#include "wl_cfg80211.h" - -#define SDIO_VENDOR_ID_BROADCOM 0x02d0 - -#define DMA_ALIGN_MASK 0x03 - -#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 - -#define SDIO_FUNC1_BLOCKSIZE 64 -#define SDIO_FUNC2_BLOCKSIZE 512 - -/* devices we support, null terminated */ -static const struct sdio_device_id brcmf_sdmmc_ids[] = { - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, - { /* end: all zeroes */ }, -}; -MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); - -static bool -brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev) -{ - bool is_err = false; -#ifdef CONFIG_PM_SLEEP - is_err = atomic_read(&sdiodev->suspend); -#endif - return is_err; -} - -static void -brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq) -{ -#ifdef CONFIG_PM_SLEEP - int retry = 0; - while (atomic_read(&sdiodev->suspend) && retry++ != 30) - wait_event_timeout(*wq, false, HZ/100); -#endif -} - -static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, - uint regaddr, u8 *byte) -{ - struct sdio_func *sdfunc = sdiodev->func[0]; - int err_ret; - - /* - * Can only directly write to some F0 registers. - * Handle F2 enable/disable and Abort command - * as a special case. - */ - if (regaddr == SDIO_CCCR_IOEx) { - sdfunc = sdiodev->func[2]; - if (sdfunc) { - sdio_claim_host(sdfunc); - if (*byte & SDIO_FUNC_ENABLE_2) { - /* Enable Function 2 */ - err_ret = sdio_enable_func(sdfunc); - if (err_ret) - brcmf_dbg(ERROR, - "enable F2 failed:%d\n", - err_ret); - } else { - /* Disable Function 2 */ - err_ret = sdio_disable_func(sdfunc); - if (err_ret) - brcmf_dbg(ERROR, - "Disable F2 failed:%d\n", - err_ret); - } - sdio_release_host(sdfunc); - } - } else if (regaddr == SDIO_CCCR_ABORT) { - sdio_claim_host(sdfunc); - sdio_writeb(sdfunc, *byte, regaddr, &err_ret); - sdio_release_host(sdfunc); - } else if (regaddr < 0xF0) { - brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); - err_ret = -EPERM; - } else { - sdio_claim_host(sdfunc); - sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); - sdio_release_host(sdfunc); - } - - return err_ret; -} - -int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, - uint regaddr, u8 *byte) -{ - int err_ret; - - brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr); - - brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); - if (brcmf_pm_resume_error(sdiodev)) - return -EIO; - - if (rw && func == 0) { - /* handle F0 separately */ - err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); - } else { - sdio_claim_host(sdiodev->func[func]); - if (rw) /* CMD52 Write */ - sdio_writeb(sdiodev->func[func], *byte, regaddr, - &err_ret); - else if (func == 0) { - *byte = sdio_f0_readb(sdiodev->func[func], regaddr, - &err_ret); - } else { - *byte = sdio_readb(sdiodev->func[func], regaddr, - &err_ret); - } - sdio_release_host(sdiodev->func[func]); - } - - if (err_ret) - brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "write" : "read", func, regaddr, *byte, err_ret); - - return err_ret; -} - -int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, - uint rw, uint func, uint addr, u32 *word, - uint nbytes) -{ - int err_ret = -EIO; - - if (func == 0) { - brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n"); - return -EINVAL; - } - - brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", - rw, func, addr, nbytes); - - brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); - if (brcmf_pm_resume_error(sdiodev)) - return -EIO; - /* Claim host controller */ - sdio_claim_host(sdiodev->func[func]); - - if (rw) { /* CMD52 Write */ - if (nbytes == 4) - sdio_writel(sdiodev->func[func], *word, addr, - &err_ret); - else if (nbytes == 2) - sdio_writew(sdiodev->func[func], (*word & 0xFFFF), - addr, &err_ret); - else - brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); - } else { /* CMD52 Read */ - if (nbytes == 4) - *word = sdio_readl(sdiodev->func[func], addr, &err_ret); - else if (nbytes == 2) - *word = sdio_readw(sdiodev->func[func], addr, - &err_ret) & 0xFFFF; - else - brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); - } - - /* Release host controller */ - sdio_release_host(sdiodev->func[func]); - - if (err_ret) - brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", - rw ? "write" : "read", err_ret); - - return err_ret; -} - -static int -brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, - uint write, uint func, uint addr, - struct sk_buff *pkt) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - u32 SGCount = 0; - int err_ret = 0; - - struct sk_buff *pnext; - - brcmf_dbg(TRACE, "Enter\n"); - - brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); - if (brcmf_pm_resume_error(sdiodev)) - return -EIO; - - /* Claim host controller */ - sdio_claim_host(sdiodev->func[func]); - for (pnext = pkt; pnext; pnext = pnext->next) { - uint pkt_len = pnext->len; - pkt_len += 3; - pkt_len &= 0xFFFFFFFC; - - if ((write) && (!fifo)) { - err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, - ((u8 *) (pnext->data)), - pkt_len); - } else if (write) { - err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, - ((u8 *) (pnext->data)), - pkt_len); - } else if (fifo) { - err_ret = sdio_readsb(sdiodev->func[func], - ((u8 *) (pnext->data)), - addr, pkt_len); - } else { - err_ret = sdio_memcpy_fromio(sdiodev->func[func], - ((u8 *) (pnext->data)), - addr, pkt_len); - } - - if (err_ret) { - brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", - write ? "TX" : "RX", pnext, SGCount, addr, - pkt_len, err_ret); - } else { - brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", - write ? "TX" : "RX", pnext, SGCount, addr, - pkt_len); - } - - if (!fifo) - addr += pkt_len; - SGCount++; - - } - - /* Release host controller */ - sdio_release_host(sdiodev->func[func]); - - brcmf_dbg(TRACE, "Exit\n"); - return err_ret; -} - -/* - * This function takes a buffer or packet, and fixes everything up - * so that in the end, a DMA-able packet is created. - * - * A buffer does not have an associated packet pointer, - * and may or may not be aligned. - * A packet may consist of a single packet, or a packet chain. - * If it is a packet chain, then all the packets in the chain - * must be properly aligned. - * - * If the packet data is not aligned, then there may only be - * one packet, and in this case, it is copied to a new - * aligned packet. - * - */ -int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, - uint fix_inc, uint write, uint func, uint addr, - uint reg_width, uint buflen_u, u8 *buffer, - struct sk_buff *pkt) -{ - int Status; - struct sk_buff *mypkt = NULL; - - brcmf_dbg(TRACE, "Enter\n"); - - brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); - if (brcmf_pm_resume_error(sdiodev)) - return -EIO; - /* Case 1: we don't have a packet. */ - if (pkt == NULL) { - brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n", - write ? "TX" : "RX", buflen_u); - mypkt = brcmu_pkt_buf_get_skb(buflen_u); - if (!mypkt) { - brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", - buflen_u); - return -EIO; - } - - /* For a write, copy the buffer data into the packet. */ - if (write) - memcpy(mypkt->data, buffer, buflen_u); - - Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, - func, addr, mypkt); - - /* For a read, copy the packet data back to the buffer. */ - if (!write) - memcpy(buffer, mypkt->data, buflen_u); - - brcmu_pkt_buf_free_skb(mypkt); - } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { - /* - * Case 2: We have a packet, but it is unaligned. - * In this case, we cannot have a chain (pkt->next == NULL) - */ - brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n", - write ? "TX" : "RX", pkt->len); - mypkt = brcmu_pkt_buf_get_skb(pkt->len); - if (!mypkt) { - brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", - pkt->len); - return -EIO; - } - - /* For a write, copy the buffer data into the packet. */ - if (write) - memcpy(mypkt->data, pkt->data, pkt->len); - - Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, - func, addr, mypkt); - - /* For a read, copy the packet data back to the buffer. */ - if (!write) - memcpy(pkt->data, mypkt->data, mypkt->len); - - brcmu_pkt_buf_free_skb(mypkt); - } else { /* case 3: We have a packet and - it is aligned. */ - brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n", - write ? "Tx" : "Rx"); - Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, - func, addr, pkt); - } - - return Status; -} - -/* Read client card reg */ -static int -brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr, - int regsize, u32 *data) -{ - - if ((func == 0) || (regsize == 1)) { - u8 temp = 0; - - brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr, - &temp); - *data = temp; - *data &= 0xff; - brcmf_dbg(DATA, "byte read data=0x%02x\n", *data); - } else { - brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr, - data, regsize); - if (regsize == 2) - *data &= 0xffff; - - brcmf_dbg(DATA, "word read data=0x%08x\n", *data); - } - - return SUCCESS; -} - -static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr) -{ - /* read 24 bits and return valid 17 bit addr */ - int i; - u32 scratch, regdata; - __le32 scratch_le; - u8 *ptr = (u8 *)&scratch_le; - - for (i = 0; i < 3; i++) { - if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1, - ®data)) != SUCCESS) - brcmf_dbg(ERROR, "Can't read!\n"); - - *ptr++ = (u8) regdata; - regaddr++; - } - - /* Only the lower 17-bits are valid */ - scratch = le32_to_cpu(scratch_le); - scratch &= 0x0001FFFF; - return scratch; -} - -static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) -{ - int err_ret; - u32 fbraddr; - u8 func; - - brcmf_dbg(TRACE, "\n"); - - /* Get the Card's common CIS address */ - sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev, - SDIO_CCCR_CIS); - brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n", - sdiodev->func_cis_ptr[0]); - - /* Get the Card's function CIS (for each function) */ - for (fbraddr = SDIO_FBR_BASE(1), func = 1; - func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { - sdiodev->func_cis_ptr[func] = - brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr); - brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n", - func, sdiodev->func_cis_ptr[func]); - } - - /* Enable Function 1 */ - sdio_claim_host(sdiodev->func[1]); - err_ret = sdio_enable_func(sdiodev->func[1]); - sdio_release_host(sdiodev->func[1]); - if (err_ret) - brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret); - - return false; -} - -/* - * Public entry points & extern's - */ -int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) -{ - int err_ret = 0; - - brcmf_dbg(TRACE, "\n"); - - sdiodev->num_funcs = 2; - - sdio_claim_host(sdiodev->func[1]); - err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE); - sdio_release_host(sdiodev->func[1]); - if (err_ret) { - brcmf_dbg(ERROR, "Failed to set F1 blocksize\n"); - goto out; - } - - sdio_claim_host(sdiodev->func[2]); - err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE); - sdio_release_host(sdiodev->func[2]); - if (err_ret) { - brcmf_dbg(ERROR, "Failed to set F2 blocksize\n"); - goto out; - } - - brcmf_sdioh_enablefuncs(sdiodev); - -out: - brcmf_dbg(TRACE, "Done\n"); - return err_ret; -} - -void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev) -{ - brcmf_dbg(TRACE, "\n"); - - /* Disable Function 2 */ - sdio_claim_host(sdiodev->func[2]); - sdio_disable_func(sdiodev->func[2]); - sdio_release_host(sdiodev->func[2]); - - /* Disable Function 1 */ - sdio_claim_host(sdiodev->func[1]); - sdio_disable_func(sdiodev->func[1]); - sdio_release_host(sdiodev->func[1]); - -} - -static int brcmf_ops_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int ret = 0; - struct brcmf_sdio_dev *sdiodev; - brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(TRACE, "func->class=%x\n", func->class); - brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); - brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device); - brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num); - - if (func->num == 1) { - if (dev_get_drvdata(&func->card->dev)) { - brcmf_dbg(ERROR, "card private drvdata occupied\n"); - return -ENXIO; - } - sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); - if (!sdiodev) - return -ENOMEM; - sdiodev->func[0] = func->card->sdio_func[0]; - sdiodev->func[1] = func; - dev_set_drvdata(&func->card->dev, sdiodev); - - atomic_set(&sdiodev->suspend, false); - init_waitqueue_head(&sdiodev->request_byte_wait); - init_waitqueue_head(&sdiodev->request_word_wait); - init_waitqueue_head(&sdiodev->request_packet_wait); - init_waitqueue_head(&sdiodev->request_buffer_wait); - } - - if (func->num == 2) { - sdiodev = dev_get_drvdata(&func->card->dev); - if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) - return -ENODEV; - sdiodev->func[2] = func; - - brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); - ret = brcmf_sdio_probe(sdiodev); - } - - return ret; -} - -static void brcmf_ops_sdio_remove(struct sdio_func *func) -{ - struct brcmf_sdio_dev *sdiodev; - brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(INFO, "func->class=%x\n", func->class); - brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor); - brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device); - brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num); - - if (func->num == 2) { - sdiodev = dev_get_drvdata(&func->card->dev); - brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); - brcmf_sdio_remove(sdiodev); - dev_set_drvdata(&func->card->dev, NULL); - kfree(sdiodev); - } -} - -#ifdef CONFIG_PM_SLEEP -static int brcmf_sdio_suspend(struct device *dev) -{ - mmc_pm_flag_t sdio_flags; - struct brcmf_sdio_dev *sdiodev; - struct sdio_func *func = dev_to_sdio_func(dev); - int ret = 0; - - brcmf_dbg(TRACE, "\n"); - - sdiodev = dev_get_drvdata(&func->card->dev); - - atomic_set(&sdiodev->suspend, true); - - sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); - if (!(sdio_flags & MMC_PM_KEEP_POWER)) { - brcmf_dbg(ERROR, "Host can't keep power while suspended\n"); - return -EINVAL; - } - - ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); - if (ret) { - brcmf_dbg(ERROR, "Failed to set pm_flags\n"); - return ret; - } - - brcmf_sdio_wdtmr_enable(sdiodev, false); - - return ret; -} - -static int brcmf_sdio_resume(struct device *dev) -{ - struct brcmf_sdio_dev *sdiodev; - struct sdio_func *func = dev_to_sdio_func(dev); - - sdiodev = dev_get_drvdata(&func->card->dev); - brcmf_sdio_wdtmr_enable(sdiodev, true); - atomic_set(&sdiodev->suspend, false); - return 0; -} - -static const struct dev_pm_ops brcmf_sdio_pm_ops = { - .suspend = brcmf_sdio_suspend, - .resume = brcmf_sdio_resume, -}; -#endif /* CONFIG_PM_SLEEP */ - -static struct sdio_driver brcmf_sdmmc_driver = { - .probe = brcmf_ops_sdio_probe, - .remove = brcmf_ops_sdio_remove, - .name = "brcmfmac", - .id_table = brcmf_sdmmc_ids, -#ifdef CONFIG_PM_SLEEP - .drv = { - .pm = &brcmf_sdio_pm_ops, - }, -#endif /* CONFIG_PM_SLEEP */ -}; - -/* bus register interface */ -int brcmf_bus_register(void) -{ - brcmf_dbg(TRACE, "Enter\n"); - - return sdio_register_driver(&brcmf_sdmmc_driver); -} - -void brcmf_bus_unregister(void) -{ - brcmf_dbg(TRACE, "Enter\n"); - - sdio_unregister_driver(&brcmf_sdmmc_driver); -} diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h deleted file mode 100644 index 3ec74778b2e3..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd.h +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/**************** - * Common types * - */ - -#ifndef _BRCMF_H_ -#define _BRCMF_H_ - -#define BRCMF_VERSION_STR "4.218.248.5" - -/******************************************************************************* - * IO codes that are interpreted by dongle firmware - ******************************************************************************/ -#define BRCMF_C_UP 2 -#define BRCMF_C_SET_PROMISC 10 -#define BRCMF_C_GET_RATE 12 -#define BRCMF_C_GET_INFRA 19 -#define BRCMF_C_SET_INFRA 20 -#define BRCMF_C_GET_AUTH 21 -#define BRCMF_C_SET_AUTH 22 -#define BRCMF_C_GET_BSSID 23 -#define BRCMF_C_GET_SSID 25 -#define BRCMF_C_SET_SSID 26 -#define BRCMF_C_GET_CHANNEL 29 -#define BRCMF_C_GET_SRL 31 -#define BRCMF_C_GET_LRL 33 -#define BRCMF_C_GET_RADIO 37 -#define BRCMF_C_SET_RADIO 38 -#define BRCMF_C_GET_PHYTYPE 39 -#define BRCMF_C_SET_KEY 45 -#define BRCMF_C_SET_PASSIVE_SCAN 49 -#define BRCMF_C_SCAN 50 -#define BRCMF_C_SCAN_RESULTS 51 -#define BRCMF_C_DISASSOC 52 -#define BRCMF_C_REASSOC 53 -#define BRCMF_C_SET_ROAM_TRIGGER 55 -#define BRCMF_C_SET_ROAM_DELTA 57 -#define BRCMF_C_GET_DTIMPRD 77 -#define BRCMF_C_SET_COUNTRY 84 -#define BRCMF_C_GET_PM 85 -#define BRCMF_C_SET_PM 86 -#define BRCMF_C_GET_AP 117 -#define BRCMF_C_SET_AP 118 -#define BRCMF_C_GET_RSSI 127 -#define BRCMF_C_GET_WSEC 133 -#define BRCMF_C_SET_WSEC 134 -#define BRCMF_C_GET_PHY_NOISE 135 -#define BRCMF_C_GET_BSS_INFO 136 -#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 -#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 -#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 -#define BRCMF_C_GET_VALID_CHANNELS 217 -#define BRCMF_C_GET_KEY_PRIMARY 235 -#define BRCMF_C_SET_KEY_PRIMARY 236 -#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 -#define BRCMF_C_GET_VAR 262 -#define BRCMF_C_SET_VAR 263 - -/* phy types (returned by WLC_GET_PHYTPE) */ -#define WLC_PHY_TYPE_A 0 -#define WLC_PHY_TYPE_B 1 -#define WLC_PHY_TYPE_G 2 -#define WLC_PHY_TYPE_N 4 -#define WLC_PHY_TYPE_LP 5 -#define WLC_PHY_TYPE_SSN 6 -#define WLC_PHY_TYPE_HT 7 -#define WLC_PHY_TYPE_LCN 8 -#define WLC_PHY_TYPE_NULL 0xf - -#define BRCMF_EVENTING_MASK_LEN 16 - -#define TOE_TX_CSUM_OL 0x00000001 -#define TOE_RX_CSUM_OL 0x00000002 - -#define BRCMF_BSS_INFO_VERSION 108 /* current ver of brcmf_bss_info struct */ - -/* size of brcmf_scan_params not including variable length array */ -#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 - -/* masks for channel and ssid count */ -#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff -#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 - -#define BRCMF_SCAN_ACTION_START 1 -#define BRCMF_SCAN_ACTION_CONTINUE 2 -#define WL_SCAN_ACTION_ABORT 3 - -#define BRCMF_ISCAN_REQ_VERSION 1 - -/* brcmf_iscan_results status values */ -#define BRCMF_SCAN_RESULTS_SUCCESS 0 -#define BRCMF_SCAN_RESULTS_PARTIAL 1 -#define BRCMF_SCAN_RESULTS_PENDING 2 -#define BRCMF_SCAN_RESULTS_ABORTED 3 -#define BRCMF_SCAN_RESULTS_NO_MEM 4 - -/* Indicates this key is using soft encrypt */ -#define WL_SOFT_KEY (1 << 0) -/* primary (ie tx) key */ -#define BRCMF_PRIMARY_KEY (1 << 1) -/* Reserved for backward compat */ -#define WL_KF_RES_4 (1 << 4) -/* Reserved for backward compat */ -#define WL_KF_RES_5 (1 << 5) -/* Indicates a group key for a IBSS PEER */ -#define WL_IBSS_PEER_GROUP_KEY (1 << 6) - -/* For supporting multiple interfaces */ -#define BRCMF_MAX_IFS 16 -#define BRCMF_DEL_IF -0xe -#define BRCMF_BAD_IF -0xf - -#define DOT11_BSSTYPE_ANY 2 -#define DOT11_MAX_DEFAULT_KEYS 4 - -#define BRCMF_EVENT_MSG_LINK 0x01 -#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 -#define BRCMF_EVENT_MSG_GROUP 0x04 - -struct brcmf_event_msg { - __be16 version; - __be16 flags; - __be32 event_type; - __be32 status; - __be32 reason; - __be32 auth_type; - __be32 datalen; - u8 addr[ETH_ALEN]; - char ifname[IFNAMSIZ]; -} __packed; - -struct brcm_ethhdr { - u16 subtype; - u16 length; - u8 version; - u8 oui[3]; - u16 usr_subtype; -} __packed; - -struct brcmf_event { - struct ethhdr eth; - struct brcm_ethhdr hdr; - struct brcmf_event_msg msg; -} __packed; - -struct dngl_stats { - unsigned long rx_packets; /* total packets received */ - unsigned long tx_packets; /* total packets transmitted */ - unsigned long rx_bytes; /* total bytes received */ - unsigned long tx_bytes; /* total bytes transmitted */ - unsigned long rx_errors; /* bad packets received */ - unsigned long tx_errors; /* packet transmit problems */ - unsigned long rx_dropped; /* packets dropped by dongle */ - unsigned long tx_dropped; /* packets dropped by dongle */ - unsigned long multicast; /* multicast packets received */ -}; - -/* event codes sent by the dongle to this driver */ -#define BRCMF_E_SET_SSID 0 -#define BRCMF_E_JOIN 1 -#define BRCMF_E_START 2 -#define BRCMF_E_AUTH 3 -#define BRCMF_E_AUTH_IND 4 -#define BRCMF_E_DEAUTH 5 -#define BRCMF_E_DEAUTH_IND 6 -#define BRCMF_E_ASSOC 7 -#define BRCMF_E_ASSOC_IND 8 -#define BRCMF_E_REASSOC 9 -#define BRCMF_E_REASSOC_IND 10 -#define BRCMF_E_DISASSOC 11 -#define BRCMF_E_DISASSOC_IND 12 -#define BRCMF_E_QUIET_START 13 -#define BRCMF_E_QUIET_END 14 -#define BRCMF_E_BEACON_RX 15 -#define BRCMF_E_LINK 16 -#define BRCMF_E_MIC_ERROR 17 -#define BRCMF_E_NDIS_LINK 18 -#define BRCMF_E_ROAM 19 -#define BRCMF_E_TXFAIL 20 -#define BRCMF_E_PMKID_CACHE 21 -#define BRCMF_E_RETROGRADE_TSF 22 -#define BRCMF_E_PRUNE 23 -#define BRCMF_E_AUTOAUTH 24 -#define BRCMF_E_EAPOL_MSG 25 -#define BRCMF_E_SCAN_COMPLETE 26 -#define BRCMF_E_ADDTS_IND 27 -#define BRCMF_E_DELTS_IND 28 -#define BRCMF_E_BCNSENT_IND 29 -#define BRCMF_E_BCNRX_MSG 30 -#define BRCMF_E_BCNLOST_MSG 31 -#define BRCMF_E_ROAM_PREP 32 -#define BRCMF_E_PFN_NET_FOUND 33 -#define BRCMF_E_PFN_NET_LOST 34 -#define BRCMF_E_RESET_COMPLETE 35 -#define BRCMF_E_JOIN_START 36 -#define BRCMF_E_ROAM_START 37 -#define BRCMF_E_ASSOC_START 38 -#define BRCMF_E_IBSS_ASSOC 39 -#define BRCMF_E_RADIO 40 -#define BRCMF_E_PSM_WATCHDOG 41 -#define BRCMF_E_PROBREQ_MSG 44 -#define BRCMF_E_SCAN_CONFIRM_IND 45 -#define BRCMF_E_PSK_SUP 46 -#define BRCMF_E_COUNTRY_CODE_CHANGED 47 -#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48 -#define BRCMF_E_ICV_ERROR 49 -#define BRCMF_E_UNICAST_DECODE_ERROR 50 -#define BRCMF_E_MULTICAST_DECODE_ERROR 51 -#define BRCMF_E_TRACE 52 -#define BRCMF_E_IF 54 -#define BRCMF_E_RSSI 56 -#define BRCMF_E_PFN_SCAN_COMPLETE 57 -#define BRCMF_E_EXTLOG_MSG 58 -#define BRCMF_E_ACTION_FRAME 59 -#define BRCMF_E_ACTION_FRAME_COMPLETE 60 -#define BRCMF_E_PRE_ASSOC_IND 61 -#define BRCMF_E_PRE_REASSOC_IND 62 -#define BRCMF_E_CHANNEL_ADOPTED 63 -#define BRCMF_E_AP_STARTED 64 -#define BRCMF_E_DFS_AP_STOP 65 -#define BRCMF_E_DFS_AP_RESUME 66 -#define BRCMF_E_RESERVED1 67 -#define BRCMF_E_RESERVED2 68 -#define BRCMF_E_ESCAN_RESULT 69 -#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 -#define BRCMF_E_DCS_REQUEST 73 - -#define BRCMF_E_FIFO_CREDIT_MAP 74 - -#define BRCMF_E_LAST 75 - -#define BRCMF_E_STATUS_SUCCESS 0 -#define BRCMF_E_STATUS_FAIL 1 -#define BRCMF_E_STATUS_TIMEOUT 2 -#define BRCMF_E_STATUS_NO_NETWORKS 3 -#define BRCMF_E_STATUS_ABORT 4 -#define BRCMF_E_STATUS_NO_ACK 5 -#define BRCMF_E_STATUS_UNSOLICITED 6 -#define BRCMF_E_STATUS_ATTEMPT 7 -#define BRCMF_E_STATUS_PARTIAL 8 -#define BRCMF_E_STATUS_NEWSCAN 9 -#define BRCMF_E_STATUS_NEWASSOC 10 -#define BRCMF_E_STATUS_11HQUIET 11 -#define BRCMF_E_STATUS_SUPPRESS 12 -#define BRCMF_E_STATUS_NOCHANS 13 -#define BRCMF_E_STATUS_CS_ABORT 15 -#define BRCMF_E_STATUS_ERROR 16 - -#define BRCMF_E_REASON_INITIAL_ASSOC 0 -#define BRCMF_E_REASON_LOW_RSSI 1 -#define BRCMF_E_REASON_DEAUTH 2 -#define BRCMF_E_REASON_DISASSOC 3 -#define BRCMF_E_REASON_BCNS_LOST 4 -#define BRCMF_E_REASON_MINTXRATE 9 -#define BRCMF_E_REASON_TXFAIL 10 - -#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 -#define BRCMF_E_REASON_DIRECTED_ROAM 6 -#define BRCMF_E_REASON_TSPEC_REJECTED 7 -#define BRCMF_E_REASON_BETTER_AP 8 - -#define BRCMF_E_PRUNE_ENCR_MISMATCH 1 -#define BRCMF_E_PRUNE_BCAST_BSSID 2 -#define BRCMF_E_PRUNE_MAC_DENY 3 -#define BRCMF_E_PRUNE_MAC_NA 4 -#define BRCMF_E_PRUNE_REG_PASSV 5 -#define BRCMF_E_PRUNE_SPCT_MGMT 6 -#define BRCMF_E_PRUNE_RADAR 7 -#define BRCMF_E_RSN_MISMATCH 8 -#define BRCMF_E_PRUNE_NO_COMMON_RATES 9 -#define BRCMF_E_PRUNE_BASIC_RATES 10 -#define BRCMF_E_PRUNE_CIPHER_NA 12 -#define BRCMF_E_PRUNE_KNOWN_STA 13 -#define BRCMF_E_PRUNE_WDS_PEER 15 -#define BRCMF_E_PRUNE_QBSS_LOAD 16 -#define BRCMF_E_PRUNE_HOME_AP 17 - -#define BRCMF_E_SUP_OTHER 0 -#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1 -#define BRCMF_E_SUP_BAD_UCAST_WEP128 2 -#define BRCMF_E_SUP_BAD_UCAST_WEP40 3 -#define BRCMF_E_SUP_UNSUP_KEY_LEN 4 -#define BRCMF_E_SUP_PW_KEY_CIPHER 5 -#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6 -#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7 -#define BRCMF_E_SUP_NO_INSTALL_FLAG 8 -#define BRCMF_E_SUP_MSG3_NO_GTK 9 -#define BRCMF_E_SUP_GRP_KEY_CIPHER 10 -#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11 -#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12 -#define BRCMF_E_SUP_SEND_FAIL 13 -#define BRCMF_E_SUP_DEAUTH 14 - -#define BRCMF_E_IF_ADD 1 -#define BRCMF_E_IF_DEL 2 -#define BRCMF_E_IF_CHANGE 3 - -#define BRCMF_E_IF_ROLE_STA 0 -#define BRCMF_E_IF_ROLE_AP 1 -#define BRCMF_E_IF_ROLE_WDS 2 - -#define BRCMF_E_LINK_BCN_LOSS 1 -#define BRCMF_E_LINK_DISASSOC 2 -#define BRCMF_E_LINK_ASSOC_REC 3 -#define BRCMF_E_LINK_BSSCFG_DIS 4 - -/* The level of bus communication with the dongle */ -enum brcmf_bus_state { - BRCMF_BUS_DOWN, /* Not ready for frame transfers */ - BRCMF_BUS_LOAD, /* Download access only (CPU reset) */ - BRCMF_BUS_DATA /* Ready for frame transfers */ -}; - -/* Pattern matching filter. Specifies an offset within received packets to - * start matching, the pattern to match, the size of the pattern, and a bitmask - * that indicates which bits within the pattern should be matched. - */ -struct brcmf_pkt_filter_pattern { - /* - * Offset within received packet to start pattern matching. - * Offset '0' is the first byte of the ethernet header. - */ - u32 offset; - /* Size of the pattern. Bitmask must be the same size.*/ - u32 size_bytes; - /* - * Variable length mask and pattern data. mask starts at offset 0. - * Pattern immediately follows mask. - */ - u8 mask_and_pattern[1]; -}; - -/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ -struct brcmf_pkt_filter { - u32 id; /* Unique filter id, specified by app. */ - u32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ - u32 negate_match; /* Negate the result of filter matches */ - union { /* Filter definitions */ - struct brcmf_pkt_filter_pattern pattern; /* Filter pattern */ - } u; -}; - -/* IOVAR "pkt_filter_enable" parameter. */ -struct brcmf_pkt_filter_enable { - u32 id; /* Unique filter id */ - u32 enable; /* Enable/disable bool */ -}; - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in struct brcmf_scan_results) - */ -struct brcmf_bss_info { - __le32 version; /* version field */ - __le32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - u8 BSSID[ETH_ALEN]; - __le16 beacon_period; /* units are Kusec */ - __le16 capability; /* Capability information */ - u8 SSID_len; - u8 SSID[32]; - struct { - __le32 count; /* # rates in this set */ - u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - __le16 chanspec; /* chanspec for bss */ - __le16 atim_window; /* units are Kusec */ - u8 dtim_period; /* DTIM period */ - __le16 RSSI; /* receive signal strength (in dBm) */ - s8 phy_noise; /* noise (in dBm) */ - - u8 n_cap; /* BSS is 802.11N Capable */ - /* 802.11N BSS Capabilities (based on HT_CAP_*): */ - __le32 nbss_cap; - u8 ctl_ch; /* 802.11N BSS control channel number */ - __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ - u8 flags; /* flags */ - u8 reserved[3]; /* Reserved for expansion of BSS properties */ - u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - __le16 ie_offset; /* offset at which IEs start, from beginning */ - __le32 ie_length; /* byte length of Information Elements */ - __le16 SNR; /* average SNR of during frame reception */ - /* Add new fields here */ - /* variable length Information Elements */ -}; - -struct brcm_rateset_le { - /* # rates in this set */ - __le32 count; - /* rates in 500kbps units w/hi bit set if basic */ - u8 rates[WL_NUMRATES]; -}; - -struct brcmf_ssid { - u32 SSID_len; - unsigned char SSID[32]; -}; - -struct brcmf_ssid_le { - __le32 SSID_len; - unsigned char SSID[32]; -}; - -struct brcmf_scan_params_le { - struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ - u8 bssid[ETH_ALEN]; /* default: bcast */ - s8 bss_type; /* default: any, - * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT - */ - u8 scan_type; /* flags, 0 use default */ - __le32 nprobes; /* -1 use default, number of probes per channel */ - __le32 active_time; /* -1 use default, dwell time per channel for - * active scanning - */ - __le32 passive_time; /* -1 use default, dwell time per channel - * for passive scanning - */ - __le32 home_time; /* -1 use default, dwell time for the - * home channel between channel scans - */ - __le32 channel_num; /* count of channels and ssids that follow - * - * low half is count of channels in - * channel_list, 0 means default (use all - * available channels) - * - * high half is entries in struct brcmf_ssid - * array that follows channel_list, aligned for - * s32 (4 bytes) meaning an odd channel count - * implies a 2-byte pad between end of - * channel_list and first ssid - * - * if ssid count is zero, single ssid in the - * fixed parameter portion is assumed, otherwise - * ssid in the fixed portion is ignored - */ - __le16 channel_list[1]; /* list of chanspecs */ -}; - -/* incremental scan struct */ -struct brcmf_iscan_params_le { - __le32 version; - __le16 action; - __le16 scan_duration; - struct brcmf_scan_params_le params_le; -}; - -struct brcmf_scan_results { - u32 buflen; - u32 version; - u32 count; - struct brcmf_bss_info bss_info[1]; -}; - -struct brcmf_scan_results_le { - __le32 buflen; - __le32 version; - __le32 count; - struct brcmf_bss_info bss_info[1]; -}; - -/* used for association with a specific BSSID and chanspec list */ -struct brcmf_assoc_params_le { - /* 00:00:00:00:00:00: broadcast scan */ - u8 bssid[ETH_ALEN]; - /* 0: all available channels, otherwise count of chanspecs in - * chanspec_list */ - __le32 chanspec_num; - /* list of chanspecs */ - __le16 chanspec_list[1]; -}; - -/* used for join with or without a specific bssid and channel list */ -struct brcmf_join_params { - struct brcmf_ssid_le ssid_le; - struct brcmf_assoc_params_le params_le; -}; - -/* size of brcmf_scan_results not including variable length array */ -#define BRCMF_SCAN_RESULTS_FIXED_SIZE \ - (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info)) - -/* incremental scan results struct */ -struct brcmf_iscan_results { - union { - u32 status; - __le32 status_le; - }; - union { - struct brcmf_scan_results results; - struct brcmf_scan_results_le results_le; - }; -}; - -/* size of brcmf_iscan_results not including variable length array */ -#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \ - (BRCMF_SCAN_RESULTS_FIXED_SIZE + \ - offsetof(struct brcmf_iscan_results, results)) - -struct brcmf_wsec_key { - u32 index; /* key index */ - u32 len; /* key length */ - u8 data[WLAN_MAX_KEY_LEN]; /* key data */ - u32 pad_1[18]; - u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ - u32 flags; /* misc flags */ - u32 pad_2[3]; - u32 iv_initialized; /* has IV been initialized already? */ - u32 pad_3; - /* Rx IV */ - struct { - u32 hi; /* upper 32 bits of IV */ - u16 lo; /* lower 16 bits of IV */ - } rxiv; - u32 pad_4[2]; - u8 ea[ETH_ALEN]; /* per station */ -}; - -/* - * dongle requires same struct as above but with fields in little endian order - */ -struct brcmf_wsec_key_le { - __le32 index; /* key index */ - __le32 len; /* key length */ - u8 data[WLAN_MAX_KEY_LEN]; /* key data */ - __le32 pad_1[18]; - __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ - __le32 flags; /* misc flags */ - __le32 pad_2[3]; - __le32 iv_initialized; /* has IV been initialized already? */ - __le32 pad_3; - /* Rx IV */ - struct { - __le32 hi; /* upper 32 bits of IV */ - __le16 lo; /* lower 16 bits of IV */ - } rxiv; - __le32 pad_4[2]; - u8 ea[ETH_ALEN]; /* per station */ -}; - -/* Used to get specific STA parameters */ -struct brcmf_scb_val_le { - __le32 val; - u8 ea[ETH_ALEN]; -}; - -/* channel encoding */ -struct brcmf_channel_info_le { - __le32 hw_channel; - __le32 target_channel; - __le32 scan_channel; -}; - -/* Bus independent dongle command */ -struct brcmf_dcmd { - uint cmd; /* common dongle cmd definition */ - void *buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - u8 set; /* get or set request (optional) */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ -}; - -/* Forward decls for struct brcmf_pub (see below) */ -struct brcmf_bus; /* device bus info */ -struct brcmf_proto; /* device communication protocol info */ -struct brcmf_info; /* device driver info */ -struct brcmf_cfg80211_dev; /* cfg80211 device info */ - -/* Common structure for module and instance linkage */ -struct brcmf_pub { - /* Linkage ponters */ - struct brcmf_bus *bus; - struct brcmf_proto *prot; - struct brcmf_info *info; - struct brcmf_cfg80211_dev *config; - - /* Internal brcmf items */ - bool up; /* Driver up/down (to OS) */ - bool txoff; /* Transmit flow-controlled */ - enum brcmf_bus_state busstate; - uint hdrlen; /* Total BRCMF header length (proto + bus) */ - uint maxctl; /* Max size rxctl request from proto to bus */ - uint rxsz; /* Rx buffer size bus module should use */ - u8 wme_dp; /* wme discard priority */ - - /* Dongle media info */ - bool iswl; /* Dongle-resident driver is wl */ - unsigned long drv_version; /* Version of dongle-resident driver */ - u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ - struct dngl_stats dstats; /* Stats for dongle-based data */ - - /* Additional stats for the bus level */ - - /* Data packets sent to dongle */ - unsigned long tx_packets; - /* Multicast data packets sent to dongle */ - unsigned long tx_multicast; - /* Errors in sending data to dongle */ - unsigned long tx_errors; - /* Control packets sent to dongle */ - unsigned long tx_ctlpkts; - /* Errors sending control frames to dongle */ - unsigned long tx_ctlerrs; - /* Packets sent up the network interface */ - unsigned long rx_packets; - /* Multicast packets sent up the network interface */ - unsigned long rx_multicast; - /* Errors processing rx data packets */ - unsigned long rx_errors; - /* Control frames processed from dongle */ - unsigned long rx_ctlpkts; - - /* Errors in processing rx control frames */ - unsigned long rx_ctlerrs; - /* Packets dropped locally (no memory) */ - unsigned long rx_dropped; - /* Packets flushed due to unscheduled sendup thread */ - unsigned long rx_flushed; - /* Number of times dpc scheduled by watchdog timer */ - unsigned long wd_dpc_sched; - - /* Number of packets where header read-ahead was used. */ - unsigned long rx_readahead_cnt; - /* Number of tx packets we had to realloc for headroom */ - unsigned long tx_realloc; - /* Number of flow control pkts recvd */ - unsigned long fc_packets; - - /* Last error return */ - int bcmerror; - uint tickcnt; - - /* Last error from dongle */ - int dongle_error; - - /* Suspend disable flag flag */ - int suspend_disable_flag; /* "1" to disable all extra powersaving - during suspend */ - int in_suspend; /* flag set to 1 when early suspend called */ - int dtim_skip; /* dtim skip , default 0 means wake each dtim */ - - /* Pkt filter defination */ - char *pktfilter[100]; - int pktfilter_count; - - u8 country_code[BRCM_CNTRY_BUF_SZ]; - char eventmask[BRCMF_EVENTING_MASK_LEN]; - -}; - -struct brcmf_if_event { - u8 ifidx; - u8 action; - u8 flags; - u8 bssidx; -}; - -struct bcmevent_name { - uint event; - const char *name; -}; - -extern const struct bcmevent_name bcmevent_names[]; - -/* Indication from bus module regarding presence/insertion of dongle. - * Return struct brcmf_pub pointer, used as handle to OS module in later calls. - * Returned structure should have bus and prot pointers filled in. - * bus_hdrlen specifies required headroom for bus module header. - */ -extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, - uint bus_hdrlen); -extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); -extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); - -extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len); - -/* Indication from bus module regarding removal/absence of dongle */ -extern void brcmf_detach(struct brcmf_pub *drvr); - -/* Indication from bus module to change flow-control state */ -extern void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool on); - -extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, - struct sk_buff *pkt, int prec); - -/* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, - struct sk_buff *rxp, int numpkt); - -/* Return pointer to interface name */ -extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); - -/* Notify tx completion */ -extern void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, - bool success); - -/* Query dongle */ -extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, - uint cmd, void *buf, uint len); - -/* OS independent layer functions */ -extern int brcmf_os_proto_block(struct brcmf_pub *drvr); -extern int brcmf_os_proto_unblock(struct brcmf_pub *drvr); -#ifdef BCMDBG -extern int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size); -#endif /* BCMDBG */ - -extern int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name); -extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx, - void *pktdata, struct brcmf_event_msg *, - void **data_ptr); - -extern void brcmf_c_init(void); - -extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, - struct net_device *ndev, char *name, u8 *mac_addr, - u32 flags, u8 bssidx); -extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx); - -/* Send packet to dongle via data channel */ -extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\ - struct sk_buff *pkt); - -extern int brcmf_bus_start(struct brcmf_pub *drvr); - -extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); -extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, - int enable, int master_mode); - -#define BRCMF_DCMD_SMLEN 256 /* "small" cmd buffer required */ -#define BRCMF_DCMD_MEDLEN 1536 /* "med" cmd buffer required */ -#define BRCMF_DCMD_MAXLEN 8192 /* max length cmd buffer required */ - -/* message levels */ -#define BRCMF_ERROR_VAL 0x0001 -#define BRCMF_TRACE_VAL 0x0002 -#define BRCMF_INFO_VAL 0x0004 -#define BRCMF_DATA_VAL 0x0008 -#define BRCMF_CTL_VAL 0x0010 -#define BRCMF_TIMER_VAL 0x0020 -#define BRCMF_HDRS_VAL 0x0040 -#define BRCMF_BYTES_VAL 0x0080 -#define BRCMF_INTR_VAL 0x0100 -#define BRCMF_GLOM_VAL 0x0400 -#define BRCMF_EVENT_VAL 0x0800 -#define BRCMF_BTA_VAL 0x1000 -#define BRCMF_ISCAN_VAL 0x2000 - -/* Enter idle immediately (no timeout) */ -#define BRCMF_IDLE_IMMEDIATE (-1) -#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change - when idle */ -#define BRCMF_IDLE_INTERVAL 1 - -#endif /* _BRCMF_H_ */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h deleted file mode 100644 index a249407c9a1b..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCMF_BUS_H_ -#define _BRCMF_BUS_H_ - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#define BRCMF_SDALIGN (1 << 6) - -/* watchdog polling interval in ms */ -#define BRCMF_WD_POLL_MS 10 - -/* - * Exported from brcmf bus module (brcmf_usb, brcmf_sdio) - */ - -/* Indicate (dis)interest in finding dongles. */ -extern int brcmf_bus_register(void); -extern void brcmf_bus_unregister(void); - -/* obtain linux device object providing bus function */ -extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus); - -/* Stop bus module: clear pending frames, disable data flow */ -extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus); - -/* Initialize bus module: prepare for communication w/dongle */ -extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr); - -/* Send a data frame to the dongle. Callee disposes of txp. */ -extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp); - -/* Send/receive a control message to/from the dongle. - * Expects caller to enforce a single outstanding transaction. - */ -extern int -brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); - -extern int -brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); - -extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick); - -#endif /* _BRCMF_BUS_H_ */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c deleted file mode 100644 index e34c5c3d1d55..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/******************************************************************************* - * Communicates with the dongle by using dcmd codes. - * For certain dcmd codes, the dongle interprets string data from the host. - ******************************************************************************/ - -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/sched.h> -#include <defs.h> - -#include <brcmu_utils.h> -#include <brcmu_wifi.h> - -#include "dhd.h" -#include "dhd_proto.h" -#include "dhd_bus.h" -#include "dhd_dbg.h" - -struct brcmf_proto_cdc_dcmd { - __le32 cmd; /* dongle command value */ - __le32 len; /* lower 16: output buflen; - * upper 16: input buflen (excludes header) */ - __le32 flags; /* flag defns given below */ - __le32 status; /* status code returned from the device */ -}; - -/* Max valid buffer size that can be sent to the dongle */ -#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) - -/* CDC flag definitions */ -#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */ -#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ -#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */ -#define CDC_DCMD_IF_SHIFT 12 -#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ -#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ -#define CDC_DCMD_ID(flags) \ - (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) - -/* - * BDC header - Broadcom specific extension of CDC. - * Used on data packets to convey priority across USB. - */ -#define BDC_HEADER_LEN 4 -#define BDC_PROTO_VER 1 /* Protocol version */ -#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ -#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ -#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ -#define BDC_PRIORITY_MASK 0x7 -#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ -#define BDC_FLAG2_IF_SHIFT 0 - -#define BDC_GET_IF_IDX(hdr) \ - ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) -#define BDC_SET_IF_IDX(hdr, idx) \ - ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ - ((idx) << BDC_FLAG2_IF_SHIFT))) - -struct brcmf_proto_bdc_header { - u8 flags; - u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */ - u8 flags2; - u8 rssi; -}; - - -#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ -#define BUS_HEADER_LEN (16+BRCMF_SDALIGN) /* Must be atleast SDPCM_RESERVE - * (amount of header tha might be added) - * plus any space that might be needed - * for alignment padding. - */ -#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for - * round off at the end of buffer - */ - -struct brcmf_proto { - u16 reqid; - u8 pending; - u32 lastcmd; - u8 bus_header[BUS_HEADER_LEN]; - struct brcmf_proto_cdc_dcmd msg; - unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; -}; - -static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) -{ - struct brcmf_proto *prot = drvr->prot; - int len = le32_to_cpu(prot->msg.len) + - sizeof(struct brcmf_proto_cdc_dcmd); - - brcmf_dbg(TRACE, "Enter\n"); - - /* NOTE : cdc->msg.len holds the desired length of the buffer to be - * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area - * is actually sent to the dongle - */ - if (len > CDC_MAX_MSG_SIZE) - len = CDC_MAX_MSG_SIZE; - - /* Send request */ - return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg, - len); -} - -static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) -{ - int ret; - struct brcmf_proto *prot = drvr->prot; - - brcmf_dbg(TRACE, "Enter\n"); - - do { - ret = brcmf_sdbrcm_bus_rxctl(drvr->bus, - (unsigned char *)&prot->msg, - len + sizeof(struct brcmf_proto_cdc_dcmd)); - if (ret < 0) - break; - } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); - - return ret; -} - -int -brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len) -{ - struct brcmf_proto *prot = drvr->prot; - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; - void *info; - int ret = 0, retries = 0; - u32 id, flags; - - brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == BRCMF_C_GET_VAR && buf) { - if (!strcmp((char *)buf, "bcmerrorstr")) { - strncpy((char *)buf, "bcm_error", - BCME_STRLEN); - goto done; - } else if (!strcmp((char *)buf, "bcmerror")) { - *(int *)buf = drvr->dongle_error; - goto done; - } - } - - memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); - - msg->cmd = cpu_to_le32(cmd); - msg->len = cpu_to_le32(len); - flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); - flags = (flags & ~CDC_DCMD_IF_MASK) | - (ifidx << CDC_DCMD_IF_SHIFT); - msg->flags = cpu_to_le32(flags); - - if (buf) - memcpy(prot->buf, buf, len); - - ret = brcmf_proto_cdc_msg(drvr); - if (ret < 0) { - brcmf_dbg(ERROR, "brcmf_proto_cdc_msg failed w/status %d\n", - ret); - goto done; - } - -retry: - /* wait for interrupt and get first fragment */ - ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); - if (ret < 0) - goto done; - - flags = le32_to_cpu(msg->flags); - id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - - if ((id < prot->reqid) && (++retries < RETRIES)) - goto retry; - if (id != prot->reqid) { - brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n", - brcmf_ifname(drvr, ifidx), id, prot->reqid); - ret = -EINVAL; - goto done; - } - - /* Check info buffer */ - info = (void *)&msg[1]; - - /* Copy info buffer */ - if (buf) { - if (ret < (int)len) - len = ret; - memcpy(buf, info, len); - } - - /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) { - ret = le32_to_cpu(msg->status); - /* Cache error from dongle */ - drvr->dongle_error = ret; - } - -done: - return ret; -} - -int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, - void *buf, uint len) -{ - struct brcmf_proto *prot = drvr->prot; - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; - int ret = 0; - u32 flags, id; - - brcmf_dbg(TRACE, "Enter\n"); - brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); - - memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); - - msg->cmd = cpu_to_le32(cmd); - msg->len = cpu_to_le32(len); - flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; - flags = (flags & ~CDC_DCMD_IF_MASK) | - (ifidx << CDC_DCMD_IF_SHIFT); - msg->flags = cpu_to_le32(flags); - - if (buf) - memcpy(prot->buf, buf, len); - - ret = brcmf_proto_cdc_msg(drvr); - if (ret < 0) - goto done; - - ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); - if (ret < 0) - goto done; - - flags = le32_to_cpu(msg->flags); - id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - - if (id != prot->reqid) { - brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n", - brcmf_ifname(drvr, ifidx), id, prot->reqid); - ret = -EINVAL; - goto done; - } - - /* Check the ERROR flag */ - if (flags & CDC_DCMD_ERROR) { - ret = le32_to_cpu(msg->status); - /* Cache error from dongle */ - drvr->dongle_error = ret; - } - -done: - return ret; -} - -int -brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd, - int len) -{ - struct brcmf_proto *prot = drvr->prot; - int ret = -1; - - if (drvr->busstate == BRCMF_BUS_DOWN) { - brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); - return ret; - } - brcmf_os_proto_block(drvr); - - brcmf_dbg(TRACE, "Enter\n"); - - if (len > BRCMF_DCMD_MAXLEN) - goto done; - - if (prot->pending == true) { - brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", - dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd, - (unsigned long)prot->lastcmd); - if (dcmd->cmd == BRCMF_C_SET_VAR || - dcmd->cmd == BRCMF_C_GET_VAR) - brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf); - - goto done; - } - - prot->pending = true; - prot->lastcmd = dcmd->cmd; - if (dcmd->set) - ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd, - dcmd->buf, len); - else { - ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd, - dcmd->buf, len); - if (ret > 0) - dcmd->used = ret - - sizeof(struct brcmf_proto_cdc_dcmd); - } - - if (ret >= 0) - ret = 0; - else { - struct brcmf_proto_cdc_dcmd *msg = &prot->msg; - /* len == needed when set/query fails from dongle */ - dcmd->needed = le32_to_cpu(msg->len); - } - - /* Intercept the wme_dp dongle cmd here */ - if (!ret && dcmd->cmd == BRCMF_C_SET_VAR && - !strcmp(dcmd->buf, "wme_dp")) { - int slen; - __le32 val = 0; - - slen = strlen("wme_dp") + 1; - if (len >= (int)(slen + sizeof(int))) - memcpy(&val, (char *)dcmd->buf + slen, sizeof(int)); - drvr->wme_dp = (u8) le32_to_cpu(val); - } - - prot->pending = false; - -done: - brcmf_os_proto_unblock(drvr); - - return ret; -} - -static bool pkt_sum_needed(struct sk_buff *skb) -{ - return skb->ip_summed == CHECKSUM_PARTIAL; -} - -static void pkt_set_sum_good(struct sk_buff *skb, bool x) -{ - skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); -} - -void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, - struct sk_buff *pktbuf) -{ - struct brcmf_proto_bdc_header *h; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Push BDC header used to convey priority for buses that don't */ - - skb_push(pktbuf, BDC_HEADER_LEN); - - h = (struct brcmf_proto_bdc_header *)(pktbuf->data); - - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (pkt_sum_needed(pktbuf)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->rssi = 0; - BDC_SET_IF_IDX(h, ifidx); -} - -int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx, - struct sk_buff *pktbuf) -{ - struct brcmf_proto_bdc_header *h; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Pop BDC header used to convey priority for buses that don't */ - - if (pktbuf->len < BDC_HEADER_LEN) { - brcmf_dbg(ERROR, "rx data too short (%d < %d)\n", - pktbuf->len, BDC_HEADER_LEN); - return -EBADE; - } - - h = (struct brcmf_proto_bdc_header *)(pktbuf->data); - - *ifidx = BDC_GET_IF_IDX(h); - if (*ifidx >= BRCMF_MAX_IFS) { - brcmf_dbg(ERROR, "rx data ifnum out of range (%d)\n", *ifidx); - return -EBADE; - } - - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != - BDC_PROTO_VER) { - brcmf_dbg(ERROR, "%s: non-BDC packet received, flags 0x%x\n", - brcmf_ifname(drvr, *ifidx), h->flags); - return -EBADE; - } - - if (h->flags & BDC_FLAG_SUM_GOOD) { - brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n", - brcmf_ifname(drvr, *ifidx), h->flags); - pkt_set_sum_good(pktbuf, true); - } - - pktbuf->priority = h->priority & BDC_PRIORITY_MASK; - - skb_pull(pktbuf, BDC_HEADER_LEN); - - return 0; -} - -int brcmf_proto_attach(struct brcmf_pub *drvr) -{ - struct brcmf_proto *cdc; - - cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); - if (!cdc) - goto fail; - - /* ensure that the msg buf directly follows the cdc msg struct */ - if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { - brcmf_dbg(ERROR, "struct brcmf_proto is not correctly defined\n"); - goto fail; - } - - drvr->prot = cdc; - drvr->hdrlen += BDC_HEADER_LEN; - drvr->maxctl = BRCMF_DCMD_MAXLEN + - sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; - return 0; - -fail: - kfree(cdc); - return -ENOMEM; -} - -/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -void brcmf_proto_detach(struct brcmf_pub *drvr) -{ - kfree(drvr->prot); - drvr->prot = NULL; -} - -void brcmf_proto_dstats(struct brcmf_pub *drvr) -{ - /* No stats from dongle added yet, copy bus stats */ - drvr->dstats.tx_packets = drvr->tx_packets; - drvr->dstats.tx_errors = drvr->tx_errors; - drvr->dstats.rx_packets = drvr->rx_packets; - drvr->dstats.rx_errors = drvr->rx_errors; - drvr->dstats.rx_dropped = drvr->rx_dropped; - drvr->dstats.multicast = drvr->rx_multicast; - return; -} - -int brcmf_proto_init(struct brcmf_pub *drvr) -{ - int ret = 0; - char buf[128]; - - brcmf_dbg(TRACE, "Enter\n"); - - brcmf_os_proto_block(drvr); - - /* Get the device MAC address */ - strcpy(buf, "cur_etheraddr"); - ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, - buf, sizeof(buf)); - if (ret < 0) { - brcmf_os_proto_unblock(drvr); - return ret; - } - memcpy(drvr->mac, buf, ETH_ALEN); - - brcmf_os_proto_unblock(drvr); - - ret = brcmf_c_preinit_dcmds(drvr); - - /* Always assumes wl for now */ - drvr->iswl = true; - - return ret; -} - -void brcmf_proto_stop(struct brcmf_pub *drvr) -{ - /* Nothing to do for CDC */ -} diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c deleted file mode 100644 index 4075fd74dd92..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/sched.h> -#include <linux/netdevice.h> -#include <asm/unaligned.h> -#include <defs.h> -#include <brcmu_wifi.h> -#include <brcmu_utils.h> -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_proto.h" -#include "dhd_dbg.h" - -#define BRCM_OUI "\x00\x10\x18" -#define DOT11_OUI_LEN 3 -#define BCMILCP_BCM_SUBTYPE_EVENT 1 -#define PKTFILTER_BUF_SIZE 2048 -#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ - -int brcmf_msg_level; - -#define MSGTRACE_VERSION 1 - -#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter, u) -#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \ - offsetof(struct brcmf_pkt_filter_pattern, mask_and_pattern) - -#ifdef BCMDBG -static const char brcmf_version[] = - "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " - __DATE__ " at " __TIME__; -#else -static const char brcmf_version[] = - "Dongle Host Driver, version " BRCMF_VERSION_STR; -#endif - -/* Message trace header */ -struct msgtrace_hdr { - u8 version; - u8 spare; - __be16 len; /* Len of the trace */ - __be32 seqnum; /* Sequence number of message. Useful - * if the messsage has been lost - * because of DMA error or a bus reset - * (ex: SDIO Func2) - */ - __be32 discarded_bytes; /* Number of discarded bytes because of - trace overflow */ - __be32 discarded_printf; /* Number of discarded printf - because of trace overflow */ -} __packed; - -void brcmf_c_init(void) -{ - /* Init global variables at run-time, not as part of the declaration. - * This is required to support init/de-init of the driver. - * Initialization - * of globals as part of the declaration results in non-deterministic - * behaviour since the value of the globals may be different on the - * first time that the driver is initialized vs subsequent - * initializations. - */ - brcmf_msg_level = BRCMF_ERROR_VAL; -} - -bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, - struct sk_buff *pkt, int prec) -{ - struct sk_buff *p; - int eprec = -1; /* precedence to evict from */ - bool discard_oldest; - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(q, prec) && !pktq_full(q)) { - brcmu_pktq_penq(q, prec, pkt); - return true; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(q, prec)) - eprec = prec; - else if (pktq_full(q)) { - p = brcmu_pktq_peek_tail(q, &eprec); - if (eprec > prec) - return false; - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return false; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : - brcmu_pktq_pdeq_tail(q, eprec); - if (p == NULL) - brcmf_dbg(ERROR, "brcmu_pktq_penq() failed, oldest %d\n", - discard_oldest); - - brcmu_pkt_buf_free_skb(p); - } - - /* Enqueue */ - p = brcmu_pktq_penq(q, prec, pkt); - if (p == NULL) - brcmf_dbg(ERROR, "brcmu_pktq_penq() failed\n"); - - return p != NULL; -} - -#ifdef BCMDBG -static void -brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) -{ - uint i, status, reason; - bool group = false, flush_txq = false, link = false; - char *auth_str, *event_name; - unsigned char *buf; - char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - static struct { - uint event; - char *event_name; - } event_names[] = { - { - BRCMF_E_SET_SSID, "SET_SSID"}, { - BRCMF_E_JOIN, "JOIN"}, { - BRCMF_E_START, "START"}, { - BRCMF_E_AUTH, "AUTH"}, { - BRCMF_E_AUTH_IND, "AUTH_IND"}, { - BRCMF_E_DEAUTH, "DEAUTH"}, { - BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, { - BRCMF_E_ASSOC, "ASSOC"}, { - BRCMF_E_ASSOC_IND, "ASSOC_IND"}, { - BRCMF_E_REASSOC, "REASSOC"}, { - BRCMF_E_REASSOC_IND, "REASSOC_IND"}, { - BRCMF_E_DISASSOC, "DISASSOC"}, { - BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, { - BRCMF_E_QUIET_START, "START_QUIET"}, { - BRCMF_E_QUIET_END, "END_QUIET"}, { - BRCMF_E_BEACON_RX, "BEACON_RX"}, { - BRCMF_E_LINK, "LINK"}, { - BRCMF_E_MIC_ERROR, "MIC_ERROR"}, { - BRCMF_E_NDIS_LINK, "NDIS_LINK"}, { - BRCMF_E_ROAM, "ROAM"}, { - BRCMF_E_TXFAIL, "TXFAIL"}, { - BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, { - BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, { - BRCMF_E_PRUNE, "PRUNE"}, { - BRCMF_E_AUTOAUTH, "AUTOAUTH"}, { - BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, { - BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, { - BRCMF_E_ADDTS_IND, "ADDTS_IND"}, { - BRCMF_E_DELTS_IND, "DELTS_IND"}, { - BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, { - BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, { - BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, { - BRCMF_E_ROAM_PREP, "ROAM_PREP"}, { - BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, { - BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, { - BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, { - BRCMF_E_JOIN_START, "JOIN_START"}, { - BRCMF_E_ROAM_START, "ROAM_START"}, { - BRCMF_E_ASSOC_START, "ASSOC_START"}, { - BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, { - BRCMF_E_RADIO, "RADIO"}, { - BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, { - BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, { - BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, { - BRCMF_E_PSK_SUP, "PSK_SUP"}, { - BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, { - BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, { - BRCMF_E_ICV_ERROR, "ICV_ERROR"}, { - BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, { - BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, { - BRCMF_E_TRACE, "TRACE"}, { - BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, { - BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, { - BRCMF_E_IF, "IF"}, { - BRCMF_E_RSSI, "RSSI"}, { - BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} - }; - uint event_type, flags, auth_type, datalen; - static u32 seqnum_prev; - struct msgtrace_hdr hdr; - u32 nblost; - char *s, *p; - - event_type = be32_to_cpu(event->event_type); - flags = be16_to_cpu(event->flags); - status = be32_to_cpu(event->status); - reason = be32_to_cpu(event->reason); - auth_type = be32_to_cpu(event->auth_type); - datalen = be32_to_cpu(event->datalen); - /* debug dump of event messages */ - sprintf(eabuf, "%pM", event->addr); - - event_name = "UNKNOWN"; - for (i = 0; i < ARRAY_SIZE(event_names); i++) { - if (event_names[i].event == event_type) - event_name = event_names[i].event_name; - } - - brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type); - brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n", - flags, status, reason, auth_type, eabuf); - - if (flags & BRCMF_EVENT_MSG_LINK) - link = true; - if (flags & BRCMF_EVENT_MSG_GROUP) - group = true; - if (flags & BRCMF_EVENT_MSG_FLUSHTXQ) - flush_txq = true; - - switch (event_type) { - case BRCMF_E_START: - case BRCMF_E_DEAUTH: - case BRCMF_E_DISASSOC: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); - break; - - case BRCMF_E_ASSOC_IND: - case BRCMF_E_REASSOC_IND: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); - break; - - case BRCMF_E_ASSOC: - case BRCMF_E_REASSOC: - if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n", - event_name, eabuf); - else if (status == BRCMF_E_STATUS_TIMEOUT) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n", - event_name, eabuf); - else if (status == BRCMF_E_STATUS_FAIL) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n", - event_name, eabuf, (int)reason); - else - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n", - event_name, eabuf, (int)status); - break; - - case BRCMF_E_DEAUTH_IND: - case BRCMF_E_DISASSOC_IND: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n", - event_name, eabuf, (int)reason); - break; - - case BRCMF_E_AUTH: - case BRCMF_E_AUTH_IND: - if (auth_type == WLAN_AUTH_OPEN) - auth_str = "Open System"; - else if (auth_type == WLAN_AUTH_SHARED_KEY) - auth_str = "Shared Key"; - else { - sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); - auth_str = err_msg; - } - if (event_type == BRCMF_E_AUTH_IND) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n", - event_name, eabuf, auth_str); - else if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n", - event_name, eabuf, auth_str); - else if (status == BRCMF_E_STATUS_TIMEOUT) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n", - event_name, eabuf, auth_str); - else if (status == BRCMF_E_STATUS_FAIL) { - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", - event_name, eabuf, auth_str, (int)reason); - } - - break; - - case BRCMF_E_JOIN: - case BRCMF_E_ROAM: - case BRCMF_E_SET_SSID: - if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", - event_name, eabuf); - else if (status == BRCMF_E_STATUS_FAIL) - brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name); - else if (status == BRCMF_E_STATUS_NO_NETWORKS) - brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n", - event_name); - else - brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n", - event_name, (int)status); - break; - - case BRCMF_E_BEACON_RX: - if (status == BRCMF_E_STATUS_SUCCESS) - brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name); - else if (status == BRCMF_E_STATUS_FAIL) - brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name); - else - brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n", - event_name, status); - break; - - case BRCMF_E_LINK: - brcmf_dbg(EVENT, "MACEVENT: %s %s\n", - event_name, link ? "UP" : "DOWN"); - break; - - case BRCMF_E_MIC_ERROR: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n", - event_name, eabuf, group, flush_txq); - break; - - case BRCMF_E_ICV_ERROR: - case BRCMF_E_UNICAST_DECODE_ERROR: - case BRCMF_E_MULTICAST_DECODE_ERROR: - brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); - break; - - case BRCMF_E_TXFAIL: - brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf); - break; - - case BRCMF_E_SCAN_COMPLETE: - case BRCMF_E_PMKID_CACHE: - brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); - break; - - case BRCMF_E_PFN_NET_FOUND: - case BRCMF_E_PFN_NET_LOST: - case BRCMF_E_PFN_SCAN_COMPLETE: - brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name); - break; - - case BRCMF_E_PSK_SUP: - case BRCMF_E_PRUNE: - brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason); - break; - - case BRCMF_E_TRACE: - buf = (unsigned char *) event_data; - memcpy(&hdr, buf, sizeof(struct msgtrace_hdr)); - - if (hdr.version != MSGTRACE_VERSION) { - brcmf_dbg(ERROR, - "MACEVENT: %s [unsupported version --> brcmf" - " version:%d dongle version:%d]\n", - event_name, MSGTRACE_VERSION, hdr.version); - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - /* There are 2 bytes available at the end of data */ - *(buf + sizeof(struct msgtrace_hdr) - + be16_to_cpu(hdr.len)) = '\0'; - - if (be32_to_cpu(hdr.discarded_bytes) - || be32_to_cpu(hdr.discarded_printf)) - brcmf_dbg(ERROR, - "WLC_E_TRACE: [Discarded traces in dongle -->" - " discarded_bytes %d discarded_printf %d]\n", - be32_to_cpu(hdr.discarded_bytes), - be32_to_cpu(hdr.discarded_printf)); - - nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) - brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum " - " %d nblost %d\n", be32_to_cpu(hdr.seqnum), - nblost); - seqnum_prev = be32_to_cpu(hdr.seqnum); - - /* Display the trace buffer. Advance from \n to \n to - * avoid display big - * printf (issue with Linux printk ) - */ - p = (char *)&buf[sizeof(struct msgtrace_hdr)]; - while ((s = strstr(p, "\n")) != NULL) { - *s = '\0'; - printk(KERN_DEBUG"%s\n", p); - p = s + 1; - } - printk(KERN_DEBUG "%s\n", p); - - /* Reset datalen to avoid display below */ - datalen = 0; - break; - - case BRCMF_E_RSSI: - brcmf_dbg(EVENT, "MACEVENT: %s %d\n", - event_name, be32_to_cpu(*((__be32 *)event_data))); - break; - - default: - brcmf_dbg(EVENT, - "MACEVENT: %s %d, MAC %s, status %d, reason %d, " - "auth %d\n", event_name, event_type, eabuf, - (int)status, (int)reason, (int)auth_type); - break; - } - - /* show any appended data */ - if (datalen) { - buf = (unsigned char *) event_data; - brcmf_dbg(EVENT, " data (%d) : ", datalen); - for (i = 0; i < datalen; i++) - brcmf_dbg(EVENT, " 0x%02x ", *buf++); - brcmf_dbg(EVENT, "\n"); - } -} -#endif /* BCMDBG */ - -int -brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, - struct brcmf_event_msg *event, void **data_ptr) -{ - /* check whether packet is a BRCM event pkt */ - struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; - struct brcmf_if_event *ifevent; - char *event_data; - u32 type, status; - u16 flags; - int evlen; - - if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { - brcmf_dbg(ERROR, "mismatched OUI, bailing\n"); - return -EBADE; - } - - /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ - if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != - BCMILCP_BCM_SUBTYPE_EVENT) { - brcmf_dbg(ERROR, "mismatched subtype, bailing\n"); - return -EBADE; - } - - *data_ptr = &pvt_data[1]; - event_data = *data_ptr; - - /* memcpy since BRCM event pkt may be unaligned. */ - memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); - - type = get_unaligned_be32(&event->event_type); - flags = get_unaligned_be16(&event->flags); - status = get_unaligned_be32(&event->status); - evlen = get_unaligned_be32(&event->datalen) + - sizeof(struct brcmf_event); - - switch (type) { - case BRCMF_E_IF: - ifevent = (struct brcmf_if_event *) event_data; - brcmf_dbg(TRACE, "if event\n"); - - if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { - if (ifevent->action == BRCMF_E_IF_ADD) - brcmf_add_if(drvr_priv, ifevent->ifidx, NULL, - event->ifname, - pvt_data->eth.h_dest, - ifevent->flags, ifevent->bssidx); - else - brcmf_del_if(drvr_priv, ifevent->ifidx); - } else { - brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n", - ifevent->ifidx, event->ifname); - } - - /* send up the if event: btamp user needs it */ - *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); - break; - - /* These are what external supplicant/authenticator wants */ - case BRCMF_E_LINK: - case BRCMF_E_ASSOC_IND: - case BRCMF_E_REASSOC_IND: - case BRCMF_E_DISASSOC_IND: - case BRCMF_E_MIC_ERROR: - default: - /* Fall through: this should get _everything_ */ - - *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); - brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n", - type, flags, status); - - /* put it back to BRCMF_E_NDIS_LINK */ - if (type == BRCMF_E_NDIS_LINK) { - u32 temp1; - __be32 temp2; - - temp1 = get_unaligned_be32(&event->event_type); - brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n", - temp1); - - temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK); - memcpy((void *)(&pvt_data->msg.event_type), &temp2, - sizeof(pvt_data->msg.event_type)); - } - break; - } - -#ifdef BCMDBG - brcmf_c_show_host_event(event, event_data); -#endif /* BCMDBG */ - - return 0; -} - -/* Convert user's input in hex pattern to byte-size mask */ -static int brcmf_c_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { - brcmf_dbg(ERROR, "Mask invalid format. Needs to start with 0x\n"); - return -EINVAL; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - brcmf_dbg(ERROR, "Mask invalid format. Length must be even.\n"); - return -EINVAL; - } - for (i = 0; *src != '\0'; i++) { - unsigned long res; - char num[3]; - strncpy(num, src, 2); - num[2] = '\0'; - if (kstrtoul(num, 16, &res)) - return -EINVAL; - dst[i] = (u8)res; - src += 2; - } - return i; -} - -void -brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable, - int master_mode) -{ - unsigned long res; - char *argv[8]; - int i = 0; - const char *str; - int buf_len; - int str_len; - char *arg_save = NULL, *arg_org = NULL; - int rc; - char buf[128]; - struct brcmf_pkt_filter_enable enable_parm; - struct brcmf_pkt_filter_enable *pkt_filterp; - - arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC); - if (!arg_save) - goto fail; - - arg_org = arg_save; - memcpy(arg_save, arg, strlen(arg) + 1); - - argv[i] = strsep(&arg_save, " "); - - i = 0; - if (NULL == argv[i]) { - brcmf_dbg(ERROR, "No args provided\n"); - goto fail; - } - - str = "pkt_filter_enable"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[str_len] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (struct brcmf_pkt_filter_enable *) (buf + str_len + 1); - - /* Parse packet filter id. */ - enable_parm.id = 0; - if (!kstrtoul(argv[i], 0, &res)) - enable_parm.id = (u32)res; - - /* Parse enable/disable value. */ - enable_parm.enable = enable; - - buf_len += sizeof(enable_parm); - memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm)); - - /* Enable/disable the specified filter. */ - rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); - rc = rc >= 0 ? 0 : rc; - if (rc) - brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", - arg, rc); - else - brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); - - /* Contorl the master mode */ - brcmu_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, - sizeof(buf)); - rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, - sizeof(buf)); - rc = rc >= 0 ? 0 : rc; - if (rc) - brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", - arg, rc); - -fail: - kfree(arg_org); -} - -void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg) -{ - const char *str; - struct brcmf_pkt_filter pkt_filter; - struct brcmf_pkt_filter *pkt_filterp; - unsigned long res; - int buf_len; - int str_len; - int rc; - u32 mask_size; - u32 pattern_size; - char *argv[8], *buf = NULL; - int i = 0; - char *arg_save = NULL, *arg_org = NULL; - - arg_save = kstrdup(arg, GFP_ATOMIC); - if (!arg_save) - goto fail; - - arg_org = arg_save; - - buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC); - if (!buf) - goto fail; - - argv[i] = strsep(&arg_save, " "); - while (argv[i++]) - argv[i] = strsep(&arg_save, " "); - - i = 0; - if (NULL == argv[i]) { - brcmf_dbg(ERROR, "No args provided\n"); - goto fail; - } - - str = "pkt_filter_add"; - strcpy(buf, str); - str_len = strlen(str); - buf_len = str_len + 1; - - pkt_filterp = (struct brcmf_pkt_filter *) (buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = 0; - if (!kstrtoul(argv[i], 0, &res)) - pkt_filter.id = (u32)res; - - if (NULL == argv[++i]) { - brcmf_dbg(ERROR, "Polarity not provided\n"); - goto fail; - } - - /* Parse filter polarity. */ - pkt_filter.negate_match = 0; - if (!kstrtoul(argv[i], 0, &res)) - pkt_filter.negate_match = (u32)res; - - if (NULL == argv[++i]) { - brcmf_dbg(ERROR, "Filter type not provided\n"); - goto fail; - } - - /* Parse filter type. */ - pkt_filter.type = 0; - if (!kstrtoul(argv[i], 0, &res)) - pkt_filter.type = (u32)res; - - if (NULL == argv[++i]) { - brcmf_dbg(ERROR, "Offset not provided\n"); - goto fail; - } - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = 0; - if (!kstrtoul(argv[i], 0, &res)) - pkt_filter.u.pattern.offset = (u32)res; - - if (NULL == argv[++i]) { - brcmf_dbg(ERROR, "Bitmask not provided\n"); - goto fail; - } - - /* Parse pattern filter mask. */ - mask_size = - brcmf_c_pattern_atoh - (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern); - - if (NULL == argv[++i]) { - brcmf_dbg(ERROR, "Pattern not provided\n"); - goto fail; - } - - /* Parse pattern filter pattern. */ - pattern_size = - brcmf_c_pattern_atoh(argv[i], - (char *)&pkt_filterp->u.pattern. - mask_and_pattern[mask_size]); - - if (mask_size != pattern_size) { - brcmf_dbg(ERROR, "Mask and pattern not the same size\n"); - goto fail; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += BRCMF_PKT_FILTER_FIXED_LEN; - buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - - /* Keep-alive attributes are set in local - * variable (keep_alive_pkt), and - ** then memcpy'ed into buffer (keep_alive_pktp) since there is no - ** guarantee that the buffer is properly aligned. - */ - memcpy((char *)pkt_filterp, - &pkt_filter, - BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN); - - rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); - rc = rc >= 0 ? 0 : rc; - - if (rc) - brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", - arg, rc); - else - brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); - -fail: - kfree(arg_org); - - kfree(buf); -} - -static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) -{ - char iovbuf[32]; - int retcode; - - brcmu_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); - retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, - iovbuf, sizeof(iovbuf)); - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n", - arp_mode, retcode); - else - brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n", - arp_mode); -} - -static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) -{ - char iovbuf[32]; - int retcode; - - brcmu_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); - retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, - iovbuf, sizeof(iovbuf)); - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n", - arp_enable, retcode); - else - brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n", - arp_enable); -} - -int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) -{ - char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for - "event_msgs" + '\0' + bitvec */ - uint up = 0; - char buf[128], *ptr; - u32 dongle_align = BRCMF_SDALIGN; - u32 glom = 0; - u32 roaming = 1; - uint bcn_timeout = 3; - int scan_assoc_time = 40; - int scan_unassoc_time = 40; - int i; - - brcmf_os_proto_block(drvr); - - /* Set Country code */ - if (drvr->country_code[0] != 0) { - if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY, - drvr->country_code, - sizeof(drvr->country_code)) < 0) - brcmf_dbg(ERROR, "country code setting failed\n"); - } - - /* query for 'ver' to get version info from firmware */ - memset(buf, 0, sizeof(buf)); - ptr = buf; - brcmu_mkiovar("ver", NULL, 0, buf, sizeof(buf)); - brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf)); - strsep(&ptr, "\n"); - /* Print fw version info */ - brcmf_dbg(ERROR, "Firmware version = %s\n", buf); - - /* Match Host and Dongle rx alignment */ - brcmu_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, - sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - /* disable glom option per default */ - brcmu_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - /* Setup timeout if Beacons are lost and roam is off to report - link down */ - brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, - sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - /* Enable/Disable build-in roaming to allowed ext supplicant to take - of romaing */ - brcmu_mkiovar("roam_off", (char *)&roaming, 4, - iovbuf, sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - /* Force STA UP */ - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); - - /* Setup event_msgs */ - brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, - iovbuf, sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, - (char *)&scan_assoc_time, sizeof(scan_assoc_time)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, - (char *)&scan_unassoc_time, sizeof(scan_unassoc_time)); - - /* Set and enable ARP offload feature */ - brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); - brcmf_c_arp_offload_enable(drvr, true); - - /* Set up pkt filter */ - for (i = 0; i < drvr->pktfilter_count; i++) { - brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]); - brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i], - 0, true); - } - - brcmf_os_proto_unblock(drvr); - - return 0; -} diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h b/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h deleted file mode 100644 index 7467922f0536..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCMF_DBG_H_ -#define _BRCMF_DBG_H_ - -#if defined(BCMDBG) - -#define brcmf_dbg(level, fmt, ...) \ -do { \ - if (BRCMF_ERROR_VAL == BRCMF_##level##_VAL) { \ - if (brcmf_msg_level & BRCMF_##level##_VAL) { \ - if (net_ratelimit()) \ - printk(KERN_DEBUG "%s: " fmt, \ - __func__, ##__VA_ARGS__); \ - } \ - } else { \ - if (brcmf_msg_level & BRCMF_##level##_VAL) { \ - printk(KERN_DEBUG "%s: " fmt, \ - __func__, ##__VA_ARGS__); \ - } \ - } \ -} while (0) - -#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL) -#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL) -#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) -#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) -#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) - -#else /* (defined BCMDBG) || (defined BCMDBG) */ - -#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__) - -#define BRCMF_DATA_ON() 0 -#define BRCMF_CTL_ON() 0 -#define BRCMF_HDRS_ON() 0 -#define BRCMF_BYTES_ON() 0 -#define BRCMF_GLOM_ON() 0 - -#endif /* defined(BCMDBG) */ - -extern int brcmf_msg_level; - -#endif /* _BRCMF_DBG_H_ */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c deleted file mode 100644 index 99ba5e3e45fa..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ /dev/null @@ -1,1354 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/kthread.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/mmc/sdio_func.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/hardirq.h> -#include <linux/mutex.h> -#include <linux/wait.h> -#include <net/cfg80211.h> -#include <net/rtnetlink.h> -#include <defs.h> -#include <brcmu_utils.h> -#include <brcmu_wifi.h> - -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_proto.h" -#include "dhd_dbg.h" -#include "wl_cfg80211.h" -#include "bcmchip.h" - -MODULE_AUTHOR("Broadcom Corporation"); -MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); -MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards"); -MODULE_LICENSE("Dual BSD/GPL"); - - -/* Interface control information */ -struct brcmf_if { - struct brcmf_info *info; /* back pointer to brcmf_info */ - /* OS/stack specifics */ - struct net_device *ndev; - struct net_device_stats stats; - int idx; /* iface idx in dongle */ - int state; /* interface state */ - u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ -}; - -/* Local private structure (extension of pub) */ -struct brcmf_info { - struct brcmf_pub pub; - - /* OS/stack specifics */ - struct brcmf_if *iflist[BRCMF_MAX_IFS]; - - struct mutex proto_block; - - struct work_struct setmacaddr_work; - struct work_struct multicast_work; - u8 macvalue[ETH_ALEN]; - atomic_t pend_8021x_cnt; -}; - -/* Error bits */ -module_param(brcmf_msg_level, int, 0); - - -static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev) -{ - int i = 0; - - while (i < BRCMF_MAX_IFS) { - if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev) - return i; - i++; - } - - return BRCMF_BAD_IF; -} - -int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) -{ - int i = BRCMF_MAX_IFS; - struct brcmf_if *ifp; - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) { - ifp = drvr_priv->iflist[i]; - if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ)) - break; - } - - brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name); - - return i; /* default - the primary interface */ -} - -char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) -{ - struct brcmf_info *drvr_priv = drvr->info; - - if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { - brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx); - return "<if_bad>"; - } - - if (drvr_priv->iflist[ifidx] == NULL) { - brcmf_dbg(ERROR, "null i/f %d\n", ifidx); - return "<if_null>"; - } - - if (drvr_priv->iflist[ifidx]->ndev) - return drvr_priv->iflist[ifidx]->ndev->name; - - return "<if_none>"; -} - -static void _brcmf_set_multicast_list(struct work_struct *work) -{ - struct net_device *ndev; - struct netdev_hw_addr *ha; - u32 allmulti, cnt; - __le32 cnt_le; - __le32 allmulti_le; - - struct brcmf_dcmd dcmd; - char *buf, *bufp; - uint buflen; - int ret; - - struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info, - multicast_work); - - ndev = drvr_priv->iflist[0]->ndev; - cnt = netdev_mc_count(ndev); - - /* Determine initial value of allmulti flag */ - allmulti = (ndev->flags & IFF_ALLMULTI) ? true : false; - - /* Send down the multicast list first. */ - - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN); - bufp = buf = kmalloc(buflen, GFP_ATOMIC); - if (!bufp) - return; - - strcpy(bufp, "mcast_list"); - bufp += strlen("mcast_list") + 1; - - cnt_le = cpu_to_le32(cnt); - memcpy(bufp, &cnt_le, sizeof(cnt)); - bufp += sizeof(cnt_le); - - netdev_for_each_mc_addr(ha, ndev) { - if (!cnt) - break; - memcpy(bufp, ha->addr, ETH_ALEN); - bufp += ETH_ALEN; - cnt--; - } - - memset(&dcmd, 0, sizeof(dcmd)); - dcmd.cmd = BRCMF_C_SET_VAR; - dcmd.buf = buf; - dcmd.len = buflen; - dcmd.set = true; - - ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n", - brcmf_ifname(&drvr_priv->pub, 0), cnt); - allmulti = cnt ? true : allmulti; - } - - kfree(buf); - - /* Now send the allmulti setting. This is based on the setting in the - * net_device flags, but might be modified above to be turned on if we - * were trying to set some addresses and dongle rejected it... - */ - - buflen = sizeof("allmulti") + sizeof(allmulti); - buf = kmalloc(buflen, GFP_ATOMIC); - if (!buf) - return; - - allmulti_le = cpu_to_le32(allmulti); - - if (!brcmu_mkiovar - ("allmulti", (void *)&allmulti_le, - sizeof(allmulti_le), buf, buflen)) { - brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n", - brcmf_ifname(&drvr_priv->pub, 0), - (int)sizeof(allmulti), buflen); - kfree(buf); - return; - } - - memset(&dcmd, 0, sizeof(dcmd)); - dcmd.cmd = BRCMF_C_SET_VAR; - dcmd.buf = buf; - dcmd.len = buflen; - dcmd.set = true; - - ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: set allmulti %d failed\n", - brcmf_ifname(&drvr_priv->pub, 0), - le32_to_cpu(allmulti_le)); - } - - kfree(buf); - - /* Finally, pick up the PROMISC flag as well, like the NIC - driver does */ - - allmulti = (ndev->flags & IFF_PROMISC) ? true : false; - allmulti_le = cpu_to_le32(allmulti); - - memset(&dcmd, 0, sizeof(dcmd)); - dcmd.cmd = BRCMF_C_SET_PROMISC; - dcmd.buf = &allmulti_le; - dcmd.len = sizeof(allmulti_le); - dcmd.set = true; - - ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: set promisc %d failed\n", - brcmf_ifname(&drvr_priv->pub, 0), - le32_to_cpu(allmulti_le)); - } -} - -static void -_brcmf_set_mac_address(struct work_struct *work) -{ - char buf[32]; - struct brcmf_dcmd dcmd; - int ret; - - struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info, - setmacaddr_work); - - brcmf_dbg(TRACE, "enter\n"); - if (!brcmu_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue, - ETH_ALEN, buf, 32)) { - brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n", - brcmf_ifname(&drvr_priv->pub, 0)); - return; - } - memset(&dcmd, 0, sizeof(dcmd)); - dcmd.cmd = BRCMF_C_SET_VAR; - dcmd.buf = buf; - dcmd.len = 32; - dcmd.set = true; - - ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); - if (ret < 0) - brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n", - brcmf_ifname(&drvr_priv->pub, 0)); - else - memcpy(drvr_priv->iflist[0]->ndev->dev_addr, - drvr_priv->macvalue, ETH_ALEN); - - return; -} - -static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - struct sockaddr *sa = (struct sockaddr *)addr; - int ifidx; - - ifidx = brcmf_net2idx(drvr_priv, ndev); - if (ifidx == BRCMF_BAD_IF) - return -1; - - memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN); - schedule_work(&drvr_priv->setmacaddr_work); - return 0; -} - -static void brcmf_netdev_set_multicast_list(struct net_device *ndev) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - int ifidx; - - ifidx = brcmf_net2idx(drvr_priv, ndev); - if (ifidx == BRCMF_BAD_IF) - return; - - schedule_work(&drvr_priv->multicast_work); -} - -int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) -{ - struct brcmf_info *drvr_priv = drvr->info; - - /* Reject if down */ - if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) - return -ENODEV; - - /* Update multicast statistic */ - if (pktbuf->len >= ETH_ALEN) { - u8 *pktdata = (u8 *) (pktbuf->data); - struct ethhdr *eh = (struct ethhdr *)pktdata; - - if (is_multicast_ether_addr(eh->h_dest)) - drvr->tx_multicast++; - if (ntohs(eh->h_proto) == ETH_P_PAE) - atomic_inc(&drvr_priv->pend_8021x_cnt); - } - - /* If the protocol uses a data header, apply it */ - brcmf_proto_hdrpush(drvr, ifidx, pktbuf); - - /* Use bus module to send data frame */ - return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); -} - -static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - int ret; - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - int ifidx; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Reject if down */ - if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { - brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", - drvr_priv->pub.up, drvr_priv->pub.busstate); - netif_stop_queue(ndev); - return -ENODEV; - } - - ifidx = brcmf_net2idx(drvr_priv, ndev); - if (ifidx == BRCMF_BAD_IF) { - brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx); - netif_stop_queue(ndev); - return -ENODEV; - } - - /* Make sure there's enough room for any header */ - if (skb_headroom(skb) < drvr_priv->pub.hdrlen) { - struct sk_buff *skb2; - - brcmf_dbg(INFO, "%s: insufficient headroom\n", - brcmf_ifname(&drvr_priv->pub, ifidx)); - drvr_priv->pub.tx_realloc++; - skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen); - dev_kfree_skb(skb); - skb = skb2; - if (skb == NULL) { - brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n", - brcmf_ifname(&drvr_priv->pub, ifidx)); - ret = -ENOMEM; - goto done; - } - } - - ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb); - -done: - if (ret) - drvr_priv->pub.dstats.tx_dropped++; - else - drvr_priv->pub.tx_packets++; - - /* Return ok: we always eat the packet */ - return 0; -} - -void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state) -{ - struct net_device *ndev; - struct brcmf_info *drvr_priv = drvr->info; - - brcmf_dbg(TRACE, "Enter\n"); - - drvr->txoff = state; - ndev = drvr_priv->iflist[ifidx]->ndev; - if (state == ON) - netif_stop_queue(ndev); - else - netif_wake_queue(ndev); -} - -static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, - void *pktdata, struct brcmf_event_msg *event, - void **data) -{ - int bcmerror = 0; - - bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data); - if (bcmerror != 0) - return bcmerror; - - if (drvr_priv->iflist[*ifidx]->ndev) - brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev, - event, *data); - - return bcmerror; -} - -void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, - int numpkt) -{ - struct brcmf_info *drvr_priv = drvr->info; - unsigned char *eth; - uint len; - void *data; - struct sk_buff *pnext, *save_pktbuf; - int i; - struct brcmf_if *ifp; - struct brcmf_event_msg event; - - brcmf_dbg(TRACE, "Enter\n"); - - save_pktbuf = skb; - - for (i = 0; skb && i < numpkt; i++, skb = pnext) { - - pnext = skb->next; - skb->next = NULL; - - /* Get the protocol, maintain skb around eth_type_trans() - * The main reason for this hack is for the limitation of - * Linux 2.4 where 'eth_type_trans' uses the - * 'net->hard_header_len' - * to perform skb_pull inside vs ETH_HLEN. Since to avoid - * coping of the packet coming from the network stack to add - * BDC, Hardware header etc, during network interface - * registration - * we set the 'net->hard_header_len' to ETH_HLEN + extra space - * required - * for BDC, Hardware header etc. and not just the ETH_HLEN - */ - eth = skb->data; - len = skb->len; - - ifp = drvr_priv->iflist[ifidx]; - if (ifp == NULL) - ifp = drvr_priv->iflist[0]; - - skb->dev = ifp->ndev; - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) - drvr_priv->pub.rx_multicast++; - - skb->data = eth; - skb->len = len; - - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Process special event packets and then discard them */ - if (ntohs(skb->protocol) == ETH_P_LINK_CTL) - brcmf_host_event(drvr_priv, &ifidx, - skb_mac_header(skb), - &event, &data); - - if (drvr_priv->iflist[ifidx] && - !drvr_priv->iflist[ifidx]->state) - ifp = drvr_priv->iflist[ifidx]; - - if (ifp->ndev) - ifp->ndev->last_rx = jiffies; - - drvr->dstats.rx_bytes += skb->len; - drvr->rx_packets++; /* Local count */ - - if (in_interrupt()) - netif_rx(skb); - else - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ - netif_rx_ni(skb); - } -} - -void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success) -{ - uint ifidx; - struct brcmf_info *drvr_priv = drvr->info; - struct ethhdr *eh; - u16 type; - - brcmf_proto_hdrpull(drvr, &ifidx, txp); - - eh = (struct ethhdr *)(txp->data); - type = ntohs(eh->h_proto); - - if (type == ETH_P_PAE) - atomic_dec(&drvr_priv->pend_8021x_cnt); - -} - -static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - struct brcmf_if *ifp; - int ifidx; - - brcmf_dbg(TRACE, "Enter\n"); - - ifidx = brcmf_net2idx(drvr_priv, ndev); - if (ifidx == BRCMF_BAD_IF) - return NULL; - - ifp = drvr_priv->iflist[ifidx]; - - if (drvr_priv->pub.up) - /* Use the protocol to get dongle stats */ - brcmf_proto_dstats(&drvr_priv->pub); - - /* Copy dongle stats to net device stats */ - ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets; - ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets; - ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes; - ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes; - ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors; - ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors; - ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped; - ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped; - ifp->stats.multicast = drvr_priv->pub.dstats.multicast; - - return &ifp->stats; -} - -/* Retrieve current toe component enables, which are kept - as a bitmap in toe_ol iovar */ -static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol) -{ - struct brcmf_dcmd dcmd; - char buf[32]; - int ret; - - memset(&dcmd, 0, sizeof(dcmd)); - - dcmd.cmd = BRCMF_C_GET_VAR; - dcmd.buf = buf; - dcmd.len = (uint) sizeof(buf); - dcmd.set = false; - - strcpy(buf, "toe_ol"); - ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); - if (ret < 0) { - /* Check for older dongle image that doesn't support toe_ol */ - if (ret == -EIO) { - brcmf_dbg(ERROR, "%s: toe not supported by device\n", - brcmf_ifname(&drvr_priv->pub, ifidx)); - return -EOPNOTSUPP; - } - - brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n", - brcmf_ifname(&drvr_priv->pub, ifidx), ret); - return ret; - } - - memcpy(toe_ol, buf, sizeof(u32)); - return 0; -} - -/* Set current toe component enables in toe_ol iovar, - and set toe global enable iovar */ -static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol) -{ - struct brcmf_dcmd dcmd; - char buf[32]; - int toe, ret; - - memset(&dcmd, 0, sizeof(dcmd)); - - dcmd.cmd = BRCMF_C_SET_VAR; - dcmd.buf = buf; - dcmd.len = (uint) sizeof(buf); - dcmd.set = true; - - /* Set toe_ol as requested */ - - strcpy(buf, "toe_ol"); - memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(u32)); - - ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n", - brcmf_ifname(&drvr_priv->pub, ifidx), ret); - return ret; - } - - /* Enable toe globally only if any components are enabled. */ - - toe = (toe_ol != 0); - - strcpy(buf, "toe"); - memcpy(&buf[sizeof("toe")], &toe, sizeof(u32)); - - ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n", - brcmf_ifname(&drvr_priv->pub, ifidx), ret); - return ret; - } - - return 0; -} - -static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, - struct ethtool_drvinfo *info) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - - sprintf(info->driver, KBUILD_MODNAME); - sprintf(info->version, "%lu", drvr_priv->pub.drv_version); - sprintf(info->fw_version, "%s", BCM4329_FW_NAME); - sprintf(info->bus_info, "%s", - dev_name(brcmf_bus_get_device(drvr_priv->pub.bus))); -} - -static struct ethtool_ops brcmf_ethtool_ops = { - .get_drvinfo = brcmf_ethtool_get_drvinfo -}; - -static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr) -{ - struct ethtool_drvinfo info; - char drvname[sizeof(info.driver)]; - u32 cmd; - struct ethtool_value edata; - u32 toe_cmpnt, csum_dir; - int ret; - - brcmf_dbg(TRACE, "Enter\n"); - - /* all ethtool calls start with a cmd word */ - if (copy_from_user(&cmd, uaddr, sizeof(u32))) - return -EFAULT; - - switch (cmd) { - case ETHTOOL_GDRVINFO: - /* Copy out any request driver name */ - if (copy_from_user(&info, uaddr, sizeof(info))) - return -EFAULT; - strncpy(drvname, info.driver, sizeof(info.driver)); - drvname[sizeof(info.driver) - 1] = '\0'; - - /* clear struct for return */ - memset(&info, 0, sizeof(info)); - info.cmd = cmd; - - /* if requested, identify ourselves */ - if (strcmp(drvname, "?dhd") == 0) { - sprintf(info.driver, "dhd"); - strcpy(info.version, BRCMF_VERSION_STR); - } - - /* otherwise, require dongle to be up */ - else if (!drvr_priv->pub.up) { - brcmf_dbg(ERROR, "dongle is not up\n"); - return -ENODEV; - } - - /* finally, report dongle driver type */ - else if (drvr_priv->pub.iswl) - sprintf(info.driver, "wl"); - else - sprintf(info.driver, "xx"); - - sprintf(info.version, "%lu", drvr_priv->pub.drv_version); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - brcmf_dbg(CTL, "given %*s, returning %s\n", - (int)sizeof(drvname), drvname, info.driver); - break; - - /* Get toe offload components from dongle */ - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); - if (ret < 0) - return ret; - - csum_dir = - (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - edata.cmd = cmd; - edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; - - if (copy_to_user(uaddr, &edata, sizeof(edata))) - return -EFAULT; - break; - - /* Set toe offload components in dongle */ - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - if (copy_from_user(&edata, uaddr, sizeof(edata))) - return -EFAULT; - - /* Read the current settings, update and write back */ - ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); - if (ret < 0) - return ret; - - csum_dir = - (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - if (edata.data != 0) - toe_cmpnt |= csum_dir; - else - toe_cmpnt &= ~csum_dir; - - ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt); - if (ret < 0) - return ret; - - /* If setting TX checksum mode, tell Linux the new mode */ - if (cmd == ETHTOOL_STXCSUM) { - if (edata.data) - drvr_priv->iflist[0]->ndev->features |= - NETIF_F_IP_CSUM; - else - drvr_priv->iflist[0]->ndev->features &= - ~NETIF_F_IP_CSUM; - } - - break; - - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, - int cmd) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - int ifidx; - - ifidx = brcmf_net2idx(drvr_priv, ndev); - brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd); - - if (ifidx == BRCMF_BAD_IF) - return -1; - - if (cmd == SIOCETHTOOL) - return brcmf_ethtool(drvr_priv, ifr->ifr_data); - - return -EOPNOTSUPP; -} - -/* called only from within this driver. Sends a command to the dongle. */ -s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) -{ - struct brcmf_dcmd dcmd; - s32 err = 0; - int buflen = 0; - bool is_set_key_cmd; - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - int ifidx; - - memset(&dcmd, 0, sizeof(dcmd)); - dcmd.cmd = cmd; - dcmd.buf = arg; - dcmd.len = len; - - ifidx = brcmf_net2idx(drvr_priv, ndev); - - if (dcmd.buf != NULL) - buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); - - /* send to dongle (must be up, and wl) */ - if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { - brcmf_dbg(ERROR, "DONGLE_DOWN\n"); - err = -EIO; - goto done; - } - - if (!drvr_priv->pub.iswl) { - err = -EIO; - goto done; - } - - /* - * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and - * set key CMD to prevent M4 encryption. - */ - is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) || - ((dcmd.cmd == BRCMF_C_SET_VAR) && - !(strncmp("wsec_key", dcmd.buf, 9))) || - ((dcmd.cmd == BRCMF_C_SET_VAR) && - !(strncmp("bsscfg:wsec_key", dcmd.buf, 15)))); - if (is_set_key_cmd) - brcmf_netdev_wait_pend8021x(ndev); - - err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen); - -done: - if (err > 0) - err = 0; - - return err; -} - -static int brcmf_netdev_stop(struct net_device *ndev) -{ - struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev); - - brcmf_dbg(TRACE, "Enter\n"); - brcmf_cfg80211_down(drvr->config); - if (drvr->up == 0) - return 0; - - /* Set state and stop OS transmissions */ - drvr->up = 0; - netif_stop_queue(ndev); - - return 0; -} - -static int brcmf_netdev_open(struct net_device *ndev) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **) - netdev_priv(ndev); - u32 toe_ol; - int ifidx = brcmf_net2idx(drvr_priv, ndev); - s32 ret = 0; - - brcmf_dbg(TRACE, "ifidx %d\n", ifidx); - - if (ifidx == 0) { /* do it only for primary eth0 */ - - /* try to bring up bus */ - ret = brcmf_bus_start(&drvr_priv->pub); - if (ret != 0) { - brcmf_dbg(ERROR, "failed with code %d\n", ret); - return -1; - } - atomic_set(&drvr_priv->pend_8021x_cnt, 0); - - memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN); - - /* Get current TOE mode from dongle */ - if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0 - && (toe_ol & TOE_TX_CSUM_OL) != 0) - drvr_priv->iflist[ifidx]->ndev->features |= - NETIF_F_IP_CSUM; - else - drvr_priv->iflist[ifidx]->ndev->features &= - ~NETIF_F_IP_CSUM; - } - /* Allow transmit calls */ - netif_start_queue(ndev); - drvr_priv->pub.up = 1; - if (brcmf_cfg80211_up(drvr_priv->pub.config)) { - brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); - return -1; - } - - return ret; -} - -int -brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev, - char *name, u8 *mac_addr, u32 flags, u8 bssidx) -{ - struct brcmf_if *ifp; - int ret = 0, err = 0; - - brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev); - - ifp = drvr_priv->iflist[ifidx]; - if (!ifp) { - ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC); - if (!ifp) - return -ENOMEM; - } - - memset(ifp, 0, sizeof(struct brcmf_if)); - ifp->info = drvr_priv; - drvr_priv->iflist[ifidx] = ifp; - if (mac_addr != NULL) - memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); - - if (ndev == NULL) { - ifp->state = BRCMF_E_IF_ADD; - ifp->idx = ifidx; - /* - * Delete the existing interface before overwriting it - * in case we missed the BRCMF_E_IF_DEL event. - */ - if (ifp->ndev != NULL) { - brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", - ifp->ndev->name); - netif_stop_queue(ifp->ndev); - unregister_netdev(ifp->ndev); - free_netdev(ifp->ndev); - } - - /* Allocate netdev, including space for private structure */ - ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", - ether_setup); - if (!ifp->ndev) { - brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); - ret = -ENOMEM; - } - - if (ret == 0) { - memcpy(netdev_priv(ifp->ndev), &drvr_priv, - sizeof(drvr_priv)); - err = brcmf_net_attach(&drvr_priv->pub, ifp->idx); - if (err != 0) { - brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n", - err); - ret = -EOPNOTSUPP; - } else { - brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", - current->pid, ifp->ndev->name); - ifp->state = 0; - } - } - - if (ret < 0) { - if (ifp->ndev) - free_netdev(ifp->ndev); - - drvr_priv->iflist[ifp->idx] = NULL; - kfree(ifp); - } - } else - ifp->ndev = ndev; - - return 0; -} - -void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) -{ - struct brcmf_if *ifp; - - brcmf_dbg(TRACE, "idx %d\n", ifidx); - - ifp = drvr_priv->iflist[ifidx]; - if (!ifp) { - brcmf_dbg(ERROR, "Null interface\n"); - return; - } - - ifp->state = BRCMF_E_IF_DEL; - ifp->idx = ifidx; - if (ifp->ndev != NULL) { - netif_stop_queue(ifp->ndev); - unregister_netdev(ifp->ndev); - free_netdev(ifp->ndev); - drvr_priv->iflist[ifidx] = NULL; - kfree(ifp); - } -} - -struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) -{ - struct brcmf_info *drvr_priv = NULL; - struct net_device *ndev; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Allocate netdev, including space for private structure */ - ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup); - if (!ndev) { - brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); - goto fail; - } - - /* Allocate primary brcmf_info */ - drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC); - if (!drvr_priv) - goto fail; - - /* - * Save the brcmf_info into the priv - */ - memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); - - if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) == - BRCMF_BAD_IF) - goto fail; - - ndev->netdev_ops = NULL; - mutex_init(&drvr_priv->proto_block); - - /* Link to info module */ - drvr_priv->pub.info = drvr_priv; - - /* Link to bus module */ - drvr_priv->pub.bus = bus; - drvr_priv->pub.hdrlen = bus_hdrlen; - - /* Attach and link in the protocol */ - if (brcmf_proto_attach(&drvr_priv->pub) != 0) { - brcmf_dbg(ERROR, "brcmf_prot_attach failed\n"); - goto fail; - } - - /* Attach and link in the cfg80211 */ - drvr_priv->pub.config = - brcmf_cfg80211_attach(ndev, - brcmf_bus_get_device(bus), - &drvr_priv->pub); - if (drvr_priv->pub.config == NULL) { - brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); - goto fail; - } - - INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address); - INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list); - - /* - * Save the brcmf_info into the priv - */ - memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); - - return &drvr_priv->pub; - -fail: - if (ndev) - free_netdev(ndev); - if (drvr_priv) - brcmf_detach(&drvr_priv->pub); - - return NULL; -} - -int brcmf_bus_start(struct brcmf_pub *drvr) -{ - int ret = -1; - struct brcmf_info *drvr_priv = drvr->info; - /* Room for "event_msgs" + '\0' + bitvec */ - char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; - - brcmf_dbg(TRACE, "\n"); - - /* Bring up the bus */ - ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub); - if (ret != 0) { - brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret); - return ret; - } - - /* If bus is not ready, can't come up */ - if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { - brcmf_dbg(ERROR, "failed bus is not ready\n"); - return -ENODEV; - } - - brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, - iovbuf, sizeof(iovbuf)); - brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf, - sizeof(iovbuf)); - memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); - - setbit(drvr->eventmask, BRCMF_E_SET_SSID); - setbit(drvr->eventmask, BRCMF_E_PRUNE); - setbit(drvr->eventmask, BRCMF_E_AUTH); - setbit(drvr->eventmask, BRCMF_E_REASSOC); - setbit(drvr->eventmask, BRCMF_E_REASSOC_IND); - setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND); - setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND); - setbit(drvr->eventmask, BRCMF_E_DISASSOC); - setbit(drvr->eventmask, BRCMF_E_JOIN); - setbit(drvr->eventmask, BRCMF_E_ASSOC_IND); - setbit(drvr->eventmask, BRCMF_E_PSK_SUP); - setbit(drvr->eventmask, BRCMF_E_LINK); - setbit(drvr->eventmask, BRCMF_E_NDIS_LINK); - setbit(drvr->eventmask, BRCMF_E_MIC_ERROR); - setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE); - setbit(drvr->eventmask, BRCMF_E_TXFAIL); - setbit(drvr->eventmask, BRCMF_E_JOIN_START); - setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE); - -/* enable dongle roaming event */ - - drvr->pktfilter_count = 1; - /* Setup filter to allow only unicast */ - drvr->pktfilter[0] = "100 0 0 0 0x01 0x00"; - - /* Bus is ready, do any protocol initialization */ - ret = brcmf_proto_init(&drvr_priv->pub); - if (ret < 0) - return ret; - - return 0; -} - -static struct net_device_ops brcmf_netdev_ops_pri = { - .ndo_open = brcmf_netdev_open, - .ndo_stop = brcmf_netdev_stop, - .ndo_get_stats = brcmf_netdev_get_stats, - .ndo_do_ioctl = brcmf_netdev_ioctl_entry, - .ndo_start_xmit = brcmf_netdev_start_xmit, - .ndo_set_mac_address = brcmf_netdev_set_mac_address, - .ndo_set_multicast_list = brcmf_netdev_set_multicast_list -}; - -int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) -{ - struct brcmf_info *drvr_priv = drvr->info; - struct net_device *ndev; - u8 temp_addr[ETH_ALEN] = { - 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33}; - - brcmf_dbg(TRACE, "ifidx %d\n", ifidx); - - ndev = drvr_priv->iflist[ifidx]->ndev; - ndev->netdev_ops = &brcmf_netdev_ops_pri; - - /* - * We have to use the primary MAC for virtual interfaces - */ - if (ifidx != 0) { - /* for virtual interfaces use the primary MAC */ - memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN); - - } - - if (ifidx == 1) { - brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); - /* ACCESSPOINT INTERFACE CASE */ - temp_addr[0] |= 0X02; /* set bit 2 , - - Locally Administered address */ - - } - ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen; - ndev->ethtool_ops = &brcmf_ethtool_ops; - - drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len + - drvr_priv->pub.hdrlen; - - memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); - - if (register_netdev(ndev) != 0) { - brcmf_dbg(ERROR, "couldn't register the net device\n"); - goto fail; - } - - brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); - - return 0; - -fail: - ndev->netdev_ops = NULL; - return -EBADE; -} - -static void brcmf_bus_detach(struct brcmf_pub *drvr) -{ - struct brcmf_info *drvr_priv; - - brcmf_dbg(TRACE, "Enter\n"); - - if (drvr) { - drvr_priv = drvr->info; - if (drvr_priv) { - /* Stop the protocol module */ - brcmf_proto_stop(&drvr_priv->pub); - - /* Stop the bus module */ - brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus); - } - } -} - -void brcmf_detach(struct brcmf_pub *drvr) -{ - struct brcmf_info *drvr_priv; - - brcmf_dbg(TRACE, "Enter\n"); - - if (drvr) { - drvr_priv = drvr->info; - if (drvr_priv) { - struct brcmf_if *ifp; - int i; - - for (i = 1; i < BRCMF_MAX_IFS; i++) - if (drvr_priv->iflist[i]) - brcmf_del_if(drvr_priv, i); - - ifp = drvr_priv->iflist[0]; - if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { - rtnl_lock(); - brcmf_netdev_stop(ifp->ndev); - rtnl_unlock(); - unregister_netdev(ifp->ndev); - } - - cancel_work_sync(&drvr_priv->setmacaddr_work); - cancel_work_sync(&drvr_priv->multicast_work); - - brcmf_bus_detach(drvr); - - if (drvr->prot) - brcmf_proto_detach(drvr); - - brcmf_cfg80211_detach(drvr->config); - - free_netdev(ifp->ndev); - kfree(ifp); - kfree(drvr_priv); - } - } -} - -static void __exit brcmf_module_cleanup(void) -{ - brcmf_dbg(TRACE, "Enter\n"); - - brcmf_bus_unregister(); -} - -static int __init brcmf_module_init(void) -{ - int error; - - brcmf_dbg(TRACE, "Enter\n"); - - error = brcmf_bus_register(); - - if (error) { - brcmf_dbg(ERROR, "brcmf_bus_register failed\n"); - goto failed; - } - return 0; - -failed: - return -EINVAL; -} - -module_init(brcmf_module_init); -module_exit(brcmf_module_cleanup); - -int brcmf_os_proto_block(struct brcmf_pub *drvr) -{ - struct brcmf_info *drvr_priv = drvr->info; - - if (drvr_priv) { - mutex_lock(&drvr_priv->proto_block); - return 1; - } - return 0; -} - -int brcmf_os_proto_unblock(struct brcmf_pub *drvr) -{ - struct brcmf_info *drvr_priv = drvr->info; - - if (drvr_priv) { - mutex_unlock(&drvr_priv->proto_block); - return 1; - } - - return 0; -} - -static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv) -{ - return atomic_read(&drvr_priv->pend_8021x_cnt); -} - -#define MAX_WAIT_FOR_8021X_TX 10 - -int brcmf_netdev_wait_pend8021x(struct net_device *ndev) -{ - struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev); - int timeout = 10 * HZ / 1000; - int ntimes = MAX_WAIT_FOR_8021X_TX; - int pend = brcmf_get_pend_8021x_cnt(drvr_priv); - - while (ntimes && pend) { - if (pend) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(timeout); - set_current_state(TASK_RUNNING); - ntimes--; - } - pend = brcmf_get_pend_8021x_cnt(drvr_priv); - } - return pend; -} - -#ifdef BCMDBG -int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size) -{ - int ret = 0; - struct file *fp; - mm_segment_t old_fs; - loff_t pos = 0; - - /* change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* open file to write */ - fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640); - if (!fp) { - brcmf_dbg(ERROR, "open file error\n"); - ret = -1; - goto exit; - } - - /* Write buf to file */ - fp->f_op->write(fp, buf, size, &pos); - -exit: - /* free buf before return */ - kfree(buf); - /* close file before return */ - if (fp) - filp_close(fp, current->files); - /* restore previous address limit */ - set_fs(old_fs); - - return ret; -} -#endif /* BCMDBG */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h deleted file mode 100644 index 4ee1ea846f6d..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCMF_PROTO_H_ -#define _BRCMF_PROTO_H_ - -/* - * Exported from the brcmf protocol module (brcmf_cdc) - */ - -/* Linkage, sets prot link and updates hdrlen in pub */ -extern int brcmf_proto_attach(struct brcmf_pub *drvr); - -/* Unlink, frees allocated protocol memory (including brcmf_proto) */ -extern void brcmf_proto_detach(struct brcmf_pub *drvr); - -/* Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -extern int brcmf_proto_init(struct brcmf_pub *drvr); - -/* Stop protocol: sync w/dongle state. */ -extern void brcmf_proto_stop(struct brcmf_pub *drvr); - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, - struct sk_buff *txp); - -/* Remove any protocol-specific data header. */ -extern int brcmf_proto_hdrpull(struct brcmf_pub *, int *ifidx, - struct sk_buff *rxp); - -/* Use protocol to issue command to dongle */ -extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, - struct brcmf_dcmd *dcmd, int len); - -/* Update local copy of dongle statistics */ -extern void brcmf_proto_dstats(struct brcmf_pub *drvr); - -extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr); - -extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, - uint cmd, void *buf, uint len); - -#endif /* _BRCMF_PROTO_H_ */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c deleted file mode 100644 index 6885755f4ec6..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ /dev/null @@ -1,4581 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/kthread.h> -#include <linux/printk.h> -#include <linux/pci_ids.h> -#include <linux/netdevice.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/card.h> -#include <linux/semaphore.h> -#include <linux/firmware.h> -#include <asm/unaligned.h> -#include <defs.h> -#include <brcmu_wifi.h> -#include <brcmu_utils.h> -#include <brcm_hw_ids.h> -#include <soc.h> -#include "sdio_host.h" - -#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ - -#ifdef BCMDBG - -#define BRCMF_TRAP_INFO_SIZE 80 - -#define CBUF_LEN (128) - -struct rte_log_le { - __le32 buf; /* Can't be pointer on (64-bit) hosts */ - __le32 buf_size; - __le32 idx; - char *_buf_compat; /* Redundant pointer for backward compat. */ -}; - -struct rte_console { - /* Virtual UART - * When there is no UART (e.g. Quickturn), - * the host should write a complete - * input line directly into cbuf and then write - * the length into vcons_in. - * This may also be used when there is a real UART - * (at risk of conflicting with - * the real UART). vcons_out is currently unused. - */ - uint vcons_in; - uint vcons_out; - - /* Output (logging) buffer - * Console output is written to a ring buffer log_buf at index log_idx. - * The host may read the output when it sees log_idx advance. - * Output will be lost if the output wraps around faster than the host - * polls. - */ - struct rte_log_le log_le; - - /* Console input line buffer - * Characters are read one at a time into cbuf - * until <CR> is received, then - * the buffer is processed as a command line. - * Also used for virtual UART. - */ - uint cbuf_idx; - char cbuf[CBUF_LEN]; -}; - -#endif /* BCMDBG */ -#include <chipcommon.h> - -#include "dhd.h" -#include "dhd_bus.h" -#include "dhd_proto.h" -#include "dhd_dbg.h" -#include <bcmchip.h> - -#define TXQLEN 2048 /* bulk tx queue length */ -#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ -#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */ -#define PRIOMASK 7 - -#define TXRETRIES 2 /* # of retries for tx frames */ - -#define BRCMF_RXBOUND 50 /* Default for max rx frames in - one scheduling */ - -#define BRCMF_TXBOUND 20 /* Default for max tx frames in - one scheduling */ - -#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ - -#define MEMBLOCK 2048 /* Block size used for downloading - of dongle image */ -#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold - biggest possible glom */ - -#define BRCMF_FIRSTREAD (1 << 6) - - -/* SBSDIO_DEVICE_CTL */ - -/* 1: device will assert busy signal when receiving CMD53 */ -#define SBSDIO_DEVCTL_SETBUSY 0x01 -/* 1: assertion of sdio interrupt is synchronous to the sdio clock */ -#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 -/* 1: mask all interrupts to host except the chipActive (rev 8) */ -#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 -/* 1: isolate internal sdio signals, put external pads in tri-state; requires - * sdio bus power cycle to clear (rev 9) */ -#define SBSDIO_DEVCTL_PADS_ISO 0x08 -/* Force SD->SB reset mapping (rev 11) */ -#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 -/* Determined by CoreControl bit */ -#define SBSDIO_DEVCTL_RST_CORECTL 0x00 -/* Force backplane reset */ -#define SBSDIO_DEVCTL_RST_BPRESET 0x10 -/* Force no backplane reset */ -#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 - -/* SBSDIO_FUNC1_CHIPCLKCSR */ - -/* Force ALP request to backplane */ -#define SBSDIO_FORCE_ALP 0x01 -/* Force HT request to backplane */ -#define SBSDIO_FORCE_HT 0x02 -/* Force ILP request to backplane */ -#define SBSDIO_FORCE_ILP 0x04 -/* Make ALP ready (power up xtal) */ -#define SBSDIO_ALP_AVAIL_REQ 0x08 -/* Make HT ready (power up PLL) */ -#define SBSDIO_HT_AVAIL_REQ 0x10 -/* Squelch clock requests from HW */ -#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 -/* Status: ALP is ready */ -#define SBSDIO_ALP_AVAIL 0x40 -/* Status: HT is ready */ -#define SBSDIO_HT_AVAIL 0x80 - -#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) -#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) -#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) -#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) - -#define SBSDIO_CLKAV(regval, alponly) \ - (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) - -/* direct(mapped) cis space */ - -/* MAPPED common CIS address */ -#define SBSDIO_CIS_BASE_COMMON 0x1000 -/* maximum bytes in one CIS */ -#define SBSDIO_CIS_SIZE_LIMIT 0x200 -/* cis offset addr is < 17 bits */ -#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF - -/* manfid tuple length, include tuple, link bytes */ -#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 - -/* intstatus */ -#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ -#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ -#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ -#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ -#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ -#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ -#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ -#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ -#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ -#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ -#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ -#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ -#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ -#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ -#define I_PC (1 << 10) /* descriptor error */ -#define I_PD (1 << 11) /* data error */ -#define I_DE (1 << 12) /* Descriptor protocol Error */ -#define I_RU (1 << 13) /* Receive descriptor Underflow */ -#define I_RO (1 << 14) /* Receive fifo Overflow */ -#define I_XU (1 << 15) /* Transmit fifo Underflow */ -#define I_RI (1 << 16) /* Receive Interrupt */ -#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ -#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ -#define I_XI (1 << 24) /* Transmit Interrupt */ -#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ -#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ -#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ -#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ -#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */ -#define I_SRESET (1 << 30) /* CCCR RES interrupt */ -#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ -#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) -#define I_DMA (I_RI | I_XI | I_ERRORS) - -/* corecontrol */ -#define CC_CISRDY (1 << 0) /* CIS Ready */ -#define CC_BPRESEN (1 << 1) /* CCCR RES signal */ -#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ -#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */ -#define CC_XMTDATAAVAIL_MODE (1 << 4) -#define CC_XMTDATAAVAIL_CTRL (1 << 5) - -/* SDA_FRAMECTRL */ -#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ -#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ -#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */ -#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */ - -/* HW frame tag */ -#define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */ - -/* Total length of frame header for dongle protocol */ -#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) - -/* - * Software allocation of To SB Mailbox resources - */ - -/* tosbmailbox bits corresponding to intstatus bits */ -#define SMB_NAK (1 << 0) /* Frame NAK */ -#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */ -#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */ -#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */ - -/* tosbmailboxdata */ -#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */ - -/* - * Software allocation of To Host Mailbox resources - */ - -/* intstatus bits */ -#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */ -#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */ -#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */ -#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */ - -/* tohostmailboxdata */ -#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */ -#define HMB_DATA_DEVREADY 2 /* talk to host after enable */ -#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */ -#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */ - -#define HMB_DATA_FCDATA_MASK 0xff000000 -#define HMB_DATA_FCDATA_SHIFT 24 - -#define HMB_DATA_VERSION_MASK 0x00ff0000 -#define HMB_DATA_VERSION_SHIFT 16 - -/* - * Software-defined protocol header - */ - -/* Current protocol version */ -#define SDPCM_PROT_VERSION 4 - -/* SW frame header */ -#define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff) - -#define SDPCM_CHANNEL_MASK 0x00000f00 -#define SDPCM_CHANNEL_SHIFT 8 -#define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f) - -#define SDPCM_NEXTLEN_OFFSET 2 - -/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ -#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ -#define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) -#define SDPCM_DOFFSET_MASK 0xff000000 -#define SDPCM_DOFFSET_SHIFT 24 -#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ -#define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff) -#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ -#define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) - -#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ - -/* logical channel numbers */ -#define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */ -#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ -#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ -#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */ -#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ - -#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */ - -#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80) - -/* - * Shared structure between dongle and the host. - * The structure contains pointers to trap or assert information. - */ -#define SDPCM_SHARED_VERSION 0x0002 -#define SDPCM_SHARED_VERSION_MASK 0x00FF -#define SDPCM_SHARED_ASSERT_BUILT 0x0100 -#define SDPCM_SHARED_ASSERT 0x0200 -#define SDPCM_SHARED_TRAP 0x0400 - -/* Space for header read, limit for data packets */ -#define MAX_HDR_READ (1 << 6) -#define MAX_RX_DATASZ 2048 - -/* Maximum milliseconds to wait for F2 to come up */ -#define BRCMF_WAIT_F2RDY 3000 - -/* Bump up limit on waiting for HT to account for first startup; - * if the image is doing a CRC calculation before programming the PMU - * for HT availability, it could take a couple hundred ms more, so - * max out at a 1 second (1000000us). - */ -#undef PMU_MAX_TRANSITION_DLY -#define PMU_MAX_TRANSITION_DLY 1000000 - -/* Value for ChipClockCSR during initial setup */ -#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \ - SBSDIO_ALP_AVAIL_REQ) - -/* Flags for SDH calls */ -#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) - -/* sbimstate */ -#define SBIM_IBE 0x20000 /* inbanderror */ -#define SBIM_TO 0x40000 /* timeout */ -#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */ -#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */ - -/* sbtmstatelow */ - -/* reset */ -#define SBTML_RESET 0x0001 -/* reject field */ -#define SBTML_REJ_MASK 0x0006 -/* reject */ -#define SBTML_REJ 0x0002 -/* temporary reject, for error recovery */ -#define SBTML_TMPREJ 0x0004 - -/* Shift to locate the SI control flags in sbtml */ -#define SBTML_SICF_SHIFT 16 - -/* sbtmstatehigh */ -#define SBTMH_SERR 0x0001 /* serror */ -#define SBTMH_INT 0x0002 /* interrupt */ -#define SBTMH_BUSY 0x0004 /* busy */ -#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ - -/* Shift to locate the SI status flags in sbtmh */ -#define SBTMH_SISF_SHIFT 16 - -/* sbidlow */ -#define SBIDL_INIT 0x80 /* initiator */ - -/* sbidhigh */ -#define SBIDH_RC_MASK 0x000f /* revision code */ -#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */ -#define SBIDH_RCE_SHIFT 8 -#define SBCOREREV(sbidh) \ - ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \ - ((sbidh) & SBIDH_RC_MASK)) -#define SBIDH_CC_MASK 0x8ff0 /* core code */ -#define SBIDH_CC_SHIFT 4 -#define SBIDH_VC_MASK 0xffff0000 /* vendor code */ -#define SBIDH_VC_SHIFT 16 - -/* - * Conversion of 802.1D priority to precedence level - */ -static uint prio2prec(u32 prio) -{ - return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? - (prio^2) : prio; -} - -/* - * Core reg address translation. - * Both macro's returns a 32 bits byte address on the backplane bus. - */ -#define CORE_CC_REG(base, field) \ - (base + offsetof(struct chipcregs, field)) -#define CORE_BUS_REG(base, field) \ - (base + offsetof(struct sdpcmd_regs, field)) -#define CORE_SB(base, field) \ - (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) - -/* core registers */ -struct sdpcmd_regs { - u32 corecontrol; /* 0x00, rev8 */ - u32 corestatus; /* rev8 */ - u32 PAD[1]; - u32 biststatus; /* rev8 */ - - /* PCMCIA access */ - u16 pcmciamesportaladdr; /* 0x010, rev8 */ - u16 PAD[1]; - u16 pcmciamesportalmask; /* rev8 */ - u16 PAD[1]; - u16 pcmciawrframebc; /* rev8 */ - u16 PAD[1]; - u16 pcmciaunderflowtimer; /* rev8 */ - u16 PAD[1]; - - /* interrupt */ - u32 intstatus; /* 0x020, rev8 */ - u32 hostintmask; /* rev8 */ - u32 intmask; /* rev8 */ - u32 sbintstatus; /* rev8 */ - u32 sbintmask; /* rev8 */ - u32 funcintmask; /* rev4 */ - u32 PAD[2]; - u32 tosbmailbox; /* 0x040, rev8 */ - u32 tohostmailbox; /* rev8 */ - u32 tosbmailboxdata; /* rev8 */ - u32 tohostmailboxdata; /* rev8 */ - - /* synchronized access to registers in SDIO clock domain */ - u32 sdioaccess; /* 0x050, rev8 */ - u32 PAD[3]; - - /* PCMCIA frame control */ - u8 pcmciaframectrl; /* 0x060, rev8 */ - u8 PAD[3]; - u8 pcmciawatermark; /* rev8 */ - u8 PAD[155]; - - /* interrupt batching control */ - u32 intrcvlazy; /* 0x100, rev8 */ - u32 PAD[3]; - - /* counters */ - u32 cmd52rd; /* 0x110, rev8 */ - u32 cmd52wr; /* rev8 */ - u32 cmd53rd; /* rev8 */ - u32 cmd53wr; /* rev8 */ - u32 abort; /* rev8 */ - u32 datacrcerror; /* rev8 */ - u32 rdoutofsync; /* rev8 */ - u32 wroutofsync; /* rev8 */ - u32 writebusy; /* rev8 */ - u32 readwait; /* rev8 */ - u32 readterm; /* rev8 */ - u32 writeterm; /* rev8 */ - u32 PAD[40]; - u32 clockctlstatus; /* rev8 */ - u32 PAD[7]; - - u32 PAD[128]; /* DMA engines */ - - /* SDIO/PCMCIA CIS region */ - char cis[512]; /* 0x400-0x5ff, rev6 */ - - /* PCMCIA function control registers */ - char pcmciafcr[256]; /* 0x600-6ff, rev6 */ - u16 PAD[55]; - - /* PCMCIA backplane access */ - u16 backplanecsr; /* 0x76E, rev6 */ - u16 backplaneaddr0; /* rev6 */ - u16 backplaneaddr1; /* rev6 */ - u16 backplaneaddr2; /* rev6 */ - u16 backplaneaddr3; /* rev6 */ - u16 backplanedata0; /* rev6 */ - u16 backplanedata1; /* rev6 */ - u16 backplanedata2; /* rev6 */ - u16 backplanedata3; /* rev6 */ - u16 PAD[31]; - - /* sprom "size" & "blank" info */ - u16 spromstatus; /* 0x7BE, rev2 */ - u32 PAD[464]; - - u16 PAD[0x80]; -}; - -#ifdef BCMDBG -/* Device console log buffer state */ -struct brcmf_console { - uint count; /* Poll interval msec counter */ - uint log_addr; /* Log struct address (fixed) */ - struct rte_log_le log_le; /* Log struct (host copy) */ - uint bufsize; /* Size of log buffer */ - u8 *buf; /* Log buffer (host copy) */ - uint last; /* Last buffer read index */ -}; -#endif /* BCMDBG */ - -struct sdpcm_shared { - u32 flags; - u32 trap_addr; - u32 assert_exp_addr; - u32 assert_file_addr; - u32 assert_line; - u32 console_addr; /* Address of struct rte_console */ - u32 msgtrace_addr; - u8 tag[32]; -}; - -struct sdpcm_shared_le { - __le32 flags; - __le32 trap_addr; - __le32 assert_exp_addr; - __le32 assert_file_addr; - __le32 assert_line; - __le32 console_addr; /* Address of struct rte_console */ - __le32 msgtrace_addr; - u8 tag[32]; -}; - - -/* misc chip info needed by some of the routines */ -struct chip_info { - u32 chip; - u32 chiprev; - u32 cccorebase; - u32 ccrev; - u32 cccaps; - u32 buscorebase; /* 32 bits backplane bus address */ - u32 buscorerev; - u32 buscoretype; - u32 ramcorebase; - u32 armcorebase; - u32 pmurev; - u32 ramsize; -}; - -/* Private data for SDIO bus interaction */ -struct brcmf_bus { - struct brcmf_pub *drvr; - - struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ - struct chip_info *ci; /* Chip info struct */ - char *vars; /* Variables (from CIS and/or other) */ - uint varsz; /* Size of variables buffer */ - - u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - - u32 hostintmask; /* Copy of Host Interrupt Mask */ - u32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ - bool fcstate; /* State of dongle flow-control */ - - uint blocksize; /* Block size of SDIO transfers */ - uint roundup; /* Max roundup limit */ - - struct pktq txq; /* Queue length used for flow-control */ - u8 flowcontrol; /* per prio flow control bitmask */ - u8 tx_seq; /* Transmit sequence number (next) */ - u8 tx_max; /* Maximum transmit sequence allowed */ - - u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; - u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ - u16 nextlen; /* Next Read Len from last header */ - u8 rx_seq; /* Receive sequence number (expected) */ - bool rxskip; /* Skip receive (awaiting NAK ACK) */ - - uint rxbound; /* Rx frames to read before resched */ - uint txbound; /* Tx frames to send before resched */ - uint txminmax; - - struct sk_buff *glomd; /* Packet containing glomming descriptor */ - struct sk_buff *glom; /* Packet chain for glommed superframe */ - uint glomerr; /* Glom packet read errors */ - - u8 *rxbuf; /* Buffer for receiving control packets */ - uint rxblen; /* Allocated length of rxbuf */ - u8 *rxctl; /* Aligned pointer into rxbuf */ - u8 *databuf; /* Buffer for receiving big glom packet */ - u8 *dataptr; /* Aligned pointer into databuf */ - uint rxlen; /* Length of valid data in buffer */ - - u8 sdpcm_ver; /* Bus protocol reported by dongle */ - - bool intr; /* Use interrupts */ - bool poll; /* Use polling */ - bool ipend; /* Device interrupt is pending */ - uint intrcount; /* Count of device interrupt callbacks */ - uint lastintrs; /* Count as of last watchdog timer */ - uint spurious; /* Count of spurious interrupts */ - uint pollrate; /* Ticks between device polls */ - uint polltick; /* Tick counter */ - uint pollcnt; /* Count of active polls */ - -#ifdef BCMDBG - uint console_interval; - struct brcmf_console console; /* Console output polling support */ - uint console_addr; /* Console address from shared struct */ -#endif /* BCMDBG */ - - uint regfails; /* Count of R_REG failures */ - - uint clkstate; /* State of sd and backplane clock(s) */ - bool activity; /* Activity flag for clock down */ - s32 idletime; /* Control for activity timeout */ - s32 idlecount; /* Activity timeout counter */ - s32 idleclock; /* How to set bus driver when idle */ - s32 sd_rxchain; - bool use_rxchain; /* If brcmf should use PKT chains */ - bool sleeping; /* Is SDIO bus sleeping? */ - bool rxflow_mode; /* Rx flow control mode */ - bool rxflow; /* Is rx flow control on */ - bool alp_only; /* Don't use HT clock (ALP only) */ -/* Field to decide if rx of control frames happen in rxbuf or lb-pool */ - bool usebufpool; - - /* Some additional counters */ - uint tx_sderrs; /* Count of tx attempts with sd errors */ - uint fcqueued; /* Tx packets that got queued */ - uint rxrtx; /* Count of rtx requests (NAK to dongle) */ - uint rx_toolong; /* Receive frames too long to receive */ - uint rxc_errors; /* SDIO errors when reading control frames */ - uint rx_hdrfail; /* SDIO errors on header reads */ - uint rx_badhdr; /* Bad received headers (roosync?) */ - uint rx_badseq; /* Mismatched rx sequence number */ - uint fc_rcvd; /* Number of flow-control events received */ - uint fc_xoff; /* Number which turned on flow-control */ - uint fc_xon; /* Number which turned off flow-control */ - uint rxglomfail; /* Failed deglom attempts */ - uint rxglomframes; /* Number of glom frames (superframes) */ - uint rxglompkts; /* Number of packets from glom frames */ - uint f2rxhdrs; /* Number of header reads */ - uint f2rxdata; /* Number of frame data reads */ - uint f2txdata; /* Number of f2 frame writes */ - uint f1regdata; /* Number of f1 register accesses */ - - u8 *ctrl_frame_buf; - u32 ctrl_frame_len; - bool ctrl_frame_stat; - - spinlock_t txqlock; - wait_queue_head_t ctrl_wait; - wait_queue_head_t dcmd_resp_wait; - - struct timer_list timer; - struct completion watchdog_wait; - struct task_struct *watchdog_tsk; - bool wd_timer_valid; - uint save_ms; - - struct task_struct *dpc_tsk; - struct completion dpc_wait; - - struct semaphore sdsem; - - const char *fw_name; - const struct firmware *firmware; - const char *nv_name; - u32 fw_ptr; -}; - -struct sbconfig { - u32 PAD[2]; - u32 sbipsflag; /* initiator port ocp slave flag */ - u32 PAD[3]; - u32 sbtpsflag; /* target port ocp slave flag */ - u32 PAD[11]; - u32 sbtmerrloga; /* (sonics >= 2.3) */ - u32 PAD; - u32 sbtmerrlog; /* (sonics >= 2.3) */ - u32 PAD[3]; - u32 sbadmatch3; /* address match3 */ - u32 PAD; - u32 sbadmatch2; /* address match2 */ - u32 PAD; - u32 sbadmatch1; /* address match1 */ - u32 PAD[7]; - u32 sbimstate; /* initiator agent state */ - u32 sbintvec; /* interrupt mask */ - u32 sbtmstatelow; /* target state */ - u32 sbtmstatehigh; /* target state */ - u32 sbbwa0; /* bandwidth allocation table0 */ - u32 PAD; - u32 sbimconfiglow; /* initiator configuration */ - u32 sbimconfighigh; /* initiator configuration */ - u32 sbadmatch0; /* address match0 */ - u32 PAD; - u32 sbtmconfiglow; /* target configuration */ - u32 sbtmconfighigh; /* target configuration */ - u32 sbbconfig; /* broadcast configuration */ - u32 PAD; - u32 sbbstate; /* broadcast state */ - u32 PAD[3]; - u32 sbactcnfg; /* activate configuration */ - u32 PAD[3]; - u32 sbflagst; /* current sbflags */ - u32 PAD[3]; - u32 sbidlow; /* identification */ - u32 sbidhigh; /* identification */ -}; - -/* clkstate */ -#define CLK_NONE 0 -#define CLK_SDONLY 1 -#define CLK_PENDING 2 /* Not used yet */ -#define CLK_AVAIL 3 - -#ifdef BCMDBG -static int qcount[NUMPRIO]; -static int tx_packets[NUMPRIO]; -#endif /* BCMDBG */ - -#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */ - -#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL) - -/* Retry count for register access failures */ -static const uint retry_limit = 2; - -/* Limit on rounding up frames */ -static const uint max_roundup = 512; - -#define ALIGNMENT 4 - -static void pkt_align(struct sk_buff *p, int len, int align) -{ - uint datalign; - datalign = (unsigned long)(p->data); - datalign = roundup(datalign, (align)) - datalign; - if (datalign) - skb_pull(p, datalign); - __skb_trim(p, len); -} - -/* To check if there's window offered */ -static bool data_ok(struct brcmf_bus *bus) -{ - return (u8)(bus->tx_max - bus->tx_seq) != 0 && - ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; -} - -/* - * Reads a register in the SDIO hardware block. This block occupies a series of - * adresses on the 32 bit backplane bus. - */ -static void -r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) -{ - *retryvar = 0; - do { - *regvar = brcmf_sdcard_reg_read(bus->sdiodev, - bus->ci->buscorebase + reg_offset, sizeof(u32)); - } while (brcmf_sdcard_regfail(bus->sdiodev) && - (++(*retryvar) <= retry_limit)); - if (*retryvar) { - bus->regfails += (*retryvar-1); - if (*retryvar > retry_limit) { - brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset); - *regvar = 0; - } - } -} - -static void -w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) -{ - *retryvar = 0; - do { - brcmf_sdcard_reg_write(bus->sdiodev, - bus->ci->buscorebase + reg_offset, - sizeof(u32), regval); - } while (brcmf_sdcard_regfail(bus->sdiodev) && - (++(*retryvar) <= retry_limit)); - if (*retryvar) { - bus->regfails += (*retryvar-1); - if (*retryvar > retry_limit) - brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n", - reg_offset); - } -} - -#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) - -#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) - -/* Packet free applicable unconditionally for sdio and sdspi. - * Conditional if bufpool was present for gspi bus. - */ -static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt) -{ - if (bus->usebufpool) - brcmu_pkt_buf_free_skb(pkt); -} - -/* Turn backplane clock on or off */ -static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) -{ - int err; - u8 clkctl, clkreq, devctl; - unsigned long timeout; - - brcmf_dbg(TRACE, "Enter\n"); - - clkctl = 0; - - if (on) { - /* Request HT Avail */ - clkreq = - bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; - - if ((bus->ci->chip == BCM4329_CHIP_ID) - && (bus->ci->chiprev == 0)) - clkreq |= SBSDIO_FORCE_ALP; - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - if (err) { - brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); - return -EBADE; - } - - if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID) - && (bus->ci->buscorerev == 9))) { - u32 dummy, retries; - r_sdreg32(bus, &dummy, - offsetof(struct sdpcmd_regs, clockctlstatus), - &retries); - } - - /* Check current status */ - clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - brcmf_dbg(ERROR, "HT Avail read error: %d\n", err); - return -EBADE; - } - - /* Go to pending and await interrupt if appropriate */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { - /* Allow only clock-available interrupt */ - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); - if (err) { - brcmf_dbg(ERROR, "Devctl error setting CA: %d\n", - err); - return -EBADE; - } - - devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); - brcmf_dbg(INFO, "CLKCTL: set PENDING\n"); - bus->clkstate = CLK_PENDING; - - return 0; - } else if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); - } - - /* Otherwise, wait here (polling) for HT Avail */ - timeout = jiffies + - msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000); - while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - &err); - if (time_after(jiffies, timeout)) - break; - else - usleep_range(5000, 10000); - } - if (err) { - brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); - return -EBADE; - } - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n", - PMU_MAX_TRANSITION_DLY, clkctl); - return -EBADE; - } - - /* Mark clock available */ - bus->clkstate = CLK_AVAIL; - brcmf_dbg(INFO, "CLKCTL: turned ON\n"); - -#if defined(BCMDBG) - if (bus->alp_only != true) { - if (SBSDIO_ALPONLY(clkctl)) - brcmf_dbg(ERROR, "HT Clock should be on\n"); - } -#endif /* defined (BCMDBG) */ - - bus->activity = true; - } else { - clkreq = 0; - - if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); - } - - bus->clkstate = CLK_SDONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - brcmf_dbg(INFO, "CLKCTL: turned OFF\n"); - if (err) { - brcmf_dbg(ERROR, "Failed access turning clock off: %d\n", - err); - return -EBADE; - } - } - return 0; -} - -/* Change idle/active SD state */ -static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) -{ - brcmf_dbg(TRACE, "Enter\n"); - - if (on) - bus->clkstate = CLK_SDONLY; - else - bus->clkstate = CLK_NONE; - - return 0; -} - -/* Transition SD and backplane clock readiness */ -static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) -{ -#ifdef BCMDBG - uint oldstate = bus->clkstate; -#endif /* BCMDBG */ - - brcmf_dbg(TRACE, "Enter\n"); - - /* Early exit if we're already there */ - if (bus->clkstate == target) { - if (target == CLK_AVAIL) { - brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - bus->activity = true; - } - return 0; - } - - switch (target) { - case CLK_AVAIL: - /* Make sure SD clock is available */ - if (bus->clkstate == CLK_NONE) - brcmf_sdbrcm_sdclk(bus, true); - /* Now request HT Avail on the backplane */ - brcmf_sdbrcm_htclk(bus, true, pendok); - brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - bus->activity = true; - break; - - case CLK_SDONLY: - /* Remove HT request, or bring up SD clock */ - if (bus->clkstate == CLK_NONE) - brcmf_sdbrcm_sdclk(bus, true); - else if (bus->clkstate == CLK_AVAIL) - brcmf_sdbrcm_htclk(bus, false, false); - else - brcmf_dbg(ERROR, "request for %d -> %d\n", - bus->clkstate, target); - brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - break; - - case CLK_NONE: - /* Make sure to remove HT request */ - if (bus->clkstate == CLK_AVAIL) - brcmf_sdbrcm_htclk(bus, false, false); - /* Now remove the SD clock */ - brcmf_sdbrcm_sdclk(bus, false); - brcmf_sdbrcm_wd_timer(bus, 0); - break; - } -#ifdef BCMDBG - brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate); -#endif /* BCMDBG */ - - return 0; -} - -static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) -{ - uint retries = 0; - - brcmf_dbg(INFO, "request %s (currently %s)\n", - sleep ? "SLEEP" : "WAKE", - bus->sleeping ? "SLEEP" : "WAKE"); - - /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) - return 0; - - /* Going to sleep: set the alarm and turn off the lights... */ - if (sleep) { - /* Don't sleep if something is pending */ - if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) - return -EBUSY; - - /* Make sure the controller has the bus up */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Tell device to start using OOB wakeup */ - w_sdreg32(bus, SMB_USE_OOB, - offsetof(struct sdpcmd_regs, tosbmailbox), &retries); - if (retries > retry_limit) - brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); - - /* Turn off our contribution to the HT clock request */ - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); - - /* Isolate the bus */ - if (bus->ci->chip != BCM4329_CHIP_ID) { - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); - } - - /* Change state */ - bus->sleeping = true; - - } else { - /* Waking up: bus power up is ok, set local state */ - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - /* Force pad isolation off if possible - (in case power never toggled) */ - if ((bus->ci->buscoretype == PCMCIA_CORE_ID) - && (bus->ci->buscorerev >= 10)) - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, 0, NULL); - - /* Make sure the controller has the bus up */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Send misc interrupt to indicate OOB not needed */ - w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata), - &retries); - if (retries <= retry_limit) - w_sdreg32(bus, SMB_DEV_INT, - offsetof(struct sdpcmd_regs, tosbmailbox), - &retries); - - if (retries > retry_limit) - brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); - - /* Make sure we have SD bus access */ - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - /* Change state */ - bus->sleeping = false; - } - - return 0; -} - -static void bus_wake(struct brcmf_bus *bus) -{ - if (bus->sleeping) - brcmf_sdbrcm_bussleep(bus, false); -} - -static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) -{ - u32 intstatus = 0; - u32 hmb_data; - u8 fcbits; - uint retries = 0; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Read mailbox data and ack that we did so */ - r_sdreg32(bus, &hmb_data, - offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries); - - if (retries <= retry_limit) - w_sdreg32(bus, SMB_INT_ACK, - offsetof(struct sdpcmd_regs, tosbmailbox), &retries); - bus->f1regdata += 2; - - /* Dongle recomposed rx frames, accept them again */ - if (hmb_data & HMB_DATA_NAKHANDLED) { - brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n", - bus->rx_seq); - if (!bus->rxskip) - brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n"); - - bus->rxskip = false; - intstatus |= I_HMB_FRAME_IND; - } - - /* - * DEVREADY does not occur with gSPI. - */ - if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { - bus->sdpcm_ver = - (hmb_data & HMB_DATA_VERSION_MASK) >> - HMB_DATA_VERSION_SHIFT; - if (bus->sdpcm_ver != SDPCM_PROT_VERSION) - brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, " - "expecting %d\n", - bus->sdpcm_ver, SDPCM_PROT_VERSION); - else - brcmf_dbg(INFO, "Dongle ready, protocol version %d\n", - bus->sdpcm_ver); - } - - /* - * Flow Control has been moved into the RX headers and this out of band - * method isn't used any more. - * remaining backward compatible with older dongles. - */ - if (hmb_data & HMB_DATA_FC) { - fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> - HMB_DATA_FCDATA_SHIFT; - - if (fcbits & ~bus->flowcontrol) - bus->fc_xoff++; - - if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; - - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Shouldn't be any others */ - if (hmb_data & ~(HMB_DATA_DEVREADY | - HMB_DATA_NAKHANDLED | - HMB_DATA_FC | - HMB_DATA_FWREADY | - HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) - brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n", - hmb_data); - - return intstatus; -} - -static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) -{ - uint retries = 0; - u16 lastrbc; - u8 hi, lo; - int err; - - brcmf_dbg(ERROR, "%sterminate frame%s\n", - abort ? "abort command, " : "", - rtx ? ", send NAK" : ""); - - if (abort) - brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, - SFC_RF_TERM, &err); - bus->f1regdata++; - - /* Wait until the packet has been flushed (device/FIFO stable) */ - for (lastrbc = retries = 0xffff; retries > 0; retries--) { - hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_RFRAMEBCLO, NULL); - bus->f1regdata += 2; - - if ((hi == 0) && (lo == 0)) - break; - - if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { - brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n", - lastrbc, (hi << 8) + lo); - } - lastrbc = (hi << 8) + lo; - } - - if (!retries) - brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc); - else - brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries); - - if (rtx) { - bus->rxrtx++; - w_sdreg32(bus, SMB_NAK, - offsetof(struct sdpcmd_regs, tosbmailbox), &retries); - - bus->f1regdata++; - if (retries <= retry_limit) - bus->rxskip = true; - } - - /* Clear partial in any case */ - bus->nextlen = 0; - - /* If we can't reach the device, signal failure */ - if (err || brcmf_sdcard_regfail(bus->sdiodev)) - bus->drvr->busstate = BRCMF_BUS_DOWN; -} - -static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) -{ - u16 dlen, totlen; - u8 *dptr, num = 0; - - u16 sublen, check; - struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; - - int errcode; - u8 chan, seq, doff, sfdoff; - u8 txmax; - - int ifidx = 0; - bool usechain = bus->use_rxchain; - - /* If packets, issue read(s) and send up packet chain */ - /* Return sequence numbers consumed? */ - - brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom); - - /* If there's a descriptor, generate the packet chain */ - if (bus->glomd) { - pfirst = plast = pnext = NULL; - dlen = (u16) (bus->glomd->len); - dptr = bus->glomd->data; - if (!dlen || (dlen & 1)) { - brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n", - dlen); - dlen = 0; - } - - for (totlen = num = 0; dlen; num++) { - /* Get (and move past) next length */ - sublen = get_unaligned_le16(dptr); - dlen -= sizeof(u16); - dptr += sizeof(u16); - if ((sublen < SDPCM_HDRLEN) || - ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { - brcmf_dbg(ERROR, "descriptor len %d bad: %d\n", - num, sublen); - pnext = NULL; - break; - } - if (sublen % BRCMF_SDALIGN) { - brcmf_dbg(ERROR, "sublen %d not multiple of %d\n", - sublen, BRCMF_SDALIGN); - usechain = false; - } - totlen += sublen; - - /* For last frame, adjust read len so total - is a block multiple */ - if (!dlen) { - sublen += - (roundup(totlen, bus->blocksize) - totlen); - totlen = roundup(totlen, bus->blocksize); - } - - /* Allocate/chain packet for next subframe */ - pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN); - if (pnext == NULL) { - brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n", - num, sublen); - break; - } - if (!pfirst) { - pfirst = plast = pnext; - } else { - plast->next = pnext; - plast = pnext; - } - - /* Adhere to start alignment requirements */ - pkt_align(pnext, sublen, BRCMF_SDALIGN); - } - - /* If all allocations succeeded, save packet chain - in bus structure */ - if (pnext) { - brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", - totlen, num); - if (BRCMF_GLOM_ON() && bus->nextlen && - totlen != bus->nextlen) { - brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", - bus->nextlen, totlen, rxseq); - } - bus->glom = pfirst; - pfirst = pnext = NULL; - } else { - if (pfirst) - brcmu_pkt_buf_free_skb(pfirst); - bus->glom = NULL; - num = 0; - } - - /* Done with descriptor packet */ - brcmu_pkt_buf_free_skb(bus->glomd); - bus->glomd = NULL; - bus->nextlen = 0; - } - - /* Ok -- either we just generated a packet chain, - or had one from before */ - if (bus->glom) { - if (BRCMF_GLOM_ON()) { - brcmf_dbg(GLOM, "try superframe read, packet chain:\n"); - for (pnext = bus->glom; pnext; pnext = pnext->next) { - brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n", - pnext, (u8 *) (pnext->data), - pnext->len, pnext->len); - } - } - - pfirst = bus->glom; - dlen = (u16) brcmu_pkttotlen(pfirst); - - /* Do an SDIO read for the superframe. Configurable iovar to - * read directly into the chained packet, or allocate a large - * packet and and copy into the chain. - */ - if (usechain) { - errcode = brcmf_sdcard_recv_buf(bus->sdiodev, - bus->sdiodev->sbwad, - SDIO_FUNC_2, - F2SYNC, (u8 *) pfirst->data, dlen, - pfirst); - } else if (bus->dataptr) { - errcode = brcmf_sdcard_recv_buf(bus->sdiodev, - bus->sdiodev->sbwad, - SDIO_FUNC_2, - F2SYNC, bus->dataptr, dlen, - NULL); - sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen, - bus->dataptr); - if (sublen != dlen) { - brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", - dlen, sublen); - errcode = -1; - } - pnext = NULL; - } else { - brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", - dlen); - errcode = -1; - } - bus->f2rxdata++; - - /* On failure, kill the superframe, allow a couple retries */ - if (errcode < 0) { - brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n", - dlen, errcode); - bus->drvr->rx_errors++; - - if (bus->glomerr++ < 3) { - brcmf_sdbrcm_rxfail(bus, true, true); - } else { - bus->glomerr = 0; - brcmf_sdbrcm_rxfail(bus, true, false); - brcmu_pkt_buf_free_skb(bus->glom); - bus->rxglomfail++; - bus->glom = NULL; - } - return 0; - } -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - printk(KERN_DEBUG "SUPERFRAME:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - pfirst->data, min_t(int, pfirst->len, 48)); - } -#endif - - /* Validate the superframe header */ - dptr = (u8 *) (pfirst->data); - sublen = get_unaligned_le16(dptr); - check = get_unaligned_le16(dptr + sizeof(u16)); - - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); - bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", - bus->nextlen, seq); - bus->nextlen = 0; - } - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - - errcode = 0; - if ((u16)~(sublen ^ check)) { - brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n", - sublen, check); - errcode = -1; - } else if (roundup(sublen, bus->blocksize) != dlen) { - brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", - sublen, roundup(sublen, bus->blocksize), - dlen); - errcode = -1; - } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != - SDPCM_GLOM_CHANNEL) { - brcmf_dbg(ERROR, "(superframe): bad channel %d\n", - SDPCM_PACKET_CHANNEL( - &dptr[SDPCM_FRAMETAG_LEN])); - errcode = -1; - } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { - brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n"); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || - (doff > (pfirst->len - SDPCM_HDRLEN))) { - brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n", - doff, sublen, pfirst->len, SDPCM_HDRLEN); - errcode = -1; - } - - /* Check sequence number of superframe SW header */ - if (rxseq != seq) { - brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", - seq, rxseq); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((u8) (txmax - bus->tx_seq) > 0x40) { - brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", - txmax, bus->tx_seq); - txmax = bus->tx_seq + 2; - } - bus->tx_max = txmax; - - /* Remove superframe header, remember offset */ - skb_pull(pfirst, doff); - sfdoff = doff; - - /* Validate all the subframe headers */ - for (num = 0, pnext = pfirst; pnext && !errcode; - num++, pnext = pnext->next) { - dptr = (u8 *) (pnext->data); - dlen = (u16) (pnext->len); - sublen = get_unaligned_le16(dptr); - check = get_unaligned_le16(dptr + sizeof(u16)); - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - printk(KERN_DEBUG "subframe:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - dptr, 32); - } -#endif - - if ((u16)~(sublen ^ check)) { - brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n", - num, sublen, check); - errcode = -1; - } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { - brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n", - num, sublen, dlen); - errcode = -1; - } else if ((chan != SDPCM_DATA_CHANNEL) && - (chan != SDPCM_EVENT_CHANNEL)) { - brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n", - num, chan); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { - brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n", - num, doff, sublen, SDPCM_HDRLEN); - errcode = -1; - } - } - - if (errcode) { - /* Terminate frame on error, request - a couple retries */ - if (bus->glomerr++ < 3) { - /* Restore superframe header space */ - skb_push(pfirst, sfdoff); - brcmf_sdbrcm_rxfail(bus, true, true); - } else { - bus->glomerr = 0; - brcmf_sdbrcm_rxfail(bus, true, false); - brcmu_pkt_buf_free_skb(bus->glom); - bus->rxglomfail++; - bus->glom = NULL; - } - bus->nextlen = 0; - return 0; - } - - /* Basic SD framing looks ok - process each packet (header) */ - save_pfirst = pfirst; - bus->glom = NULL; - plast = NULL; - - for (num = 0; pfirst; rxseq++, pfirst = pnext) { - pnext = pfirst->next; - pfirst->next = NULL; - - dptr = (u8 *) (pfirst->data); - sublen = get_unaligned_le16(dptr); - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - - brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", - num, pfirst, pfirst->data, - pfirst->len, sublen, chan, seq); - - /* precondition: chan == SDPCM_DATA_CHANNEL || - chan == SDPCM_EVENT_CHANNEL */ - - if (rxseq != seq) { - brcmf_dbg(GLOM, "rx_seq %d, expected %d\n", - seq, rxseq); - bus->rx_badseq++; - rxseq = seq; - } -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { - printk(KERN_DEBUG "Rx Subframe Data:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - dptr, dlen); - } -#endif - - __skb_trim(pfirst, sublen); - skb_pull(pfirst, doff); - - if (pfirst->len == 0) { - brcmu_pkt_buf_free_skb(pfirst); - if (plast) - plast->next = pnext; - else - save_pfirst = pnext; - - continue; - } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, - pfirst) != 0) { - brcmf_dbg(ERROR, "rx protocol error\n"); - bus->drvr->rx_errors++; - brcmu_pkt_buf_free_skb(pfirst); - if (plast) - plast->next = pnext; - else - save_pfirst = pnext; - - continue; - } - - /* this packet will go up, link back into - chain and count it */ - pfirst->next = pnext; - plast = pfirst; - num++; - -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", - num, pfirst, pfirst->data, - pfirst->len, pfirst->next, - pfirst->prev); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - pfirst->data, - min_t(int, pfirst->len, 32)); - } -#endif /* BCMDBG */ - } - if (num) { - up(&bus->sdsem); - brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num); - down(&bus->sdsem); - } - - bus->rxglomframes++; - bus->rxglompkts += num; - } - return num; -} - -static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition, - bool *pending) -{ - DECLARE_WAITQUEUE(wait, current); - int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT); - - /* Wait until control frame is available */ - add_wait_queue(&bus->dcmd_resp_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - while (!(*condition) && (!signal_pending(current) && timeout)) - timeout = schedule_timeout(timeout); - - if (signal_pending(current)) - *pending = true; - - set_current_state(TASK_RUNNING); - remove_wait_queue(&bus->dcmd_resp_wait, &wait); - - return timeout; -} - -static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus) -{ - if (waitqueue_active(&bus->dcmd_resp_wait)) - wake_up_interruptible(&bus->dcmd_resp_wait); - - return 0; -} -static void -brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) -{ - uint rdlen, pad; - - int sdret; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Set rxctl for frame (w/optional alignment) */ - bus->rxctl = bus->rxbuf; - bus->rxctl += BRCMF_FIRSTREAD; - pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); - if (pad) - bus->rxctl += (BRCMF_SDALIGN - pad); - bus->rxctl -= BRCMF_FIRSTREAD; - - /* Copy the already-read portion over */ - memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); - if (len <= BRCMF_FIRSTREAD) - goto gotpkt; - - /* Raise rdlen to next SDIO block to avoid tail command */ - rdlen = len - BRCMF_FIRSTREAD; - if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { - pad = bus->blocksize - (rdlen % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize) && - ((len + pad) < bus->drvr->maxctl)) - rdlen += pad; - } else if (rdlen % BRCMF_SDALIGN) { - rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (rdlen & (ALIGNMENT - 1)) - rdlen = roundup(rdlen, ALIGNMENT); - - /* Drop if the read is too big or it exceeds our maximum */ - if ((rdlen + BRCMF_FIRSTREAD) > bus->drvr->maxctl) { - brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n", - rdlen, bus->drvr->maxctl); - bus->drvr->rx_errors++; - brcmf_sdbrcm_rxfail(bus, false, false); - goto done; - } - - if ((len - doff) > bus->drvr->maxctl) { - brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", - len, len - doff, bus->drvr->maxctl); - bus->drvr->rx_errors++; - bus->rx_toolong++; - brcmf_sdbrcm_rxfail(bus, false, false); - goto done; - } - - /* Read remainder of frame body into the rxctl buffer */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, - bus->sdiodev->sbwad, - SDIO_FUNC_2, - F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen, - NULL); - bus->f2rxdata++; - - /* Control frame failures need retransmission */ - if (sdret < 0) { - brcmf_dbg(ERROR, "read %d control bytes failed: %d\n", - rdlen, sdret); - bus->rxc_errors++; - brcmf_sdbrcm_rxfail(bus, true, true); - goto done; - } - -gotpkt: - -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { - printk(KERN_DEBUG "RxCtrl:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len); - } -#endif - - /* Point to valid data and indicate its length */ - bus->rxctl += doff; - bus->rxlen = len - doff; - -done: - /* Awake any waiters */ - brcmf_sdbrcm_dcmd_resp_wake(bus); -} - -/* Pad read to blocksize for efficiency */ -static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen) -{ - if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) { - *pad = bus->blocksize - (*rdlen % bus->blocksize); - if (*pad <= bus->roundup && *pad < bus->blocksize && - *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ) - *rdlen += *pad; - } else if (*rdlen % BRCMF_SDALIGN) { - *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN); - } -} - -static void -brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, - struct sk_buff **pkt, u8 **rxbuf) -{ - int sdret; /* Return code from calls */ - - *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); - if (*pkt == NULL) - return; - - pkt_align(*pkt, rdlen, BRCMF_SDALIGN); - *rxbuf = (u8 *) ((*pkt)->data); - /* Read the entire frame */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, - *rxbuf, rdlen, *pkt); - bus->f2rxdata++; - - if (sdret < 0) { - brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", - rdlen, sdret); - brcmu_pkt_buf_free_skb(*pkt); - bus->drvr->rx_errors++; - /* Force retry w/normal header read. - * Don't attempt NAK for - * gSPI - */ - brcmf_sdbrcm_rxfail(bus, true, true); - *pkt = NULL; - } -} - -/* Checks the header */ -static int -brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf, - u8 rxseq, u16 nextlen, u16 *len) -{ - u16 check; - bool len_consistent; /* Result of comparing readahead len and - len from hw-hdr */ - - memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); - - /* Extract hardware header fields */ - *len = get_unaligned_le16(bus->rxhdr); - check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); - - /* All zeros means readahead info was bad */ - if (!(*len | check)) { - brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n"); - goto fail; - } - - /* Validate check bytes */ - if ((u16)~(*len ^ check)) { - brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", - nextlen, *len, check); - bus->rx_badhdr++; - brcmf_sdbrcm_rxfail(bus, false, false); - goto fail; - } - - /* Validate frame length */ - if (*len < SDPCM_HDRLEN) { - brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n", - *len); - goto fail; - } - - /* Check for consistency with readahead info */ - len_consistent = (nextlen != (roundup(*len, 16) >> 4)); - if (len_consistent) { - /* Mismatch, force retry w/normal - header (may be >4K) */ - brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n", - nextlen, *len, roundup(*len, 16), - rxseq); - brcmf_sdbrcm_rxfail(bus, true, true); - goto fail; - } - - return 0; - -fail: - brcmf_sdbrcm_pktfree2(bus, pkt); - return -EINVAL; -} - -/* Return true if there may be more frames to read */ -static uint -brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) -{ - u16 len, check; /* Extracted hardware header fields */ - u8 chan, seq, doff; /* Extracted software header fields */ - u8 fcbits; /* Extracted fcbits from software header */ - - struct sk_buff *pkt; /* Packet for event or data frames */ - u16 pad; /* Number of pad bytes to read */ - u16 rdlen; /* Total number of bytes to read */ - u8 rxseq; /* Next sequence number to expect */ - uint rxleft = 0; /* Remaining number of frames allowed */ - int sdret; /* Return code from calls */ - u8 txmax; /* Maximum tx sequence offered */ - u8 *rxbuf; - int ifidx = 0; - uint rxcount = 0; /* Total frames read */ - - brcmf_dbg(TRACE, "Enter\n"); - - /* Not finished unless we encounter no more frames indication */ - *finished = false; - - for (rxseq = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; - rxseq++, rxleft--) { - - /* Handle glomming separately */ - if (bus->glom || bus->glomd) { - u8 cnt; - brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", - bus->glomd, bus->glom); - cnt = brcmf_sdbrcm_rxglom(bus, rxseq); - brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); - rxseq += cnt - 1; - rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; - continue; - } - - /* Try doing single read if we can */ - if (bus->nextlen) { - u16 nextlen = bus->nextlen; - bus->nextlen = 0; - - rdlen = len = nextlen << 4; - brcmf_pad(bus, &pad, &rdlen); - - /* - * After the frame is received we have to - * distinguish whether it is data - * or non-data frame. - */ - brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf); - if (pkt == NULL) { - /* Give up on data, request rtx of events */ - brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n", - len, rdlen, rxseq); - continue; - } - - if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen, - &len) < 0) - continue; - - /* Extract software header fields */ - chan = SDPCM_PACKET_CHANNEL( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - bus->nextlen = - bus->rxhdr[SDPCM_FRAMETAG_LEN + - SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", - bus->nextlen, seq); - bus->nextlen = 0; - } - - bus->drvr->rx_readahead_cnt++; - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE( - &bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - if (bus->flowcontrol != fcbits) { - if (~bus->flowcontrol & fcbits) - bus->fc_xoff++; - - if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; - - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", - seq, rxseq); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((u8) (txmax - bus->tx_seq) > 0x40) { - brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n", - txmax, bus->tx_seq); - txmax = bus->tx_seq + 2; - } - bus->tx_max = txmax; - -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { - printk(KERN_DEBUG "Rx Data:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - rxbuf, len); - } else if (BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "RxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - if (chan == SDPCM_CONTROL_CHANNEL) { - brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", - seq); - /* Force retry w/normal header read */ - bus->nextlen = 0; - brcmf_sdbrcm_rxfail(bus, false, true); - brcmf_sdbrcm_pktfree2(bus, pkt); - continue; - } - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n", - doff, len, SDPCM_HDRLEN); - brcmf_sdbrcm_rxfail(bus, false, false); - brcmf_sdbrcm_pktfree2(bus, pkt); - continue; - } - - /* All done with this one -- now deliver the packet */ - goto deliver; - } - - /* Read frame header (hardware and software) */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, bus->rxhdr, - BRCMF_FIRSTREAD, NULL); - bus->f2rxhdrs++; - - if (sdret < 0) { - brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); - bus->rx_hdrfail++; - brcmf_sdbrcm_rxfail(bus, true, true); - continue; - } -#ifdef BCMDBG - if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "RxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - /* Extract hardware header fields */ - len = get_unaligned_le16(bus->rxhdr); - check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); - - /* All zeros means no more frames */ - if (!(len | check)) { - *finished = true; - break; - } - - /* Validate check bytes */ - if ((u16) ~(len ^ check)) { - brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", - len, check); - bus->rx_badhdr++; - brcmf_sdbrcm_rxfail(bus, false, false); - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len); - continue; - } - - /* Extract software header fields */ - chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", - doff, len, SDPCM_HDRLEN, seq); - bus->rx_badhdr++; - brcmf_sdbrcm_rxfail(bus, false, false); - continue; - } - - /* Save the readahead length if there is one */ - bus->nextlen = - bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", - bus->nextlen, seq); - bus->nextlen = 0; - } - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - if (bus->flowcontrol != fcbits) { - if (~bus->flowcontrol & fcbits) - bus->fc_xoff++; - - if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; - - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((u8) (txmax - bus->tx_seq) > 0x40) { - brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", - txmax, bus->tx_seq); - txmax = bus->tx_seq + 2; - } - bus->tx_max = txmax; - - /* Call a separate function for control frames */ - if (chan == SDPCM_CONTROL_CHANNEL) { - brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); - continue; - } - - /* precondition: chan is either SDPCM_DATA_CHANNEL, - SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or - SDPCM_GLOM_CHANNEL */ - - /* Length to read */ - rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0; - - /* May pad read to blocksize for efficiency */ - if (bus->roundup && bus->blocksize && - (rdlen > bus->blocksize)) { - pad = bus->blocksize - (rdlen % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize) && - ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % BRCMF_SDALIGN) { - rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (rdlen & (ALIGNMENT - 1)) - rdlen = roundup(rdlen, ALIGNMENT); - - if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) { - /* Too long -- skip this frame */ - brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", - len, rdlen); - bus->drvr->rx_errors++; - bus->rx_toolong++; - brcmf_sdbrcm_rxfail(bus, false, false); - continue; - } - - pkt = brcmu_pkt_buf_get_skb(rdlen + - BRCMF_FIRSTREAD + BRCMF_SDALIGN); - if (!pkt) { - /* Give up on data, request rtx of events */ - brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n", - rdlen, chan); - bus->drvr->rx_dropped++; - brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); - continue; - } - - /* Leave room for what we already read, and align remainder */ - skb_pull(pkt, BRCMF_FIRSTREAD); - pkt_align(pkt, rdlen, BRCMF_SDALIGN); - - /* Read the remaining frame data */ - sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)), - rdlen, pkt); - bus->f2rxdata++; - - if (sdret < 0) { - brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, - ((chan == SDPCM_EVENT_CHANNEL) ? "event" - : ((chan == SDPCM_DATA_CHANNEL) ? "data" - : "test")), sdret); - brcmu_pkt_buf_free_skb(pkt); - bus->drvr->rx_errors++; - brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); - continue; - } - - /* Copy the already-read portion */ - skb_push(pkt, BRCMF_FIRSTREAD); - memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); - -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { - printk(KERN_DEBUG "Rx Data:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - pkt->data, len); - } -#endif - -deliver: - /* Save superframe descriptor and allocate packet frame */ - if (chan == SDPCM_GLOM_CHANNEL) { - if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { - brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", - len); -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - printk(KERN_DEBUG "Glom Data:\n"); - print_hex_dump_bytes("", - DUMP_PREFIX_OFFSET, - pkt->data, len); - } -#endif - __skb_trim(pkt, len); - skb_pull(pkt, SDPCM_HDRLEN); - bus->glomd = pkt; - } else { - brcmf_dbg(ERROR, "%s: glom superframe w/o " - "descriptor!\n", __func__); - brcmf_sdbrcm_rxfail(bus, false, false); - } - continue; - } - - /* Fill in packet len and prio, deliver upward */ - __skb_trim(pkt, len); - skb_pull(pkt, doff); - - if (pkt->len == 0) { - brcmu_pkt_buf_free_skb(pkt); - continue; - } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) { - brcmf_dbg(ERROR, "rx protocol error\n"); - brcmu_pkt_buf_free_skb(pkt); - bus->drvr->rx_errors++; - continue; - } - - /* Unlock during rx call */ - up(&bus->sdsem); - brcmf_rx_frame(bus->drvr, ifidx, pkt, 1); - down(&bus->sdsem); - } - rxcount = maxframes - rxleft; -#ifdef BCMDBG - /* Message if we hit the limit */ - if (!rxleft) - brcmf_dbg(DATA, "hit rx limit of %d frames\n", - maxframes); - else -#endif /* BCMDBG */ - brcmf_dbg(DATA, "processed %d frames\n", rxcount); - /* Back off rxseq if awaiting rtx, update rx_seq */ - if (bus->rxskip) - rxseq--; - bus->rx_seq = rxseq; - - return rxcount; -} - -static int -brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags, - u8 *buf, uint nbytes, struct sk_buff *pkt) -{ - return brcmf_sdcard_send_buf - (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt); -} - -static void -brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) -{ - up(&bus->sdsem); - wait_event_interruptible_timeout(bus->ctrl_wait, - (*lockvar == false), HZ * 2); - down(&bus->sdsem); - return; -} - -static void -brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) -{ - if (waitqueue_active(&bus->ctrl_wait)) - wake_up_interruptible(&bus->ctrl_wait); - return; -} - -/* Writes a HW/SW header into the packet and sends it. */ -/* Assumes: (a) header space already there, (b) caller holds lock */ -static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, - uint chan, bool free_pkt) -{ - int ret; - u8 *frame; - u16 len, pad = 0; - u32 swheader; - struct sk_buff *new; - int i; - - brcmf_dbg(TRACE, "Enter\n"); - - frame = (u8 *) (pkt->data); - - /* Add alignment padding, allocate new packet if needed */ - pad = ((unsigned long)frame % BRCMF_SDALIGN); - if (pad) { - if (skb_headroom(pkt) < pad) { - brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n", - skb_headroom(pkt), pad); - bus->drvr->tx_realloc++; - new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN); - if (!new) { - brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n", - pkt->len + BRCMF_SDALIGN); - ret = -ENOMEM; - goto done; - } - - pkt_align(new, pkt->len, BRCMF_SDALIGN); - memcpy(new->data, pkt->data, pkt->len); - if (free_pkt) - brcmu_pkt_buf_free_skb(pkt); - /* free the pkt if canned one is not used */ - free_pkt = true; - pkt = new; - frame = (u8 *) (pkt->data); - /* precondition: (frame % BRCMF_SDALIGN) == 0) */ - pad = 0; - } else { - skb_push(pkt, pad); - frame = (u8 *) (pkt->data); - /* precondition: pad + SDPCM_HDRLEN <= pkt->len */ - memset(frame, 0, pad + SDPCM_HDRLEN); - } - } - /* precondition: pad < BRCMF_SDALIGN */ - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - len = (u16) (pkt->len); - *(__le16 *) frame = cpu_to_le16(len); - *(((__le16 *) frame) + 1) = cpu_to_le16(~len); - - /* Software tag: channel, sequence number, data offset */ - swheader = - ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | - (((pad + - SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); - - put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); - put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - -#ifdef BCMDBG - tx_packets[pkt->priority]++; - if (BRCMF_BYTES_ON() && - (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || - (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { - printk(KERN_DEBUG "Tx Frame:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len); - } else if (BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "TxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - frame, min_t(u16, len, 16)); - } -#endif - - /* Raise len to next SDIO block to eliminate tail command */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - u16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; - } else if (len % BRCMF_SDALIGN) { - len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); - } - - /* Some controllers have trouble with odd bytes -- round to even */ - if (len & (ALIGNMENT - 1)) - len = roundup(len, ALIGNMENT); - - ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, frame, - len, pkt); - bus->f2txdata++; - - if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - ret); - bus->tx_sderrs++; - - brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, - NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - u8 hi, lo; - hi = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, - NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - - } - if (ret == 0) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - -done: - /* restore pkt buffer pointer before calling tx complete routine */ - skb_pull(pkt, SDPCM_HDRLEN + pad); - up(&bus->sdsem); - brcmf_txcomplete(bus->drvr, pkt, ret != 0); - down(&bus->sdsem); - - if (free_pkt) - brcmu_pkt_buf_free_skb(pkt); - - return ret; -} - -static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) -{ - struct sk_buff *pkt; - u32 intstatus = 0; - uint retries = 0; - int ret = 0, prec_out; - uint cnt = 0; - uint datalen; - u8 tx_prec_map; - - struct brcmf_pub *drvr = bus->drvr; - - brcmf_dbg(TRACE, "Enter\n"); - - tx_prec_map = ~bus->flowcontrol; - - /* Send frames until the limit or some other event */ - for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { - spin_lock_bh(&bus->txqlock); - pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); - if (pkt == NULL) { - spin_unlock_bh(&bus->txqlock); - break; - } - spin_unlock_bh(&bus->txqlock); - datalen = pkt->len - SDPCM_HDRLEN; - - ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); - if (ret) - bus->drvr->tx_errors++; - else - bus->drvr->dstats.tx_bytes += datalen; - - /* In poll mode, need to check for other events */ - if (!bus->intr && cnt) { - /* Check device status, signal pending interrupt */ - r_sdreg32(bus, &intstatus, - offsetof(struct sdpcmd_regs, intstatus), - &retries); - bus->f2txdata++; - if (brcmf_sdcard_regfail(bus->sdiodev)) - break; - if (intstatus & bus->hostintmask) - bus->ipend = true; - } - } - - /* Deflow-control stack if needed */ - if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && - drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) - brcmf_txflowcontrol(drvr, 0, OFF); - - return cnt; -} - -static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) -{ - u32 intstatus, newstatus = 0; - uint retries = 0; - uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ - uint txlimit = bus->txbound; /* Tx frames to send before resched */ - uint framecnt = 0; /* Temporary counter of tx/rx frames */ - bool rxdone = true; /* Flag for no more read data */ - bool resched = false; /* Flag indicating resched wanted */ - - brcmf_dbg(TRACE, "Enter\n"); - - /* Start with leftover status bits */ - intstatus = bus->intstatus; - - down(&bus->sdsem); - - /* If waiting for HTAVAIL, check status */ - if (bus->clkstate == CLK_PENDING) { - int err; - u8 clkctl, devctl = 0; - -#ifdef BCMDBG - /* Check for inconsistent device control */ - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); - if (err) { - brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); - bus->drvr->busstate = BRCMF_BUS_DOWN; - } -#endif /* BCMDBG */ - - /* Read CSR, if clock on switch to AVAIL, else ignore */ - clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - brcmf_dbg(ERROR, "error reading CSR: %d\n", - err); - bus->drvr->busstate = BRCMF_BUS_DOWN; - } - - brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", - devctl, clkctl); - - if (SBSDIO_HTAV(clkctl)) { - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); - if (err) { - brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", - err); - bus->drvr->busstate = BRCMF_BUS_DOWN; - } - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); - if (err) { - brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", - err); - bus->drvr->busstate = BRCMF_BUS_DOWN; - } - bus->clkstate = CLK_AVAIL; - } else { - goto clkwait; - } - } - - bus_wake(bus); - - /* Make sure backplane clock is on */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); - if (bus->clkstate == CLK_PENDING) - goto clkwait; - - /* Pending interrupt indicates new device status */ - if (bus->ipend) { - bus->ipend = false; - r_sdreg32(bus, &newstatus, - offsetof(struct sdpcmd_regs, intstatus), &retries); - bus->f1regdata++; - if (brcmf_sdcard_regfail(bus->sdiodev)) - newstatus = 0; - newstatus &= bus->hostintmask; - bus->fcstate = !!(newstatus & I_HMB_FC_STATE); - if (newstatus) { - w_sdreg32(bus, newstatus, - offsetof(struct sdpcmd_regs, intstatus), - &retries); - bus->f1regdata++; - } - } - - /* Merge new bits with previous */ - intstatus |= newstatus; - bus->intstatus = 0; - - /* Handle flow-control change: read new state in case our ack - * crossed another change interrupt. If change still set, assume - * FC ON for safety, let next loop through do the debounce. - */ - if (intstatus & I_HMB_FC_CHANGE) { - intstatus &= ~I_HMB_FC_CHANGE; - w_sdreg32(bus, I_HMB_FC_CHANGE, - offsetof(struct sdpcmd_regs, intstatus), &retries); - - r_sdreg32(bus, &newstatus, - offsetof(struct sdpcmd_regs, intstatus), &retries); - bus->f1regdata += 2; - bus->fcstate = - !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); - intstatus |= (newstatus & bus->hostintmask); - } - - /* Handle host mailbox indication */ - if (intstatus & I_HMB_HOST_INT) { - intstatus &= ~I_HMB_HOST_INT; - intstatus |= brcmf_sdbrcm_hostmail(bus); - } - - /* Generally don't ask for these, can get CRC errors... */ - if (intstatus & I_WR_OOSYNC) { - brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); - intstatus &= ~I_WR_OOSYNC; - } - - if (intstatus & I_RD_OOSYNC) { - brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n"); - intstatus &= ~I_RD_OOSYNC; - } - - if (intstatus & I_SBINT) { - brcmf_dbg(ERROR, "Dongle reports SBINT\n"); - intstatus &= ~I_SBINT; - } - - /* Would be active due to wake-wlan in gSPI */ - if (intstatus & I_CHIPACTIVE) { - brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n"); - intstatus &= ~I_CHIPACTIVE; - } - - /* Ignore frame indications if rxskip is set */ - if (bus->rxskip) - intstatus &= ~I_HMB_FRAME_IND; - - /* On frame indication, read available frames */ - if (PKT_AVAILABLE()) { - framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); - if (rxdone || bus->rxskip) - intstatus &= ~I_HMB_FRAME_IND; - rxlimit -= min(framecnt, rxlimit); - } - - /* Keep still-pending events for next scheduling */ - bus->intstatus = intstatus; - -clkwait: - if (data_ok(bus) && bus->ctrl_frame_stat && - (bus->clkstate == CLK_AVAIL)) { - int ret, i; - - ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, - (u32) bus->ctrl_frame_len, NULL); - - if (ret < 0) { - /* On failure, abort the command and - terminate the frame */ - brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - ret); - bus->tx_sderrs++; - - brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, - NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - u8 hi, lo; - hi = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, - NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - - } - if (ret == 0) - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - - brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret); - bus->ctrl_frame_stat = false; - brcmf_sdbrcm_wait_event_wakeup(bus); - } - /* Send queued frames (limit 1 if rx may still be pending) */ - else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && - brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit - && data_ok(bus)) { - framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); - framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); - txlimit -= framecnt; - } - - /* Resched if events or tx frames are pending, - else await next interrupt */ - /* On failed register access, all bets are off: - no resched or interrupts */ - if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || - brcmf_sdcard_regfail(bus->sdiodev)) { - brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", - brcmf_sdcard_regfail(bus->sdiodev)); - bus->drvr->busstate = BRCMF_BUS_DOWN; - bus->intstatus = 0; - } else if (bus->clkstate == CLK_PENDING) { - brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); - resched = true; - } else if (bus->intstatus || bus->ipend || - (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) - && data_ok(bus)) || PKT_AVAILABLE()) { - resched = true; - } - - bus->dpc_sched = resched; - - /* If we're done for now, turn off clock request. */ - if ((bus->clkstate != CLK_PENDING) - && bus->idletime == BRCMF_IDLE_IMMEDIATE) { - bus->activity = false; - brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); - } - - up(&bus->sdsem); - - return resched; -} - -static int brcmf_sdbrcm_dpc_thread(void *data) -{ - struct brcmf_bus *bus = (struct brcmf_bus *) data; - - allow_signal(SIGTERM); - /* Run until signal received */ - while (1) { - if (kthread_should_stop()) - break; - if (!wait_for_completion_interruptible(&bus->dpc_wait)) { - /* Call bus dpc unless it indicated down - (then clean stop) */ - if (bus->drvr->busstate != BRCMF_BUS_DOWN) { - if (brcmf_sdbrcm_dpc(bus)) - complete(&bus->dpc_wait); - } else { - /* after stopping the bus, exit thread */ - brcmf_sdbrcm_bus_stop(bus); - bus->dpc_tsk = NULL; - break; - } - } else - break; - } - return 0; -} - -int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) -{ - int ret = -EBADE; - uint datalen, prec; - - brcmf_dbg(TRACE, "Enter\n"); - - datalen = pkt->len; - - /* Add space for the header */ - skb_push(pkt, SDPCM_HDRLEN); - /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ - - prec = prio2prec((pkt->priority & PRIOMASK)); - - /* Check for existing queue, current flow-control, - pending event, or pending clock */ - brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq)); - bus->fcqueued++; - - /* Priority based enq */ - spin_lock_bh(&bus->txqlock); - if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) { - skb_pull(pkt, SDPCM_HDRLEN); - brcmf_txcomplete(bus->drvr, pkt, false); - brcmu_pkt_buf_free_skb(pkt); - brcmf_dbg(ERROR, "out of bus->txq !!!\n"); - ret = -ENOSR; - } else { - ret = 0; - } - spin_unlock_bh(&bus->txqlock); - - if (pktq_len(&bus->txq) >= TXHI) - brcmf_txflowcontrol(bus->drvr, 0, ON); - -#ifdef BCMDBG - if (pktq_plen(&bus->txq, prec) > qcount[prec]) - qcount[prec] = pktq_plen(&bus->txq, prec); -#endif - /* Schedule DPC if needed to send queued packet(s) */ - if (!bus->dpc_sched) { - bus->dpc_sched = true; - if (bus->dpc_tsk) - complete(&bus->dpc_wait); - } - - return ret; -} - -static int -brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data, - uint size) -{ - int bcmerror = 0; - u32 sdaddr; - uint dsize; - - /* Determine initial transfer parameters */ - sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; - if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) - dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); - else - dsize = size; - - /* Set the backplane window to include the start address */ - bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); - if (bcmerror) { - brcmf_dbg(ERROR, "window change failed\n"); - goto xfer_done; - } - - /* Do the transfer(s) */ - while (size) { - brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n", - write ? "write" : "read", dsize, - sdaddr, address & SBSDIO_SBWINDOW_MASK); - bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write, - sdaddr, data, dsize); - if (bcmerror) { - brcmf_dbg(ERROR, "membytes transfer failed\n"); - break; - } - - /* Adjust for next transfer (if any) */ - size -= dsize; - if (size) { - data += dsize; - address += dsize; - bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, - address); - if (bcmerror) { - brcmf_dbg(ERROR, "window change failed\n"); - break; - } - sdaddr = 0; - dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); - } - } - -xfer_done: - /* Return the window to backplane enumeration space for core access */ - if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad)) - brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", - bus->sdiodev->sbwad); - - return bcmerror; -} - -#ifdef BCMDBG -#define CONSOLE_LINE_MAX 192 - -static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus) -{ - struct brcmf_console *c = &bus->console; - u8 line[CONSOLE_LINE_MAX], ch; - u32 n, idx, addr; - int rv; - - /* Don't do anything until FWREADY updates console address */ - if (bus->console_addr == 0) - return 0; - - /* Read console log struct */ - addr = bus->console_addr + offsetof(struct rte_console, log_le); - rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le, - sizeof(c->log_le)); - if (rv < 0) - return rv; - - /* Allocate console buffer (one time only) */ - if (c->buf == NULL) { - c->bufsize = le32_to_cpu(c->log_le.buf_size); - c->buf = kmalloc(c->bufsize, GFP_ATOMIC); - if (c->buf == NULL) - return -ENOMEM; - } - - idx = le32_to_cpu(c->log_le.idx); - - /* Protect against corrupt value */ - if (idx > c->bufsize) - return -EBADE; - - /* Skip reading the console buffer if the index pointer - has not moved */ - if (idx == c->last) - return 0; - - /* Read the console buffer */ - addr = le32_to_cpu(c->log_le.buf); - rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize); - if (rv < 0) - return rv; - - while (c->last != idx) { - for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { - if (c->last == idx) { - /* This would output a partial line. - * Instead, back up - * the buffer pointer and output this - * line next time around. - */ - if (c->last >= n) - c->last -= n; - else - c->last = c->bufsize - n; - goto break2; - } - ch = c->buf[c->last]; - c->last = (c->last + 1) % c->bufsize; - if (ch == '\n') - break; - line[n] = ch; - } - - if (n > 0) { - if (line[n - 1] == '\r') - n--; - line[n] = 0; - printk(KERN_DEBUG "CONSOLE: %s\n", line); - } - } -break2: - - return 0; -} -#endif /* BCMDBG */ - -static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len) -{ - int i; - int ret; - - bus->ctrl_frame_stat = false; - ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, - SDIO_FUNC_2, F2SYNC, frame, len, NULL); - - if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - ret); - bus->tx_sderrs++; - - brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - u8 hi, lo; - hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, - NULL); - bus->f1regdata += 2; - if (hi == 0 && lo == 0) - break; - } - return ret; - } - - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - - return ret; -} - -int -brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) -{ - u8 *frame; - u16 len; - u32 swheader; - uint retries = 0; - u8 doff = 0; - int ret = -1; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Back the pointer to make a room for bus header */ - frame = msg - SDPCM_HDRLEN; - len = (msglen += SDPCM_HDRLEN); - - /* Add alignment padding (optional for ctl frames) */ - doff = ((unsigned long)frame % BRCMF_SDALIGN); - if (doff) { - frame -= doff; - len += doff; - msglen += doff; - memset(frame, 0, doff + SDPCM_HDRLEN); - } - /* precondition: doff < BRCMF_SDALIGN */ - doff += SDPCM_HDRLEN; - - /* Round send length to next SDIO block */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - u16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; - } else if (len % BRCMF_SDALIGN) { - len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (len & (ALIGNMENT - 1)) - len = roundup(len, ALIGNMENT); - - /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ - - /* Need to lock here to protect txseq and SDIO tx calls */ - down(&bus->sdsem); - - bus_wake(bus); - - /* Make sure backplane clock is on */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - *(__le16 *) frame = cpu_to_le16((u16) msglen); - *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen); - - /* Software tag: channel, sequence number, data offset */ - swheader = - ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & - SDPCM_CHANNEL_MASK) - | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & - SDPCM_DOFFSET_MASK); - put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); - put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - - if (!data_ok(bus)) { - brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", - bus->tx_max, bus->tx_seq); - bus->ctrl_frame_stat = true; - /* Send from dpc */ - bus->ctrl_frame_buf = frame; - bus->ctrl_frame_len = len; - - brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); - - if (bus->ctrl_frame_stat == false) { - brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); - ret = 0; - } else { - brcmf_dbg(INFO, "ctrl_frame_stat == true\n"); - ret = -1; - } - } - - if (ret == -1) { -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { - printk(KERN_DEBUG "Tx Frame:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - frame, len); - } else if (BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "TxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - frame, min_t(u16, len, 16)); - } -#endif - - do { - ret = brcmf_tx_frame(bus, frame, len); - } while (ret < 0 && retries++ < TXRETRIES); - } - - if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = false; - brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); - } - - up(&bus->sdsem); - - if (ret) - bus->drvr->tx_ctlerrs++; - else - bus->drvr->tx_ctlpkts++; - - return ret ? -EIO : 0; -} - -int -brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) -{ - int timeleft; - uint rxlen = 0; - bool pending; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Wait until control frame is available */ - timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); - - down(&bus->sdsem); - rxlen = bus->rxlen; - memcpy(msg, bus->rxctl, min(msglen, rxlen)); - bus->rxlen = 0; - up(&bus->sdsem); - - if (rxlen) { - brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n", - rxlen, msglen); - } else if (timeleft == 0) { - brcmf_dbg(ERROR, "resumed on timeout\n"); - } else if (pending == true) { - brcmf_dbg(CTL, "cancelled\n"); - return -ERESTARTSYS; - } else { - brcmf_dbg(CTL, "resumed for unknown reason?\n"); - } - - if (rxlen) - bus->drvr->rx_ctlpkts++; - else - bus->drvr->rx_ctlerrs++; - - return rxlen ? (int)rxlen : -ETIMEDOUT; -} - -static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len) -{ - int bcmerror = 0; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Basic sanity checks */ - if (bus->drvr->up) { - bcmerror = -EISCONN; - goto err; - } - if (!len) { - bcmerror = -EOVERFLOW; - goto err; - } - - /* Free the old ones and replace with passed variables */ - kfree(bus->vars); - - bus->vars = kmalloc(len, GFP_ATOMIC); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = -ENOMEM; - goto err; - } - - /* Copy the passed variables, which should include the - terminating double-null */ - memcpy(bus->vars, arg, bus->varsz); -err: - return bcmerror; -} - -static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) -{ - int bcmerror = 0; - u32 varsize; - u32 varaddr; - u8 *vbuffer; - u32 varsizew; - __le32 varsizew_le; -#ifdef BCMDBG - char *nvram_ularray; -#endif /* BCMDBG */ - - /* Even if there are no vars are to be written, we still - need to set the ramsize. */ - varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; - varaddr = (bus->ramsize - 4) - varsize; - - if (bus->vars) { - vbuffer = kzalloc(varsize, GFP_ATOMIC); - if (!vbuffer) - return -ENOMEM; - - memcpy(vbuffer, bus->vars, bus->varsz); - - /* Write the vars list */ - bcmerror = - brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); -#ifdef BCMDBG - /* Verify NVRAM bytes */ - brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); - nvram_ularray = kmalloc(varsize, GFP_ATOMIC); - if (!nvram_ularray) - return -ENOMEM; - - /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); - - /* Read the vars list to temp buffer for comparison */ - bcmerror = - brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, - varsize); - if (bcmerror) { - brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", - bcmerror, varsize, varaddr); - } - /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) - brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); - else - brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); - - kfree(nvram_ularray); -#endif /* BCMDBG */ - - kfree(vbuffer); - } - - /* adjust to the user specified RAM */ - brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize); - brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n", - varaddr, varsize); - varsize = ((bus->ramsize - 4) - varaddr); - - /* - * Determine the length token: - * Varsize, converted to words, in lower 16-bits, checksum - * in upper 16-bits. - */ - if (bcmerror) { - varsizew = 0; - varsizew_le = cpu_to_le32(0); - } else { - varsizew = varsize / 4; - varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); - varsizew_le = cpu_to_le32(varsizew); - } - - brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n", - varsize, varsizew); - - /* Write the length token to the last word */ - bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4), - (u8 *)&varsizew_le, 4); - - return bcmerror; -} - -static void -brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase) -{ - u32 regdata; - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); - if (regdata & SBTML_RESET) - return; - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); - if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) { - /* - * set target reject and spin until busy is clear - * (preserve core-specific bits) - */ - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), - 4, regdata | SBTML_REJ); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); - udelay(1); - SPINWAIT((brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4) & - SBTMH_BUSY), 100000); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4); - if (regdata & SBTMH_BUSY) - brcmf_dbg(ERROR, "ARM core still busy\n"); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbidlow), 4); - if (regdata & SBIDL_INIT) { - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4) | - SBIM_RJ; - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbimstate), 4, - regdata); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4); - udelay(1); - SPINWAIT((brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4) & - SBIM_BY), 100000); - } - - /* set reset and reject while enabling the clocks */ - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4, - (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | - SBTML_REJ | SBTML_RESET)); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatelow), 4); - udelay(10); - - /* clear the initiator reject bit */ - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbidlow), 4); - if (regdata & SBIDL_INIT) { - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4) & - ~SBIM_RJ; - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbimstate), 4, - regdata); - } - } - - /* leave reset and reject asserted */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, - (SBTML_REJ | SBTML_RESET)); - udelay(1); -} - -static void -brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase) -{ - u32 regdata; - - /* - * Must do the disable sequence first to work for - * arbitrary current core state. - */ - brcmf_sdbrcm_chip_disablecore(sdiodev, corebase); - - /* - * Now do the initialization sequence. - * set reset while enabling the clock and - * forcing them on throughout the core - */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, - ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | - SBTML_RESET); - udelay(1); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4); - if (regdata & SBTMH_SERR) - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(corebase, sbtmstatehigh), 4, 0); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(corebase, sbimstate), 4); - if (regdata & (SBIM_IBE | SBIM_TO)) - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4, - regdata & ~(SBIM_IBE | SBIM_TO)); - - /* clear reset and allow it to propagate throughout the core */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, - (SICF_FGC << SBTML_SICF_SHIFT) | - (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); - udelay(1); - - /* leave clock enabled */ - brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, - (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); - udelay(1); -} - -static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) -{ - uint retries; - u32 regdata; - int bcmerror = 0; - - /* To enter download state, disable ARM and reset SOCRAM. - * To exit download state, simply reset ARM (default is RAM boot). - */ - if (enter) { - bus->alp_only = true; - - brcmf_sdbrcm_chip_disablecore(bus->sdiodev, - bus->ci->armcorebase); - - brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase); - - /* Clear the top bit of memory */ - if (bus->ramsize) { - u32 zeros = 0; - brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4, - (u8 *)&zeros, 4); - } - } else { - regdata = brcmf_sdcard_reg_read(bus->sdiodev, - CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4); - regdata &= (SBTML_RESET | SBTML_REJ_MASK | - (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); - if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) { - brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n"); - bcmerror = -EBADE; - goto fail; - } - - bcmerror = brcmf_sdbrcm_write_vars(bus); - if (bcmerror) { - brcmf_dbg(ERROR, "no vars written to RAM\n"); - bcmerror = 0; - } - - w_sdreg32(bus, 0xFFFFFFFF, - offsetof(struct sdpcmd_regs, intstatus), &retries); - - brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase); - - /* Allow HT Clock now that the ARM is running. */ - bus->alp_only = false; - - bus->drvr->busstate = BRCMF_BUS_LOAD; - } -fail: - return bcmerror; -} - -static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) -{ - if (bus->firmware->size < bus->fw_ptr + len) - len = bus->firmware->size - bus->fw_ptr; - - memcpy(buf, &bus->firmware->data[bus->fw_ptr], len); - bus->fw_ptr += len; - return len; -} - -MODULE_FIRMWARE(BCM4329_FW_NAME); -MODULE_FIRMWARE(BCM4329_NV_NAME); - -static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus) -{ - int offset = 0; - uint len; - u8 *memblock = NULL, *memptr; - int ret; - - brcmf_dbg(INFO, "Enter\n"); - - bus->fw_name = BCM4329_FW_NAME; - ret = request_firmware(&bus->firmware, bus->fw_name, - &bus->sdiodev->func[2]->dev); - if (ret) { - brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); - return ret; - } - bus->fw_ptr = 0; - - memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC); - if (memblock == NULL) { - ret = -ENOMEM; - goto err; - } - if ((u32)(unsigned long)memblock % BRCMF_SDALIGN) - memptr += (BRCMF_SDALIGN - - ((u32)(unsigned long)memblock % BRCMF_SDALIGN)); - - /* Download image */ - while ((len = - brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) { - ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len); - if (ret) { - brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n", - ret, MEMBLOCK, offset); - goto err; - } - - offset += MEMBLOCK; - } - -err: - kfree(memblock); - - release_firmware(bus->firmware); - bus->fw_ptr = 0; - - return ret; -} - -/* - * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file - * and ending in a NUL. - * Removes carriage returns, empty lines, comment lines, and converts - * newlines to NULs. - * Shortens buffer as needed and pads with NULs. End of buffer is marked - * by two NULs. -*/ - -static uint brcmf_process_nvram_vars(char *varbuf, uint len) -{ - char *dp; - bool findNewline; - int column; - uint buf_len, n; - - dp = varbuf; - - findNewline = false; - column = 0; - - for (n = 0; n < len; n++) { - if (varbuf[n] == 0) - break; - if (varbuf[n] == '\r') - continue; - if (findNewline && varbuf[n] != '\n') - continue; - findNewline = false; - if (varbuf[n] == '#') { - findNewline = true; - continue; - } - if (varbuf[n] == '\n') { - if (column == 0) - continue; - *dp++ = 0; - column = 0; - continue; - } - *dp++ = varbuf[n]; - column++; - } - buf_len = dp - varbuf; - - while (dp < varbuf + n) - *dp++ = 0; - - return buf_len; -} - -static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus) -{ - uint len; - char *memblock = NULL; - char *bufp; - int ret; - - bus->nv_name = BCM4329_NV_NAME; - ret = request_firmware(&bus->firmware, bus->nv_name, - &bus->sdiodev->func[2]->dev); - if (ret) { - brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); - return ret; - } - bus->fw_ptr = 0; - - memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); - if (memblock == NULL) { - ret = -ENOMEM; - goto err; - } - - len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); - - if (len > 0 && len < MEMBLOCK) { - bufp = (char *)memblock; - bufp[len] = 0; - len = brcmf_process_nvram_vars(bufp, len); - bufp += len; - *bufp++ = 0; - if (len) - ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); - if (ret) - brcmf_dbg(ERROR, "error downloading vars: %d\n", ret); - } else { - brcmf_dbg(ERROR, "error reading nvram file: %d\n", len); - ret = -EIO; - } - -err: - kfree(memblock); - - release_firmware(bus->firmware); - bus->fw_ptr = 0; - - return ret; -} - -static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) -{ - int bcmerror = -1; - - /* Keep arm in reset */ - if (brcmf_sdbrcm_download_state(bus, true)) { - brcmf_dbg(ERROR, "error placing ARM core in reset\n"); - goto err; - } - - /* External image takes precedence if specified */ - if (brcmf_sdbrcm_download_code_file(bus)) { - brcmf_dbg(ERROR, "dongle image file download failed\n"); - goto err; - } - - /* External nvram takes precedence if specified */ - if (brcmf_sdbrcm_download_nvram(bus)) - brcmf_dbg(ERROR, "dongle nvram file download failed\n"); - - /* Take arm out of reset */ - if (brcmf_sdbrcm_download_state(bus, false)) { - brcmf_dbg(ERROR, "error getting out of ARM core reset\n"); - goto err; - } - - bcmerror = 0; - -err: - return bcmerror; -} - -static bool -brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) -{ - bool ret; - - /* Download the firmware */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - ret = _brcmf_sdbrcm_download_firmware(bus) == 0; - - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - return ret; -} - -void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) -{ - u32 local_hostintmask; - u8 saveclk; - uint retries; - int err; - - brcmf_dbg(TRACE, "Enter\n"); - - if (bus->watchdog_tsk) { - send_sig(SIGTERM, bus->watchdog_tsk, 1); - kthread_stop(bus->watchdog_tsk); - bus->watchdog_tsk = NULL; - } - - if (bus->dpc_tsk && bus->dpc_tsk != current) { - send_sig(SIGTERM, bus->dpc_tsk, 1); - kthread_stop(bus->dpc_tsk); - bus->dpc_tsk = NULL; - } - - down(&bus->sdsem); - - bus_wake(bus); - - /* Enable clock for device interrupts */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Disable and clear interrupts at the chip level also */ - w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; - - /* Change our idea of bus state */ - bus->drvr->busstate = BRCMF_BUS_DOWN; - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) - brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); - - /* Turn off the bus (F2), free any pending packets */ - brcmf_dbg(INTR, "disable SDIO interrupts\n"); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - SDIO_FUNC_ENABLE_1, NULL); - - /* Clear any pending interrupts now that F2 is disabled */ - w_sdreg32(bus, local_hostintmask, - offsetof(struct sdpcmd_regs, intstatus), &retries); - - /* Turn off the backplane clock (only) */ - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - /* Clear the data packet queues */ - brcmu_pktq_flush(&bus->txq, true, NULL, NULL); - - /* Clear any held glomming stuff */ - if (bus->glomd) - brcmu_pkt_buf_free_skb(bus->glomd); - - if (bus->glom) - brcmu_pkt_buf_free_skb(bus->glom); - - bus->glom = bus->glomd = NULL; - - /* Clear rx control and wake any waiters */ - bus->rxlen = 0; - brcmf_sdbrcm_dcmd_resp_wake(bus); - - /* Reset some F2 state stuff */ - bus->rxskip = false; - bus->tx_seq = bus->rx_seq = 0; - - up(&bus->sdsem); -} - -int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) -{ - struct brcmf_bus *bus = drvr->bus; - unsigned long timeout; - uint retries = 0; - u8 ready, enable; - int err, ret = 0; - u8 saveclk; - - brcmf_dbg(TRACE, "Enter\n"); - - /* try to download image and nvram to the dongle */ - if (drvr->busstate == BRCMF_BUS_DOWN) { - if (!(brcmf_sdbrcm_download_firmware(bus))) - return -1; - } - - if (!bus->drvr) - return 0; - - /* Start the watchdog timer */ - bus->drvr->tickcnt = 0; - brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - - down(&bus->sdsem); - - /* Make sure backplane clock is on, needed to generate F2 interrupt */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - if (bus->clkstate != CLK_AVAIL) - goto exit; - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); - goto exit; - } - - /* Enable function 2 (frame transfers) */ - w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, - offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries); - enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - enable, NULL); - - timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY); - ready = 0; - while (enable != ready) { - ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0, - SDIO_CCCR_IORx, NULL); - if (time_after(jiffies, timeout)) - break; - else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50)) - /* prevent busy waiting if it takes too long */ - msleep_interruptible(20); - } - - brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready); - - /* If F2 successfully enabled, set core and enable interrupts */ - if (ready == enable) { - /* Set up the interrupt mask and enable interrupts */ - bus->hostintmask = HOSTINTMASK; - w_sdreg32(bus, bus->hostintmask, - offsetof(struct sdpcmd_regs, hostintmask), &retries); - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_WATERMARK, 8, &err); - - /* Set bus state according to enable result */ - drvr->busstate = BRCMF_BUS_DATA; - } - - else { - /* Disable F2 again */ - enable = SDIO_FUNC_ENABLE_1; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, - SDIO_CCCR_IOEx, enable, NULL); - } - - /* Restore previous clock setting */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); - - /* If we didn't come up, turn off backplane clock */ - if (drvr->busstate != BRCMF_BUS_DATA) - brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); - -exit: - up(&bus->sdsem); - - return ret; -} - -void brcmf_sdbrcm_isr(void *arg) -{ - struct brcmf_bus *bus = (struct brcmf_bus *) arg; - - brcmf_dbg(TRACE, "Enter\n"); - - if (!bus) { - brcmf_dbg(ERROR, "bus is null pointer, exiting\n"); - return; - } - - if (bus->drvr->busstate == BRCMF_BUS_DOWN) { - brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); - return; - } - /* Count the interrupt call */ - bus->intrcount++; - bus->ipend = true; - - /* Shouldn't get this interrupt if we're sleeping? */ - if (bus->sleeping) { - brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n"); - return; - } - - /* Disable additional interrupts (is this needed now)? */ - if (!bus->intr) - brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); - - bus->dpc_sched = true; - if (bus->dpc_tsk) - complete(&bus->dpc_wait); -} - -static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) -{ - struct brcmf_bus *bus; - - brcmf_dbg(TIMER, "Enter\n"); - - bus = drvr->bus; - - /* Ignore the timer if simulating bus down */ - if (bus->sleeping) - return false; - - down(&bus->sdsem); - - /* Poll period: check device if appropriate. */ - if (bus->poll && (++bus->polltick >= bus->pollrate)) { - u32 intstatus = 0; - - /* Reset poll tick */ - bus->polltick = 0; - - /* Check device if no interrupts */ - if (!bus->intr || (bus->intrcount == bus->lastintrs)) { - - if (!bus->dpc_sched) { - u8 devpend; - devpend = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_0, SDIO_CCCR_INTx, - NULL); - intstatus = - devpend & (INTR_STATUS_FUNC1 | - INTR_STATUS_FUNC2); - } - - /* If there is something, make like the ISR and - schedule the DPC */ - if (intstatus) { - bus->pollcnt++; - bus->ipend = true; - - bus->dpc_sched = true; - if (bus->dpc_tsk) - complete(&bus->dpc_wait); - } - } - - /* Update interrupt tracking */ - bus->lastintrs = bus->intrcount; - } -#ifdef BCMDBG - /* Poll for console output periodically */ - if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) { - bus->console.count += BRCMF_WD_POLL_MS; - if (bus->console.count >= bus->console_interval) { - bus->console.count -= bus->console_interval; - /* Make sure backplane clock is on */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - if (brcmf_sdbrcm_readconsole(bus) < 0) - /* stop on error */ - bus->console_interval = 0; - } - } -#endif /* BCMDBG */ - - /* On idle timeout clear activity flag and/or turn off clock */ - if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= bus->idletime) { - bus->idlecount = 0; - if (bus->activity) { - bus->activity = false; - brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - } else { - brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); - } - } - } - - up(&bus->sdsem); - - return bus->ipend; -} - -static bool brcmf_sdbrcm_chipmatch(u16 chipid) -{ - if (chipid == BCM4329_CHIP_ID) - return true; - return false; -} - -static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - kfree(bus->rxbuf); - bus->rxctl = bus->rxbuf = NULL; - bus->rxlen = 0; - - kfree(bus->databuf); - bus->databuf = NULL; -} - -static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - if (bus->drvr->maxctl) { - bus->rxblen = - roundup((bus->drvr->maxctl + SDPCM_HDRLEN), - ALIGNMENT) + BRCMF_SDALIGN; - bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); - if (!(bus->rxbuf)) - goto fail; - } - - /* Allocate buffer to receive glomed packet */ - bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC); - if (!(bus->databuf)) { - /* release rxbuf which was already located as above */ - if (!bus->rxblen) - kfree(bus->rxbuf); - goto fail; - } - - /* Align the buffer */ - if ((unsigned long)bus->databuf % BRCMF_SDALIGN) - bus->dataptr = bus->databuf + (BRCMF_SDALIGN - - ((unsigned long)bus->databuf % BRCMF_SDALIGN)); - else - bus->dataptr = bus->databuf; - - return true; - -fail: - return false; -} - -/* SDIO Pad drive strength to select value mappings */ -struct sdiod_drive_str { - u8 strength; /* Pad Drive Strength in mA */ - u8 sel; /* Chip-specific select value */ -}; - -/* SDIO Drive Strength to sel value table for PMU Rev 1 */ -static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { - { - 4, 0x2}, { - 2, 0x3}, { - 1, 0x0}, { - 0, 0x0} - }; - -/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ -static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { - { - 12, 0x7}, { - 10, 0x6}, { - 8, 0x5}, { - 6, 0x4}, { - 4, 0x2}, { - 2, 0x1}, { - 0, 0x0} - }; - -/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ -static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { - { - 32, 0x7}, { - 26, 0x6}, { - 22, 0x5}, { - 16, 0x4}, { - 12, 0x3}, { - 8, 0x2}, { - 4, 0x1}, { - 0, 0x0} - }; - -#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) - -static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, - u32 drivestrength) { - struct sdiod_drive_str *str_tab = NULL; - u32 str_mask = 0; - u32 str_shift = 0; - char chn[8]; - - if (!(bus->ci->cccaps & CC_CAP_PMU)) - return; - - switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) { - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): - str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; - str_mask = 0x30000000; - str_shift = 28; - break; - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): - str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): - str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; - str_mask = 0x00003800; - str_shift = 11; - break; - default: - brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", - brcmu_chipname(bus->ci->chip, chn, 8), - bus->ci->chiprev, bus->ci->pmurev); - break; - } - - if (str_tab != NULL) { - u32 drivestrength_sel = 0; - u32 cc_data_temp; - int i; - - for (i = 0; str_tab[i].strength != 0; i++) { - if (drivestrength >= str_tab[i].strength) { - drivestrength_sel = str_tab[i].sel; - break; - } - } - - brcmf_sdcard_reg_write(bus->sdiodev, - CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), - 4, 1); - cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev, - CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4); - cc_data_temp &= ~str_mask; - drivestrength_sel <<= str_shift; - cc_data_temp |= drivestrength_sel; - brcmf_sdcard_reg_write(bus->sdiodev, - CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), - 4, cc_data_temp); - - brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n", - drivestrength, cc_data_temp); - } -} - -static int -brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev, - struct chip_info *ci, u32 regs) -{ - u32 regdata; - - /* - * Get CC core rev - * Chipid is assume to be at offset 0 from regs arg - * For different chiptypes or old sdio hosts w/o chipcommon, - * other ways of recognition should be added here. - */ - ci->cccorebase = regs; - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->cccorebase, chipid), 4); - ci->chip = regdata & CID_ID_MASK; - ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; - - brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev); - - /* Address of cores for new chips should be added here */ - switch (ci->chip) { - case BCM4329_CHIP_ID: - ci->buscorebase = BCM4329_CORE_BUS_BASE; - ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE; - ci->armcorebase = BCM4329_CORE_ARM_BASE; - ci->ramsize = BCM4329_RAMSIZE; - break; - default: - brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); - return -ENODEV; - } - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->cccorebase, sbidhigh), 4); - ci->ccrev = SBCOREREV(regdata); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->cccorebase, pmucapabilities), 4); - ci->pmurev = regdata & PCAP_REV_MASK; - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->buscorebase, sbidhigh), 4); - ci->buscorerev = SBCOREREV(regdata); - ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT; - - brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", - ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype); - - /* get chipcommon capabilites */ - ci->cccaps = brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->cccorebase, capabilities), 4); - - return 0; -} - -static int -brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs) -{ - struct chip_info *ci; - int err; - u8 clkval, clkset; - - brcmf_dbg(TRACE, "Enter\n"); - - /* alloc chip_info_t */ - ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC); - if (NULL == ci) - return -ENOMEM; - - /* bus/core/clk setup for register access */ - /* Try forcing SDIO core to do ALPAvail request only */ - clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); - if (err) { - brcmf_dbg(ERROR, "error writing for HT off\n"); - goto fail; - } - - /* If register supported, wait for ALPAvail and then force ALP */ - /* This may take up to 15 milliseconds */ - clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL); - if ((clkval & ~SBSDIO_AVBITS) == clkset) { - SPINWAIT(((clkval = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - NULL)), - !SBSDIO_ALPAV(clkval)), - PMU_MAX_TRANSITION_DLY); - if (!SBSDIO_ALPAV(clkval)) { - brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n", - clkval); - err = -EBUSY; - goto fail; - } - clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | - SBSDIO_FORCE_ALP; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - clkset, &err); - udelay(65); - } else { - brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n", - clkset, clkval); - err = -EACCES; - goto fail; - } - - /* Also, disable the extra SDIO pull-ups */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); - - err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs); - if (err) - goto fail; - - /* - * Make sure any on-chip ARM is off (in case strapping is wrong), - * or downloaded code was already running. - */ - brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase); - - brcmf_sdcard_reg_write(bus->sdiodev, - CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0); - brcmf_sdcard_reg_write(bus->sdiodev, - CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0); - - /* Disable F2 to clear any intermediate frame state on the dongle */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - SDIO_FUNC_ENABLE_1, NULL); - - /* WAR: cmd52 backplane read so core HW will drop ALPReq */ - clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - 0, NULL); - - /* Done with backplane-dependent accesses, can drop clock... */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - bus->ci = ci; - return 0; -fail: - bus->ci = NULL; - kfree(ci); - return err; -} - -static bool -brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva) -{ - u8 clkctl = 0; - int err = 0; - int reg_addr; - u32 reg_val; - - bus->alp_only = true; - - /* Return the window to backplane enumeration space for core access */ - if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE)) - brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n"); - -#ifdef BCMDBG - printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n", - brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); - -#endif /* BCMDBG */ - - /* - * Force PLL off until brcmf_sdbrcm_chip_attach() - * programs PLL control regs - */ - - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - BRCMF_INIT_CLKCTL1, &err); - if (!err) - clkctl = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); - - if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { - brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", - err, BRCMF_INIT_CLKCTL1, clkctl); - goto fail; - } - - if (brcmf_sdbrcm_chip_attach(bus, regsva)) { - brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n"); - goto fail; - } - - if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) { - brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip); - goto fail; - } - - brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH); - - /* Get info on the ARM and SOCRAM cores... */ - brcmf_sdcard_reg_read(bus->sdiodev, - CORE_SB(bus->ci->armcorebase, sbidhigh), 4); - bus->ramsize = bus->ci->ramsize; - if (!(bus->ramsize)) { - brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n"); - goto fail; - } - - /* Set core control so an SDIO reset does a backplane reset */ - reg_addr = bus->ci->buscorebase + - offsetof(struct sdpcmd_regs, corecontrol); - reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32)); - brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32), - reg_val | CC_BPRESEN); - - brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); - - /* Locate an appropriately-aligned portion of hdrbuf */ - bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], - BRCMF_SDALIGN); - - /* Set the poll and/or interrupt flags */ - bus->intr = true; - bus->poll = false; - if (bus->poll) - bus->pollrate = 1; - - return true; - -fail: - return false; -} - -static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - /* Disable F2 to clear any intermediate frame state on the dongle */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - SDIO_FUNC_ENABLE_1, NULL); - - bus->drvr->busstate = BRCMF_BUS_DOWN; - bus->sleeping = false; - bus->rxflow = false; - - /* Done with backplane-dependent accesses, can drop clock... */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - /* ...and initialize clock/power states */ - bus->clkstate = CLK_SDONLY; - bus->idletime = BRCMF_IDLE_INTERVAL; - bus->idleclock = BRCMF_IDLE_ACTIVE; - - /* Query the F2 block size, set roundup accordingly */ - bus->blocksize = bus->sdiodev->func[2]->cur_blksize; - bus->roundup = min(max_roundup, bus->blocksize); - - /* bus module does not support packet chaining */ - bus->use_rxchain = false; - bus->sd_rxchain = false; - - return true; -} - -static int -brcmf_sdbrcm_watchdog_thread(void *data) -{ - struct brcmf_bus *bus = (struct brcmf_bus *)data; - - allow_signal(SIGTERM); - /* Run until signal received */ - while (1) { - if (kthread_should_stop()) - break; - if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { - brcmf_sdbrcm_bus_watchdog(bus->drvr); - /* Count the tick for reference */ - bus->drvr->tickcnt++; - } else - break; - } - return 0; -} - -static void -brcmf_sdbrcm_watchdog(unsigned long data) -{ - struct brcmf_bus *bus = (struct brcmf_bus *)data; - - if (bus->watchdog_tsk) { - complete(&bus->watchdog_wait); - /* Reschedule the watchdog */ - if (bus->wd_timer_valid) - mod_timer(&bus->timer, - jiffies + BRCMF_WD_POLL_MS * HZ / 1000); - } -} - -static void -brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - kfree(bus->ci); - bus->ci = NULL; -} - -static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - if (bus->ci) { - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); - brcmf_sdbrcm_chip_detach(bus); - if (bus->vars && bus->varsz) - kfree(bus->vars); - bus->vars = NULL; - } - - brcmf_dbg(TRACE, "Disconnected\n"); -} - -/* Detach and free everything */ -static void brcmf_sdbrcm_release(struct brcmf_bus *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - if (bus) { - /* De-register interrupt handler */ - brcmf_sdcard_intr_dereg(bus->sdiodev); - - if (bus->drvr) { - brcmf_detach(bus->drvr); - brcmf_sdbrcm_release_dongle(bus); - bus->drvr = NULL; - } - - brcmf_sdbrcm_release_malloc(bus); - - kfree(bus); - } - - brcmf_dbg(TRACE, "Disconnected\n"); -} - -void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, - u32 regsva, struct brcmf_sdio_dev *sdiodev) -{ - int ret; - struct brcmf_bus *bus; - - /* Init global variables at run-time, not as part of the declaration. - * This is required to support init/de-init of the driver. - * Initialization - * of globals as part of the declaration results in non-deterministic - * behavior since the value of the globals may be different on the - * first time that the driver is initialized vs subsequent - * initializations. - */ - brcmf_c_init(); - - brcmf_dbg(TRACE, "Enter\n"); - - /* We make an assumption about address window mappings: - * regsva == SI_ENUM_BASE*/ - - /* Allocate private bus interface state */ - bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); - if (!bus) - goto fail; - - bus->sdiodev = sdiodev; - sdiodev->bus = bus; - bus->txbound = BRCMF_TXBOUND; - bus->rxbound = BRCMF_RXBOUND; - bus->txminmax = BRCMF_TXMINMAX; - bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; - bus->usebufpool = false; /* Use bufpool if allocated, - else use locally malloced rxbuf */ - - /* attempt to attach to the dongle */ - if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { - brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n"); - goto fail; - } - - spin_lock_init(&bus->txqlock); - init_waitqueue_head(&bus->ctrl_wait); - init_waitqueue_head(&bus->dcmd_resp_wait); - - /* Set up the watchdog timer */ - init_timer(&bus->timer); - bus->timer.data = (unsigned long)bus; - bus->timer.function = brcmf_sdbrcm_watchdog; - - /* Initialize thread based operation and lock */ - sema_init(&bus->sdsem, 1); - - /* Initialize watchdog thread */ - init_completion(&bus->watchdog_wait); - bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, - bus, "brcmf_watchdog"); - if (IS_ERR(bus->watchdog_tsk)) { - printk(KERN_WARNING - "brcmf_watchdog thread failed to start\n"); - bus->watchdog_tsk = NULL; - } - /* Initialize DPC thread */ - init_completion(&bus->dpc_wait); - bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, - bus, "brcmf_dpc"); - if (IS_ERR(bus->dpc_tsk)) { - printk(KERN_WARNING - "brcmf_dpc thread failed to start\n"); - bus->dpc_tsk = NULL; - } - - /* Attach to the brcmf/OS/network interface */ - bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); - if (!bus->drvr) { - brcmf_dbg(ERROR, "brcmf_attach failed\n"); - goto fail; - } - - /* Allocate buffers */ - if (!(brcmf_sdbrcm_probe_malloc(bus))) { - brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n"); - goto fail; - } - - if (!(brcmf_sdbrcm_probe_init(bus))) { - brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n"); - goto fail; - } - - /* Register interrupt callback, but mask it (not operational yet). */ - brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n"); - ret = brcmf_sdcard_intr_reg(bus->sdiodev); - if (ret != 0) { - brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret); - goto fail; - } - brcmf_dbg(INTR, "registered SDIO interrupt function ok\n"); - - brcmf_dbg(INFO, "completed!!\n"); - - /* if firmware path present try to download and bring up bus */ - ret = brcmf_bus_start(bus->drvr); - if (ret != 0) { - if (ret == -ENOLINK) { - brcmf_dbg(ERROR, "dongle is not responding\n"); - goto fail; - } - } - /* Ok, have the per-port tell the stack we're open for business */ - if (brcmf_net_attach(bus->drvr, 0) != 0) { - brcmf_dbg(ERROR, "Net attach failed!!\n"); - goto fail; - } - - return bus; - -fail: - brcmf_sdbrcm_release(bus); - return NULL; -} - -void brcmf_sdbrcm_disconnect(void *ptr) -{ - struct brcmf_bus *bus = (struct brcmf_bus *)ptr; - - brcmf_dbg(TRACE, "Enter\n"); - - if (bus) - brcmf_sdbrcm_release(bus); - - brcmf_dbg(TRACE, "Disconnected\n"); -} - -struct device *brcmf_bus_get_device(struct brcmf_bus *bus) -{ - return &bus->sdiodev->func[2]->dev; -} - -void -brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) -{ - /* don't start the wd until fw is loaded */ - if (bus->drvr->busstate == BRCMF_BUS_DOWN) - return; - - /* Totally stop the timer */ - if (!wdtick && bus->wd_timer_valid == true) { - del_timer_sync(&bus->timer); - bus->wd_timer_valid = false; - bus->save_ms = wdtick; - return; - } - - if (wdtick) { - if (bus->save_ms != BRCMF_WD_POLL_MS) { - if (bus->wd_timer_valid == true) - /* Stop timer and restart at new value */ - del_timer_sync(&bus->timer); - - /* Create timer again when watchdog period is - dynamically changed or in the first instance - */ - bus->timer.expires = - jiffies + BRCMF_WD_POLL_MS * HZ / 1000; - add_timer(&bus->timer); - - } else { - /* Re arm the timer, at last watchdog period */ - mod_timer(&bus->timer, - jiffies + BRCMF_WD_POLL_MS * HZ / 1000); - } - - bus->wd_timer_valid = true; - bus->save_ms = wdtick; - } -} diff --git a/drivers/staging/brcm80211/brcmfmac/sdio_host.h b/drivers/staging/brcm80211/brcmfmac/sdio_host.h deleted file mode 100644 index 726fa8981113..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/sdio_host.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCM_SDH_H_ -#define _BRCM_SDH_H_ - -#include <linux/skbuff.h> - -#define SDIO_FUNC_0 0 -#define SDIO_FUNC_1 1 -#define SDIO_FUNC_2 2 - -#define SDIOD_FBR_SIZE 0x100 - -/* io_en */ -#define SDIO_FUNC_ENABLE_1 0x02 -#define SDIO_FUNC_ENABLE_2 0x04 - -/* io_rdys */ -#define SDIO_FUNC_READY_1 0x02 -#define SDIO_FUNC_READY_2 0x04 - -/* intr_status */ -#define INTR_STATUS_FUNC1 0x2 -#define INTR_STATUS_FUNC2 0x4 - -/* Maximum number of I/O funcs */ -#define SDIOD_MAX_IOFUNCS 7 - -/* as of sdiod rev 0, supports 3 functions */ -#define SBSDIO_NUM_FUNCTION 3 - -/* function 1 miscellaneous registers */ - -/* sprom command and status */ -#define SBSDIO_SPROM_CS 0x10000 -/* sprom info register */ -#define SBSDIO_SPROM_INFO 0x10001 -/* sprom indirect access data byte 0 */ -#define SBSDIO_SPROM_DATA_LOW 0x10002 -/* sprom indirect access data byte 1 */ -#define SBSDIO_SPROM_DATA_HIGH 0x10003 -/* sprom indirect access addr byte 0 */ -#define SBSDIO_SPROM_ADDR_LOW 0x10004 -/* sprom indirect access addr byte 0 */ -#define SBSDIO_SPROM_ADDR_HIGH 0x10005 -/* xtal_pu (gpio) output */ -#define SBSDIO_CHIP_CTRL_DATA 0x10006 -/* xtal_pu (gpio) enable */ -#define SBSDIO_CHIP_CTRL_EN 0x10007 -/* rev < 7, watermark for sdio device */ -#define SBSDIO_WATERMARK 0x10008 -/* control busy signal generation */ -#define SBSDIO_DEVICE_CTL 0x10009 - -/* SB Address Window Low (b15) */ -#define SBSDIO_FUNC1_SBADDRLOW 0x1000A -/* SB Address Window Mid (b23:b16) */ -#define SBSDIO_FUNC1_SBADDRMID 0x1000B -/* SB Address Window High (b31:b24) */ -#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C -/* Frame Control (frame term/abort) */ -#define SBSDIO_FUNC1_FRAMECTRL 0x1000D -/* ChipClockCSR (ALP/HT ctl/status) */ -#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E -/* SdioPullUp (on cmd, d0-d2) */ -#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F -/* Write Frame Byte Count Low */ -#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 -/* Write Frame Byte Count High */ -#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A -/* Read Frame Byte Count Low */ -#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B -/* Read Frame Byte Count High */ -#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C - -#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ -#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ - -/* function 1 OCP space */ - -/* sb offset addr is <= 15 bits, 32k */ -#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF -#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 -/* with b15, maps to 32-bit SB access */ -#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 - -/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ - -#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ -#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ -#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ -/* Address bits from SBADDR regs */ -#define SBSDIO_SBWINDOW_MASK 0xffff8000 - -#define SDIOH_READ 0 /* Read request */ -#define SDIOH_WRITE 1 /* Write request */ - -#define SDIOH_DATA_FIX 0 /* Fixed addressing */ -#define SDIOH_DATA_INC 1 /* Incremental addressing */ - -/* internal return code */ -#define SUCCESS 0 -#define ERROR 1 - -struct brcmf_sdreg { - int func; - int offset; - int value; -}; - -struct brcmf_sdio_dev { - struct sdio_func *func[SDIO_MAX_FUNCS]; - u8 num_funcs; /* Supported funcs on client */ - u32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - u32 sbwad; /* Save backplane window address */ - bool regfail; /* status of last reg_r/w call */ - void *bus; - atomic_t suspend; /* suspend flag */ - wait_queue_head_t request_byte_wait; - wait_queue_head_t request_word_wait; - wait_queue_head_t request_packet_wait; - wait_queue_head_t request_buffer_wait; - -}; - -/* Register/deregister device interrupt handler. */ -extern int -brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev); - -extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev); - -/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). - * fn: function number - * addr: unmodified SDIO-space address - * data: data byte to write - * err: pointer to error code (or NULL) - */ -extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func, - u32 addr, int *err); -extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func, - u32 addr, u8 data, int *err); - -/* Synchronous access to device (client) core registers via CMD53 to F1. - * addr: backplane address (i.e. >= regsva from attach) - * size: register width in bytes (2 or 4) - * data: data for register write - */ -extern u32 -brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size); - -extern u32 -brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, - u32 data); - -/* Indicate if last reg read/write failed */ -extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev); - -/* Buffer transfer to/from device (client) core via cmd53. - * fn: function number - * addr: backplane address (i.e. >= regsva from attach) - * flags: backplane width, address increment, sync/async - * buf: pointer to memory data buffer - * nbytes: number of bytes to transfer to/from buf - * pkt: pointer to packet associated with buf (if any) - * complete: callback function for command completion (async only) - * handle: handle for completion callback (first arg in callback) - * Returns 0 or error code. - * NOTE: Async operation is not currently supported. - */ -extern int -brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); -extern int -brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); - -/* Flags bits */ - -/* Four-byte target (backplane) width (vs. two-byte) */ -#define SDIO_REQ_4BYTE 0x1 -/* Fixed address (FIFO) (vs. incrementing address) */ -#define SDIO_REQ_FIXED 0x2 -/* Async request (vs. sync request) */ -#define SDIO_REQ_ASYNC 0x4 - -/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). - * rw: read or write (0/1) - * addr: direct SDIO address - * buf: pointer to memory data buffer - * nbytes: number of bytes to transfer to/from buf - * Returns 0 or error code. - */ -extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, - u32 addr, u8 *buf, uint nbytes); - -/* Issue an abort to the specified function */ -extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn); - -/* platform specific/high level functions */ -extern int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); -extern int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev); - -extern int brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, - u32 address); - -/* attach, return handler on success, NULL if failed. - * The handler shall be provided by all subsequent calls. No local cache - * cfghdl points to the starting address of pci device mapped memory - */ -extern int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev); -extern void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev); - -/* read or write one byte using cmd52 */ -extern int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, - uint fnc, uint addr, u8 *byte); - -/* read or write 2/4 bytes using cmd53 */ -extern int -brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, - uint rw, uint fnc, uint addr, - u32 *word, uint nbyte); - -/* read or write any buffer using cmd53 */ -extern int -brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, - uint fix_inc, uint rw, uint fnc_num, - u32 addr, uint regwidth, - u32 buflen, u8 *buffer, struct sk_buff *pkt); - -/* Watchdog timer interface for pm ops */ -extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, - bool enable); - -extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, - u32 regsva, struct brcmf_sdio_dev *sdiodev); -extern void brcmf_sdbrcm_disconnect(void *ptr); -extern void brcmf_sdbrcm_isr(void *arg); -#endif /* _BRCM_SDH_H_ */ diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c deleted file mode 100644 index fc643c1eb59a..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ /dev/null @@ -1,3730 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ - -#include <linux/kernel.h> -#include <linux/if_arp.h> -#include <linux/sched.h> -#include <linux/kthread.h> -#include <linux/netdevice.h> -#include <linux/bitops.h> -#include <linux/etherdevice.h> -#include <linux/ieee80211.h> -#include <linux/uaccess.h> -#include <net/cfg80211.h> - -#include <brcmu_utils.h> -#include <defs.h> -#include <brcmu_wifi.h> -#include "dhd.h" -#include "wl_cfg80211.h" - -#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ - (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) - -static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; - -static u32 brcmf_dbg_level = WL_DBG_ERR; - -static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) -{ - dev->driver_data = data; -} - -static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) -{ - void *data = NULL; - - if (dev) - data = dev->driver_data; - return data; -} - -static -struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev) -{ - struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev); - return ci->cfg_priv; -} - -static bool check_sys_up(struct wiphy *wiphy) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { - WL_INFO("device is not ready : status (%d)\n", - (int)cfg_priv->status); - return false; - } - return true; -} - -#define CHAN2G(_channel, _freq, _flags) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -#define CHAN5G(_channel, _flags) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = 5000 + (5 * (_channel)), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) -#define RATETAB_ENT(_rateid, _flags) \ - { \ - .bitrate = RATE_TO_BASE100KBPS(_rateid), \ - .hw_value = (_rateid), \ - .flags = (_flags), \ - } - -static struct ieee80211_rate __wl_rates[] = { - RATETAB_ENT(BRCM_RATE_1M, 0), - RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(BRCM_RATE_6M, 0), - RATETAB_ENT(BRCM_RATE_9M, 0), - RATETAB_ENT(BRCM_RATE_12M, 0), - RATETAB_ENT(BRCM_RATE_18M, 0), - RATETAB_ENT(BRCM_RATE_24M, 0), - RATETAB_ENT(BRCM_RATE_36M, 0), - RATETAB_ENT(BRCM_RATE_48M, 0), - RATETAB_ENT(BRCM_RATE_54M, 0), -}; - -#define wl_a_rates (__wl_rates + 4) -#define wl_a_rates_size 8 -#define wl_g_rates (__wl_rates + 0) -#define wl_g_rates_size 12 - -static struct ieee80211_channel __wl_2ghz_channels[] = { - CHAN2G(1, 2412, 0), - CHAN2G(2, 2417, 0), - CHAN2G(3, 2422, 0), - CHAN2G(4, 2427, 0), - CHAN2G(5, 2432, 0), - CHAN2G(6, 2437, 0), - CHAN2G(7, 2442, 0), - CHAN2G(8, 2447, 0), - CHAN2G(9, 2452, 0), - CHAN2G(10, 2457, 0), - CHAN2G(11, 2462, 0), - CHAN2G(12, 2467, 0), - CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), -}; - -static struct ieee80211_channel __wl_5ghz_a_channels[] = { - CHAN5G(34, 0), CHAN5G(36, 0), - CHAN5G(38, 0), CHAN5G(40, 0), - CHAN5G(42, 0), CHAN5G(44, 0), - CHAN5G(46, 0), CHAN5G(48, 0), - CHAN5G(52, 0), CHAN5G(56, 0), - CHAN5G(60, 0), CHAN5G(64, 0), - CHAN5G(100, 0), CHAN5G(104, 0), - CHAN5G(108, 0), CHAN5G(112, 0), - CHAN5G(116, 0), CHAN5G(120, 0), - CHAN5G(124, 0), CHAN5G(128, 0), - CHAN5G(132, 0), CHAN5G(136, 0), - CHAN5G(140, 0), CHAN5G(149, 0), - CHAN5G(153, 0), CHAN5G(157, 0), - CHAN5G(161, 0), CHAN5G(165, 0), - CHAN5G(184, 0), CHAN5G(188, 0), - CHAN5G(192, 0), CHAN5G(196, 0), - CHAN5G(200, 0), CHAN5G(204, 0), - CHAN5G(208, 0), CHAN5G(212, 0), - CHAN5G(216, 0), -}; - -static struct ieee80211_channel __wl_5ghz_n_channels[] = { - CHAN5G(32, 0), CHAN5G(34, 0), - CHAN5G(36, 0), CHAN5G(38, 0), - CHAN5G(40, 0), CHAN5G(42, 0), - CHAN5G(44, 0), CHAN5G(46, 0), - CHAN5G(48, 0), CHAN5G(50, 0), - CHAN5G(52, 0), CHAN5G(54, 0), - CHAN5G(56, 0), CHAN5G(58, 0), - CHAN5G(60, 0), CHAN5G(62, 0), - CHAN5G(64, 0), CHAN5G(66, 0), - CHAN5G(68, 0), CHAN5G(70, 0), - CHAN5G(72, 0), CHAN5G(74, 0), - CHAN5G(76, 0), CHAN5G(78, 0), - CHAN5G(80, 0), CHAN5G(82, 0), - CHAN5G(84, 0), CHAN5G(86, 0), - CHAN5G(88, 0), CHAN5G(90, 0), - CHAN5G(92, 0), CHAN5G(94, 0), - CHAN5G(96, 0), CHAN5G(98, 0), - CHAN5G(100, 0), CHAN5G(102, 0), - CHAN5G(104, 0), CHAN5G(106, 0), - CHAN5G(108, 0), CHAN5G(110, 0), - CHAN5G(112, 0), CHAN5G(114, 0), - CHAN5G(116, 0), CHAN5G(118, 0), - CHAN5G(120, 0), CHAN5G(122, 0), - CHAN5G(124, 0), CHAN5G(126, 0), - CHAN5G(128, 0), CHAN5G(130, 0), - CHAN5G(132, 0), CHAN5G(134, 0), - CHAN5G(136, 0), CHAN5G(138, 0), - CHAN5G(140, 0), CHAN5G(142, 0), - CHAN5G(144, 0), CHAN5G(145, 0), - CHAN5G(146, 0), CHAN5G(147, 0), - CHAN5G(148, 0), CHAN5G(149, 0), - CHAN5G(150, 0), CHAN5G(151, 0), - CHAN5G(152, 0), CHAN5G(153, 0), - CHAN5G(154, 0), CHAN5G(155, 0), - CHAN5G(156, 0), CHAN5G(157, 0), - CHAN5G(158, 0), CHAN5G(159, 0), - CHAN5G(160, 0), CHAN5G(161, 0), - CHAN5G(162, 0), CHAN5G(163, 0), - CHAN5G(164, 0), CHAN5G(165, 0), - CHAN5G(166, 0), CHAN5G(168, 0), - CHAN5G(170, 0), CHAN5G(172, 0), - CHAN5G(174, 0), CHAN5G(176, 0), - CHAN5G(178, 0), CHAN5G(180, 0), - CHAN5G(182, 0), CHAN5G(184, 0), - CHAN5G(186, 0), CHAN5G(188, 0), - CHAN5G(190, 0), CHAN5G(192, 0), - CHAN5G(194, 0), CHAN5G(196, 0), - CHAN5G(198, 0), CHAN5G(200, 0), - CHAN5G(202, 0), CHAN5G(204, 0), - CHAN5G(206, 0), CHAN5G(208, 0), - CHAN5G(210, 0), CHAN5G(212, 0), - CHAN5G(214, 0), CHAN5G(216, 0), - CHAN5G(218, 0), CHAN5G(220, 0), - CHAN5G(222, 0), CHAN5G(224, 0), - CHAN5G(226, 0), CHAN5G(228, 0), -}; - -static struct ieee80211_supported_band __wl_band_2ghz = { - .band = IEEE80211_BAND_2GHZ, - .channels = __wl_2ghz_channels, - .n_channels = ARRAY_SIZE(__wl_2ghz_channels), - .bitrates = wl_g_rates, - .n_bitrates = wl_g_rates_size, -}; - -static struct ieee80211_supported_band __wl_band_5ghz_a = { - .band = IEEE80211_BAND_5GHZ, - .channels = __wl_5ghz_a_channels, - .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), - .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size, -}; - -static struct ieee80211_supported_band __wl_band_5ghz_n = { - .band = IEEE80211_BAND_5GHZ, - .channels = __wl_5ghz_n_channels, - .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), - .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size, -}; - -static const u32 __wl_cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, - WLAN_CIPHER_SUITE_AES_CMAC, -}; - -/* function for reading/writing a single u32 from/to the dongle */ -static int -brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par) -{ - int err; - __le32 par_le = cpu_to_le32(*par); - - err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32)); - *par = le32_to_cpu(par_le); - - return err; -} - -static void convert_key_from_CPU(struct brcmf_wsec_key *key, - struct brcmf_wsec_key_le *key_le) -{ - key_le->index = cpu_to_le32(key->index); - key_le->len = cpu_to_le32(key->len); - key_le->algo = cpu_to_le32(key->algo); - key_le->flags = cpu_to_le32(key->flags); - key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi); - key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo); - key_le->iv_initialized = cpu_to_le32(key->iv_initialized); - memcpy(key_le->data, key->data, sizeof(key->data)); - memcpy(key_le->ea, key->ea, sizeof(key->ea)); -} - -static int send_key_to_dongle(struct net_device *ndev, - struct brcmf_wsec_key *key) -{ - int err; - struct brcmf_wsec_key_le key_le; - - convert_key_from_CPU(key, &key_le); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le)); - if (err) - WL_ERR("WLC_SET_KEY error (%d)\n", err); - return err; -} - -static s32 -brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct wireless_dev *wdev; - s32 infra = 0; - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - switch (type) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - WL_ERR("type (%d) : currently we do not support this type\n", - type); - return -EOPNOTSUPP; - case NL80211_IFTYPE_ADHOC: - cfg_priv->conf->mode = WL_MODE_IBSS; - infra = 0; - break; - case NL80211_IFTYPE_STATION: - cfg_priv->conf->mode = WL_MODE_BSS; - infra = 1; - break; - default: - err = -EINVAL; - goto done; - } - - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); - if (err) { - WL_ERR("WLC_SET_INFRA error (%d)\n", err); - err = -EAGAIN; - } else { - wdev = ndev->ieee80211_ptr; - wdev->iftype = type; - } - - WL_INFO("IF Type = %s\n", - (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); - -done: - WL_TRACE("Exit\n"); - - return err; -} - -static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val) -{ - s8 buf[BRCMF_DCMD_SMLEN]; - u32 len; - s32 err = 0; - __le32 val_le; - - val_le = cpu_to_le32(val); - len = brcmu_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf, - sizeof(buf)); - BUG_ON(!len); - - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); - if (err) - WL_ERR("error (%d)\n", err); - - return err; -} - -static s32 -brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval) -{ - union { - s8 buf[BRCMF_DCMD_SMLEN]; - __le32 val; - } var; - u32 len; - u32 data_null; - s32 err = 0; - - len = - brcmu_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), - sizeof(var.buf)); - BUG_ON(!len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len); - if (err) - WL_ERR("error (%d)\n", err); - - *retval = le32_to_cpu(var.val); - - return err; -} - -static void brcmf_set_mpc(struct net_device *ndev, int mpc) -{ - s32 err = 0; - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { - err = brcmf_dev_intvar_set(ndev, "mpc", mpc); - if (err) { - WL_ERR("fail to set mpc\n"); - return; - } - WL_INFO("MPC : %d\n", mpc); - } -} - -static void wl_iscan_prep(struct brcmf_scan_params_le *params_le, - struct brcmf_ssid *ssid) -{ - memcpy(params_le->bssid, ether_bcast, ETH_ALEN); - params_le->bss_type = DOT11_BSSTYPE_ANY; - params_le->scan_type = 0; - params_le->channel_num = 0; - params_le->nprobes = cpu_to_le32(-1); - params_le->active_time = cpu_to_le32(-1); - params_le->passive_time = cpu_to_le32(-1); - params_le->home_time = cpu_to_le32(-1); - if (ssid && ssid->SSID_len) - memcpy(¶ms_le->ssid_le, ssid, sizeof(struct brcmf_ssid)); -} - -static s32 -brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - - iolen = brcmu_mkiovar(iovar, param, paramlen, bufptr, buflen); - BUG_ON(!iolen); - - return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen); -} - -static s32 -brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - - iolen = brcmu_mkiovar(iovar, param, paramlen, bufptr, buflen); - BUG_ON(!iolen); - - return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen); -} - -static s32 -brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, - struct brcmf_ssid *ssid, u16 action) -{ - s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + - offsetof(struct brcmf_iscan_params_le, params_le); - struct brcmf_iscan_params_le *params; - s32 err = 0; - - if (ssid && ssid->SSID_len) - params_size += sizeof(struct brcmf_ssid); - params = kzalloc(params_size, GFP_KERNEL); - if (!params) - return -ENOMEM; - BUG_ON(params_size >= BRCMF_DCMD_SMLEN); - - wl_iscan_prep(¶ms->params_le, ssid); - - params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION); - params->action = cpu_to_le16(action); - params->scan_duration = cpu_to_le16(0); - - err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size, - iscan->dcmd_buf, BRCMF_DCMD_SMLEN); - if (err) { - if (err == -EBUSY) - WL_INFO("system busy : iscan canceled\n"); - else - WL_ERR("error (%d)\n", err); - } - - kfree(params); - return err; -} - -static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - struct brcmf_ssid ssid; - s32 passive_scan; - s32 err = 0; - - /* Broadcast scan by default */ - memset(&ssid, 0, sizeof(ssid)); - - iscan->state = WL_ISCAN_STATE_SCANING; - - passive_scan = cfg_priv->active_scan ? 0 : 1; - err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - brcmf_set_mpc(ndev, 0); - cfg_priv->iscan_kickstart = true; - err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); - if (err) { - brcmf_set_mpc(ndev, 1); - cfg_priv->iscan_kickstart = false; - return err; - } - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - return err; -} - -static s32 -__brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int; - s32 passive_scan; - bool iscan_req; - bool spec_scan; - s32 err = 0; - u32 SSID_len; - - if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { - WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); - return -EAGAIN; - } - if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) { - WL_ERR("Scanning being aborted : status (%lu)\n", - cfg_priv->status); - return -EAGAIN; - } - if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { - WL_ERR("Connecting : status (%lu)\n", - cfg_priv->status); - return -EAGAIN; - } - - iscan_req = false; - spec_scan = false; - if (request) { - /* scan bss */ - ssids = request->ssids; - if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len)) - iscan_req = true; - } else { - /* scan in ibss */ - /* we don't do iscan in ibss */ - ssids = this_ssid; - } - - cfg_priv->scan_request = request; - set_bit(WL_STATUS_SCANNING, &cfg_priv->status); - if (iscan_req) { - err = brcmf_do_iscan(cfg_priv); - if (!err) - return err; - else - goto scan_out; - } else { - WL_SCAN("ssid \"%s\", ssid_len (%d)\n", - ssids->ssid, ssids->ssid_len); - memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); - SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); - sr->ssid_le.SSID_len = cpu_to_le32(0); - if (SSID_len) { - memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len); - sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); - spec_scan = true; - } else { - WL_SCAN("Broadcast scan\n"); - } - - passive_scan = cfg_priv->active_scan ? 0 : 1; - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); - if (err) { - WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); - goto scan_out; - } - brcmf_set_mpc(ndev, 0); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, - sizeof(sr->ssid_le)); - if (err) { - if (err == -EBUSY) - WL_INFO("system busy : scan for \"%s\" " - "canceled\n", sr->ssid_le.SSID); - else - WL_ERR("WLC_SCAN error (%d)\n", err); - - brcmf_set_mpc(ndev, 1); - goto scan_out; - } - } - - return 0; - -scan_out: - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - cfg_priv->scan_request = NULL; - return err; -} - -static s32 -brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request) -{ - s32 err = 0; - - WL_TRACE("Enter\n"); - - if (!check_sys_up(wiphy)) - return -EIO; - - err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL); - if (err) - WL_ERR("scan error (%d)\n", err); - - WL_TRACE("Exit\n"); - return err; -} - -static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold) -{ - s32 err = 0; - - err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold); - if (err) - WL_ERR("Error (%d)\n", err); - - return err; -} - -static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) -{ - s32 err = 0; - - err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold); - if (err) - WL_ERR("Error (%d)\n", err); - - return err; -} - -static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) -{ - s32 err = 0; - u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); - - err = brcmf_exec_dcmd_u32(ndev, cmd, &retry); - if (err) { - WL_ERR("cmd (%d) , error (%d)\n", cmd, err); - return err; - } - return err; -} - -static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - if (changed & WIPHY_PARAM_RTS_THRESHOLD && - (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) { - cfg_priv->conf->rts_threshold = wiphy->rts_threshold; - err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold); - if (!err) - goto done; - } - if (changed & WIPHY_PARAM_FRAG_THRESHOLD && - (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) { - cfg_priv->conf->frag_threshold = wiphy->frag_threshold; - err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold); - if (!err) - goto done; - } - if (changed & WIPHY_PARAM_RETRY_LONG - && (cfg_priv->conf->retry_long != wiphy->retry_long)) { - cfg_priv->conf->retry_long = wiphy->retry_long; - err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true); - if (!err) - goto done; - } - if (changed & WIPHY_PARAM_RETRY_SHORT - && (cfg_priv->conf->retry_short != wiphy->retry_short)) { - cfg_priv->conf->retry_short = wiphy->retry_short; - err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false); - if (!err) - goto done; - } - -done: - WL_TRACE("Exit\n"); - return err; -} - -static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) -{ - switch (item) { - case WL_PROF_SEC: - return &cfg_priv->profile->sec; - case WL_PROF_BSSID: - return &cfg_priv->profile->bssid; - case WL_PROF_SSID: - return &cfg_priv->profile->ssid; - } - WL_ERR("invalid item (%d)\n", item); - return NULL; -} - -static s32 -brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e, void *data, s32 item) -{ - s32 err = 0; - struct brcmf_ssid *ssid; - - switch (item) { - case WL_PROF_SSID: - ssid = (struct brcmf_ssid *) data; - memset(cfg_priv->profile->ssid.SSID, 0, - sizeof(cfg_priv->profile->ssid.SSID)); - memcpy(cfg_priv->profile->ssid.SSID, - ssid->SSID, ssid->SSID_len); - cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; - break; - case WL_PROF_BSSID: - if (data) - memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); - else - memset(cfg_priv->profile->bssid, 0, ETH_ALEN); - break; - case WL_PROF_SEC: - memcpy(&cfg_priv->profile->sec, data, - sizeof(cfg_priv->profile->sec)); - break; - case WL_PROF_BEACONINT: - cfg_priv->profile->beacon_interval = *(u16 *)data; - break; - case WL_PROF_DTIMPERIOD: - cfg_priv->profile->dtim_period = *(u8 *)data; - break; - default: - WL_ERR("unsupported item (%d)\n", item); - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) -{ - memset(prof, 0, sizeof(*prof)); -} - -static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, - size_t *join_params_size) -{ - u16 chanspec = 0; - - if (ch != 0) { - if (ch <= CH_MAX_2G_CHANNEL) - chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; - - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + - sizeof(u16); - - chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); - join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); - join_params->params_le.chanspec_num = cpu_to_le32(1); - - WL_CONN("join_params->params.chanspec_list[0]= %#X," - "channel %d, chanspec %#X\n", - chanspec, ch, chanspec); - } -} - -static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct net_device *ndev = NULL; - s32 err = 0; - - WL_TRACE("Enter\n"); - - if (cfg_priv->link_up) { - ndev = cfg_to_ndev(cfg_priv); - WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); - err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0); - if (err) - WL_ERR("WLC_DISASSOC failed (%d)\n", err); - cfg_priv->link_up = false; - } - WL_TRACE("Exit\n"); -} - -static s32 -brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_ibss_params *params) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct brcmf_join_params join_params; - size_t join_params_size = 0; - s32 err = 0; - s32 wsec = 0; - s32 bcnprd; - struct brcmf_ssid ssid; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - if (params->ssid) - WL_CONN("SSID: %s\n", params->ssid); - else { - WL_CONN("SSID: NULL, Not supported\n"); - return -EOPNOTSUPP; - } - - set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - - if (params->bssid) - WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n", - params->bssid[0], params->bssid[1], params->bssid[2], - params->bssid[3], params->bssid[4], params->bssid[5]); - else - WL_CONN("No BSSID specified\n"); - - if (params->channel) - WL_CONN("channel: %d\n", params->channel->center_freq); - else - WL_CONN("no channel specified\n"); - - if (params->channel_fixed) - WL_CONN("fixed channel required\n"); - else - WL_CONN("no fixed channel required\n"); - - if (params->ie && params->ie_len) - WL_CONN("ie len: %d\n", params->ie_len); - else - WL_CONN("no ie specified\n"); - - if (params->beacon_interval) - WL_CONN("beacon interval: %d\n", params->beacon_interval); - else - WL_CONN("no beacon interval specified\n"); - - if (params->basic_rates) - WL_CONN("basic rates: %08X\n", params->basic_rates); - else - WL_CONN("no basic rates specified\n"); - - if (params->privacy) - WL_CONN("privacy required\n"); - else - WL_CONN("no privacy required\n"); - - /* Configure Privacy for starter */ - if (params->privacy) - wsec |= WEP_ENABLED; - - err = brcmf_dev_intvar_set(ndev, "wsec", wsec); - if (err) { - WL_ERR("wsec failed (%d)\n", err); - goto done; - } - - /* Configure Beacon Interval for starter */ - if (params->beacon_interval) - bcnprd = params->beacon_interval; - else - bcnprd = 100; - - err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd); - if (err) { - WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); - goto done; - } - - /* Configure required join parameter */ - memset(&join_params, 0, sizeof(struct brcmf_join_params)); - - /* SSID */ - ssid.SSID_len = min_t(u32, params->ssid_len, 32); - memcpy(ssid.SSID, params->ssid, ssid.SSID_len); - memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len); - join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); - join_params_size = sizeof(join_params.ssid_le); - brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); - - /* BSSID */ - if (params->bssid) { - memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN); - join_params_size = sizeof(join_params.ssid_le) + - BRCMF_ASSOC_PARAMS_FIXED_SIZE; - } else { - memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); - } - - brcmf_update_prof(cfg_priv, NULL, - &join_params.params_le.bssid, WL_PROF_BSSID); - - /* Channel */ - if (params->channel) { - u32 target_channel; - - cfg_priv->channel = - ieee80211_frequency_to_channel( - params->channel->center_freq); - if (params->channel_fixed) { - /* adding chanspec */ - brcmf_ch_to_chanspec(cfg_priv->channel, - &join_params, &join_params_size); - } - - /* set channel for starter */ - target_channel = cfg_priv->channel; - err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL, - &target_channel); - if (err) { - WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); - goto done; - } - } else - cfg_priv->channel = 0; - - cfg_priv->ibss_starter = false; - - - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, - &join_params, join_params_size); - if (err) { - WL_ERR("WLC_SET_SSID failed (%d)\n", err); - goto done; - } - -done: - if (err) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - brcmf_link_down(cfg_priv); - - WL_TRACE("Exit\n"); - - return err; -} - -static s32 brcmf_set_wpa_version(struct net_device *ndev, - struct cfg80211_connect_params *sme) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - struct brcmf_cfg80211_security *sec; - s32 val = 0; - s32 err = 0; - - if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) - val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; - else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) - val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; - else - val = WPA_AUTH_DISABLED; - WL_CONN("setting wpa_auth to 0x%0x\n", val); - err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); - if (err) { - WL_ERR("set wpa_auth failed (%d)\n", err); - return err; - } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); - sec->wpa_versions = sme->crypto.wpa_versions; - return err; -} - -static s32 brcmf_set_auth_type(struct net_device *ndev, - struct cfg80211_connect_params *sme) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - struct brcmf_cfg80211_security *sec; - s32 val = 0; - s32 err = 0; - - switch (sme->auth_type) { - case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = 0; - WL_CONN("open system\n"); - break; - case NL80211_AUTHTYPE_SHARED_KEY: - val = 1; - WL_CONN("shared key\n"); - break; - case NL80211_AUTHTYPE_AUTOMATIC: - val = 2; - WL_CONN("automatic\n"); - break; - case NL80211_AUTHTYPE_NETWORK_EAP: - WL_CONN("network eap\n"); - default: - val = 2; - WL_ERR("invalid auth type (%d)\n", sme->auth_type); - break; - } - - err = brcmf_dev_intvar_set(ndev, "auth", val); - if (err) { - WL_ERR("set auth failed (%d)\n", err); - return err; - } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); - sec->auth_type = sme->auth_type; - return err; -} - -static s32 -brcmf_set_set_cipher(struct net_device *ndev, - struct cfg80211_connect_params *sme) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - struct brcmf_cfg80211_security *sec; - s32 pval = 0; - s32 gval = 0; - s32 err = 0; - - if (sme->crypto.n_ciphers_pairwise) { - switch (sme->crypto.ciphers_pairwise[0]) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - pval = WEP_ENABLED; - break; - case WLAN_CIPHER_SUITE_TKIP: - pval = TKIP_ENABLED; - break; - case WLAN_CIPHER_SUITE_CCMP: - pval = AES_ENABLED; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - pval = AES_ENABLED; - break; - default: - WL_ERR("invalid cipher pairwise (%d)\n", - sme->crypto.ciphers_pairwise[0]); - return -EINVAL; - } - } - if (sme->crypto.cipher_group) { - switch (sme->crypto.cipher_group) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - gval = WEP_ENABLED; - break; - case WLAN_CIPHER_SUITE_TKIP: - gval = TKIP_ENABLED; - break; - case WLAN_CIPHER_SUITE_CCMP: - gval = AES_ENABLED; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - gval = AES_ENABLED; - break; - default: - WL_ERR("invalid cipher group (%d)\n", - sme->crypto.cipher_group); - return -EINVAL; - } - } - - WL_CONN("pval (%d) gval (%d)\n", pval, gval); - err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); - sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; - sec->cipher_group = sme->crypto.cipher_group; - - return err; -} - -static s32 -brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - struct brcmf_cfg80211_security *sec; - s32 val = 0; - s32 err = 0; - - if (sme->crypto.n_akm_suites) { - err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val); - if (err) { - WL_ERR("could not get wpa_auth (%d)\n", err); - return err; - } - if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_PSK: - val = WPA_AUTH_PSK; - break; - default: - WL_ERR("invalid cipher group (%d)\n", - sme->crypto.cipher_group); - return -EINVAL; - } - } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: - val = WPA2_AUTH_UNSPECIFIED; - break; - case WLAN_AKM_SUITE_PSK: - val = WPA2_AUTH_PSK; - break; - default: - WL_ERR("invalid cipher group (%d)\n", - sme->crypto.cipher_group); - return -EINVAL; - } - } - - WL_CONN("setting wpa_auth to %d\n", val); - err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); - if (err) { - WL_ERR("could not set wpa_auth (%d)\n", err); - return err; - } - } - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); - sec->wpa_auth = sme->crypto.akm_suites[0]; - - return err; -} - -static s32 -brcmf_set_set_sharedkey(struct net_device *ndev, - struct cfg80211_connect_params *sme) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - struct brcmf_cfg80211_security *sec; - struct brcmf_wsec_key key; - s32 val; - s32 err = 0; - - WL_CONN("key len (%d)\n", sme->key_len); - if (sme->key_len) { - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); - WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n", - sec->wpa_versions, sec->cipher_pairwise); - if (! - (sec->wpa_versions & (NL80211_WPA_VERSION_1 | - NL80211_WPA_VERSION_2)) -&& (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | - WLAN_CIPHER_SUITE_WEP104))) { - memset(&key, 0, sizeof(key)); - key.len = (u32) sme->key_len; - key.index = (u32) sme->key_idx; - if (key.len > sizeof(key.data)) { - WL_ERR("Too long key length (%u)\n", key.len); - return -EINVAL; - } - memcpy(key.data, sme->key, key.len); - key.flags = BRCMF_PRIMARY_KEY; - switch (sec->cipher_pairwise) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - break; - default: - WL_ERR("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0]); - return -EINVAL; - } - /* Set the new key/index */ - WL_CONN("key length (%d) key index (%d) algo (%d)\n", - key.len, key.index, key.algo); - WL_CONN("key \"%s\"\n", key.data); - err = send_key_to_dongle(ndev, &key); - if (err) - return err; - - if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { - WL_CONN("set auth_type to shared key\n"); - val = 1; /* shared key */ - err = brcmf_dev_intvar_set(ndev, "auth", val); - if (err) { - WL_ERR("set auth failed (%d)\n", err); - return err; - } - } - } - } - return err; -} - -static s32 -brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_connect_params *sme) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct ieee80211_channel *chan = sme->channel; - struct brcmf_join_params join_params; - size_t join_params_size; - struct brcmf_ssid ssid; - - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - if (!sme->ssid) { - WL_ERR("Invalid ssid\n"); - return -EOPNOTSUPP; - } - - set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - - if (chan) { - cfg_priv->channel = - ieee80211_frequency_to_channel(chan->center_freq); - WL_CONN("channel (%d), center_req (%d)\n", - cfg_priv->channel, chan->center_freq); - } else - cfg_priv->channel = 0; - - WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); - - err = brcmf_set_wpa_version(ndev, sme); - if (err) { - WL_ERR("wl_set_wpa_version failed (%d)\n", err); - goto done; - } - - err = brcmf_set_auth_type(ndev, sme); - if (err) { - WL_ERR("wl_set_auth_type failed (%d)\n", err); - goto done; - } - - err = brcmf_set_set_cipher(ndev, sme); - if (err) { - WL_ERR("wl_set_set_cipher failed (%d)\n", err); - goto done; - } - - err = brcmf_set_key_mgmt(ndev, sme); - if (err) { - WL_ERR("wl_set_key_mgmt failed (%d)\n", err); - goto done; - } - - err = brcmf_set_set_sharedkey(ndev, sme); - if (err) { - WL_ERR("wl_set_set_sharedkey failed (%d)\n", err); - goto done; - } - - memset(&join_params, 0, sizeof(join_params)); - join_params_size = sizeof(join_params.ssid_le); - - ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len); - memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len); - memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len); - join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); - brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); - - memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); - - if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) - WL_CONN("ssid \"%s\", len (%d)\n", - ssid.SSID, ssid.SSID_len); - - brcmf_ch_to_chanspec(cfg_priv->channel, - &join_params, &join_params_size); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, - &join_params, join_params_size); - if (err) - WL_ERR("WLC_SET_SSID failed (%d)\n", err); - -done: - if (err) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, - u16 reason_code) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct brcmf_scb_val_le scbval; - s32 err = 0; - - WL_TRACE("Enter. Reason code = %d\n", reason_code); - if (!check_sys_up(wiphy)) - return -EIO; - - clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status); - - memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN); - scbval.val = cpu_to_le32(reason_code); - err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval, - sizeof(struct brcmf_scb_val_le)); - if (err) - WL_ERR("error (%d)\n", err); - - cfg_priv->link_up = false; - - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, s32 dbm) -{ - - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - u16 txpwrmw; - s32 err = 0; - s32 disable = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - switch (type) { - case NL80211_TX_POWER_AUTOMATIC: - break; - case NL80211_TX_POWER_LIMITED: - if (dbm < 0) { - WL_ERR("TX_POWER_LIMITED - dbm is negative\n"); - err = -EINVAL; - goto done; - } - break; - case NL80211_TX_POWER_FIXED: - if (dbm < 0) { - WL_ERR("TX_POWER_FIXED - dbm is negative\n"); - err = -EINVAL; - goto done; - } - break; - } - /* Make sure radio is off or on as far as software is concerned */ - disable = WL_RADIO_SW_DISABLE << 16; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable); - if (err) - WL_ERR("WLC_SET_RADIO error (%d)\n", err); - - if (dbm > 0xffff) - txpwrmw = 0xffff; - else - txpwrmw = (u16) dbm; - err = brcmf_dev_intvar_set(ndev, "qtxpower", - (s32) (brcmu_mw_to_qdbm(txpwrmw))); - if (err) - WL_ERR("qtxpower error (%d)\n", err); - cfg_priv->conf->tx_power = dbm; - -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - s32 txpwrdbm; - u8 result; - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); - if (err) { - WL_ERR("error (%d)\n", err); - goto done; - } - - result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); - *dbm = (s32) brcmu_qdbm_to_mw(result); - -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool unicast, bool multicast) -{ - u32 index; - u32 wsec; - s32 err = 0; - - WL_TRACE("Enter\n"); - WL_CONN("key index (%d)\n", key_idx); - if (!check_sys_up(wiphy)) - return -EIO; - - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); - if (err) { - WL_ERR("WLC_GET_WSEC error (%d)\n", err); - goto done; - } - - if (wsec & WEP_ENABLED) { - /* Just select a new current key */ - index = key_idx; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY, - &index); - if (err) - WL_ERR("error (%d)\n", err); - } -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, const u8 *mac_addr, struct key_params *params) -{ - struct brcmf_wsec_key key; - struct brcmf_wsec_key_le key_le; - s32 err = 0; - - memset(&key, 0, sizeof(key)); - key.index = (u32) key_idx; - /* Instead of bcast for ea address for default wep keys, - driver needs it to be Null */ - if (!is_multicast_ether_addr(mac_addr)) - memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); - key.len = (u32) params->key_len; - /* check for key index change */ - if (key.len == 0) { - /* key delete */ - err = send_key_to_dongle(ndev, &key); - if (err) - return err; - } else { - if (key.len > sizeof(key.data)) { - WL_ERR("Invalid key length (%d)\n", key.len); - return -EINVAL; - } - - WL_CONN("Setting the key index %d\n", key.index); - memcpy(key.data, params->key, key.len); - - if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { - u8 keybuf[8]; - memcpy(keybuf, &key.data[24], sizeof(keybuf)); - memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); - memcpy(&key.data[16], keybuf, sizeof(keybuf)); - } - - /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ - if (params->seq && params->seq_len == 6) { - /* rx iv */ - u8 *ivptr; - ivptr = (u8 *) params->seq; - key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | - (ivptr[3] << 8) | ivptr[2]; - key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; - key.iv_initialized = true; - } - - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); - break; - case WLAN_CIPHER_SUITE_TKIP: - key.algo = CRYPTO_ALGO_TKIP; - WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); - break; - default: - WL_ERR("Invalid cipher (0x%x)\n", params->cipher); - return -EINVAL; - } - convert_key_from_CPU(&key, &key_le); - - brcmf_netdev_wait_pend8021x(ndev); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, - sizeof(key_le)); - if (err) { - WL_ERR("WLC_SET_KEY error (%d)\n", err); - return err; - } - } - return err; -} - -static s32 -brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params) -{ - struct brcmf_wsec_key key; - s32 val; - s32 wsec; - s32 err = 0; - u8 keybuf[8]; - - WL_TRACE("Enter\n"); - WL_CONN("key index (%d)\n", key_idx); - if (!check_sys_up(wiphy)) - return -EIO; - - if (mac_addr) { - WL_TRACE("Exit"); - return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); - } - memset(&key, 0, sizeof(key)); - - key.len = (u32) params->key_len; - key.index = (u32) key_idx; - - if (key.len > sizeof(key.data)) { - WL_ERR("Too long key length (%u)\n", key.len); - err = -EINVAL; - goto done; - } - memcpy(key.data, params->key, key.len); - - key.flags = BRCMF_PRIMARY_KEY; - switch (params->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; - WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); - break; - case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; - WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); - break; - case WLAN_CIPHER_SUITE_TKIP: - memcpy(keybuf, &key.data[24], sizeof(keybuf)); - memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); - memcpy(&key.data[16], keybuf, sizeof(keybuf)); - key.algo = CRYPTO_ALGO_TKIP; - WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); - break; - case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; - WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); - break; - default: - WL_ERR("Invalid cipher (0x%x)\n", params->cipher); - err = -EINVAL; - goto done; - } - - err = send_key_to_dongle(ndev, &key); /* Set the new key/index */ - if (err) - goto done; - - val = WEP_ENABLED; - err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); - if (err) { - WL_ERR("get wsec error (%d)\n", err); - goto done; - } - wsec &= ~(WEP_ENABLED); - wsec |= val; - err = brcmf_dev_intvar_set(ndev, "wsec", wsec); - if (err) { - WL_ERR("set wsec error (%d)\n", err); - goto done; - } - - val = 1; /* assume shared key. otherwise 0 */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); - if (err) - WL_ERR("WLC_SET_AUTH error (%d)\n", err); -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool pairwise, const u8 *mac_addr) -{ - struct brcmf_wsec_key key; - s32 err = 0; - s32 val; - s32 wsec; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - memset(&key, 0, sizeof(key)); - - key.index = (u32) key_idx; - key.flags = BRCMF_PRIMARY_KEY; - key.algo = CRYPTO_ALGO_OFF; - - WL_CONN("key index (%d)\n", key_idx); - - /* Set the new key/index */ - err = send_key_to_dongle(ndev, &key); - if (err) { - if (err == -EINVAL) { - if (key.index >= DOT11_MAX_DEFAULT_KEYS) - /* we ignore this key index in this case */ - WL_ERR("invalid key index (%d)\n", key_idx); - } - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - goto done; - } - - val = 0; - err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); - if (err) { - WL_ERR("get wsec error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - goto done; - } - wsec &= ~(WEP_ENABLED); - wsec |= val; - err = brcmf_dev_intvar_set(ndev, "wsec", wsec); - if (err) { - WL_ERR("set wsec error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - goto done; - } - - val = 0; /* assume open key. otherwise 1 */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); - if (err) { - WL_ERR("WLC_SET_AUTH error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - } -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, - void (*callback) (void *cookie, struct key_params * params)) -{ - struct key_params params; - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct brcmf_cfg80211_security *sec; - s32 wsec; - s32 err = 0; - - WL_TRACE("Enter\n"); - WL_CONN("key index (%d)\n", key_idx); - if (!check_sys_up(wiphy)) - return -EIO; - - memset(¶ms, 0, sizeof(params)); - - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); - if (err) { - WL_ERR("WLC_GET_WSEC error (%d)\n", err); - /* Ignore this error, may happen during DISASSOC */ - err = -EAGAIN; - goto done; - } - switch (wsec) { - case WEP_ENABLED: - sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); - if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { - params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); - } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { - params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); - } - break; - case TKIP_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_TKIP; - WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); - break; - case AES_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; - WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); - break; - default: - WL_ERR("Invalid algo (0x%x)\n", wsec); - err = -EINVAL; - goto done; - } - callback(cookie, ¶ms); - -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *ndev, u8 key_idx) -{ - WL_INFO("Not supported\n"); - - return -EOPNOTSUPP; -} - -static s32 -brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac, struct station_info *sinfo) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct brcmf_scb_val_le scb_val; - int rssi; - s32 rate; - s32 err = 0; - u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID); - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - if (memcmp(mac, bssid, ETH_ALEN)) { - WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X" - "wl_bssid-%X:%X:%X:%X:%X:%X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - bssid[0], bssid[1], bssid[2], bssid[3], - bssid[4], bssid[5]); - err = -ENOENT; - goto done; - } - - /* Report the current tx rate */ - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); - if (err) { - WL_ERR("Could not get rate (%d)\n", err); - } else { - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_CONN("Rate %d Mbps\n", rate / 2); - } - - if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { - scb_val.val = cpu_to_le32(0); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, - sizeof(struct brcmf_scb_val_le)); - if (err) - WL_ERR("Could not get rssi (%d)\n", err); - - rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_CONN("RSSI %d dBm\n", rssi); - } - -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, - bool enabled, s32 timeout) -{ - s32 pm; - s32 err = 0; - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - - WL_TRACE("Enter\n"); - - /* - * Powersave enable/disable request is coming from the - * cfg80211 even before the interface is up. In that - * scenario, driver will be storing the power save - * preference in cfg_priv struct to apply this to - * FW later while initializing the dongle - */ - cfg_priv->pwr_save = enabled; - if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { - - WL_INFO("Device is not ready," - "storing the value in cfg_priv struct\n"); - goto done; - } - - pm = enabled ? PM_FAST : PM_OFF; - WL_INFO("power save %s\n", (pm ? "enabled" : "disabled")); - - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm); - if (err) { - if (err == -ENODEV) - WL_ERR("net_device is not ready yet\n"); - else - WL_ERR("error (%d)\n", err); - } -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, - const u8 *addr, - const struct cfg80211_bitrate_mask *mask) -{ - struct brcm_rateset_le rateset_le; - s32 rate; - s32 val; - s32 err_bg; - s32 err_a; - u32 legacy; - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - /* addr param is always NULL. ignore it */ - /* Get current rateset */ - err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le, - sizeof(rateset_le)); - if (err) { - WL_ERR("could not get current rateset (%d)\n", err); - goto done; - } - - legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF); - if (!legacy) - legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy & - 0xFFFF); - - val = wl_g_rates[legacy - 1].bitrate * 100000; - - if (val < le32_to_cpu(rateset_le.count)) - /* Select rate by rateset index */ - rate = rateset_le.rates[val] & 0x7f; - else - /* Specified rate in bps */ - rate = val / 500000; - - WL_CONN("rate %d mbps\n", rate / 2); - - /* - * - * Set rate override, - * Since the is a/b/g-blind, both a/bg_rate are enforced. - */ - err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate); - err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate); - if (err_bg && err_a) { - WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a); - err = err_bg | err_a; - } - -done: - WL_TRACE("Exit\n"); - return err; -} - -static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, - struct brcmf_bss_info *bi) -{ - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); - struct ieee80211_channel *notify_channel; - struct cfg80211_bss *bss; - struct ieee80211_supported_band *band; - s32 err = 0; - u16 channel; - u32 freq; - u64 notify_timestamp; - u16 notify_capability; - u16 notify_interval; - u8 *notify_ie; - size_t notify_ielen; - s32 notify_signal; - - if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { - WL_ERR("Bss info is larger than buffer. Discarding\n"); - return 0; - } - - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); - - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - - freq = ieee80211_channel_to_frequency(channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); - - notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ - notify_capability = le16_to_cpu(bi->capability); - notify_interval = le16_to_cpu(bi->beacon_period); - notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); - notify_ielen = le32_to_cpu(bi->ie_length); - notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - - WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], - bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); - WL_CONN("Channel: %d(%d)\n", channel, freq); - WL_CONN("Capability: %X\n", notify_capability); - WL_CONN("Beacon interval: %d\n", notify_interval); - WL_CONN("Signal: %d\n", notify_signal); - WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); - - bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, - notify_timestamp, notify_capability, notify_interval, notify_ie, - notify_ielen, notify_signal, GFP_KERNEL); - - if (!bss) { - WL_ERR("cfg80211_inform_bss_frame error\n"); - return -EINVAL; - } - - return err; -} - -static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_scan_results *bss_list; - struct brcmf_bss_info *bi = NULL; /* must be initialized */ - s32 err = 0; - int i; - - bss_list = cfg_priv->bss_list; - if (bss_list->version != BRCMF_BSS_INFO_VERSION) { - WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", - bss_list->version); - return -EOPNOTSUPP; - } - WL_SCAN("scanned AP count (%d)\n", bss_list->count); - for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) { - bi = next_bss(bss_list, bi); - err = brcmf_inform_single_bss(cfg_priv, bi); - if (err) - break; - } - return err; -} - -static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, const u8 *bssid) -{ - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); - struct ieee80211_channel *notify_channel; - struct brcmf_bss_info *bi = NULL; - struct ieee80211_supported_band *band; - u8 *buf = NULL; - s32 err = 0; - u16 channel; - u32 freq; - u64 notify_timestamp; - u16 notify_capability; - u16 notify_interval; - u8 *notify_ie; - size_t notify_ielen; - s32 notify_signal; - - WL_TRACE("Enter\n"); - - buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (buf == NULL) { - err = -ENOMEM; - goto CleanUp; - } - - *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); - - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); - if (err) { - WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); - goto CleanUp; - } - - bi = (struct brcmf_bss_info *)(buf + 4); - - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); - - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - - freq = ieee80211_channel_to_frequency(channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); - - notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ - notify_capability = le16_to_cpu(bi->capability); - notify_interval = le16_to_cpu(bi->beacon_period); - notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); - notify_ielen = le32_to_cpu(bi->ie_length); - notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - - WL_CONN("channel: %d(%d)\n", channel, freq); - WL_CONN("capability: %X\n", notify_capability); - WL_CONN("beacon interval: %d\n", notify_interval); - WL_CONN("signal: %d\n", notify_signal); - WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); - - cfg80211_inform_bss(wiphy, notify_channel, bssid, - notify_timestamp, notify_capability, notify_interval, - notify_ie, notify_ielen, notify_signal, GFP_KERNEL); - -CleanUp: - - kfree(buf); - - WL_TRACE("Exit\n"); - - return err; -} - -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) -{ - return cfg_priv->conf->mode == WL_MODE_IBSS; -} - -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_bss_info *bi; - struct brcmf_ssid *ssid; - struct brcmu_tlv *tim; - u16 beacon_interval; - u8 dtim_period; - size_t ie_len; - u8 *ie; - s32 err = 0; - - WL_TRACE("Enter\n"); - if (brcmf_is_ibssmode(cfg_priv)) - return err; - - ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); - - *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); - err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, - cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); - if (err) { - WL_ERR("Could not get bss info %d\n", err); - goto update_bss_info_out; - } - - bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4); - err = brcmf_inform_single_bss(cfg_priv, bi); - if (err) - goto update_bss_info_out; - - ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); - ie_len = le32_to_cpu(bi->ie_length); - beacon_interval = le16_to_cpu(bi->beacon_period); - - tim = brcmu_parse_tlvs(ie, ie_len, WLAN_EID_TIM); - if (tim) - dtim_period = tim->data[1]; - else { - /* - * active scan was done so we could not get dtim - * information out of probe response. - * so we speficially query dtim information to dongle. - */ - u32 var; - err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), - "dtim_assoc", &var); - if (err) { - WL_ERR("wl dtim_assoc failed (%d)\n", err); - goto update_bss_info_out; - } - dtim_period = (u8)var; - } - - brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); - brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); - -update_bss_info_out: - WL_TRACE("Exit"); - return err; -} - -static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - struct brcmf_ssid ssid; - - if (cfg_priv->iscan_on) { - iscan->state = WL_ISCAN_STATE_IDLE; - - if (iscan->timer_on) { - del_timer_sync(&iscan->timer); - iscan->timer_on = 0; - } - - cancel_work_sync(&iscan->work); - - /* Abort iscan running in FW */ - memset(&ssid, 0, sizeof(ssid)); - brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); - } -} - -static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, - bool aborted) -{ - struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { - WL_ERR("Scan complete while device not scanning\n"); - return; - } - if (cfg_priv->scan_request) { - WL_SCAN("ISCAN Completed scan: %s\n", - aborted ? "Aborted" : "Done"); - cfg80211_scan_done(cfg_priv->scan_request, aborted); - brcmf_set_mpc(ndev, 1); - cfg_priv->scan_request = NULL; - } - cfg_priv->iscan_kickstart = false; -} - -static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) -{ - if (iscan->state != WL_ISCAN_STATE_IDLE) { - WL_SCAN("wake up iscan\n"); - schedule_work(&iscan->work); - return 0; - } - - return -EIO; -} - -static s32 -brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, - struct brcmf_scan_results **bss_list) -{ - struct brcmf_iscan_results list; - struct brcmf_scan_results *results; - struct brcmf_scan_results_le *results_le; - struct brcmf_iscan_results *list_buf; - s32 err = 0; - - memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); - list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; - results = &list_buf->results; - results_le = &list_buf->results_le; - results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; - results->version = 0; - results->count = 0; - - memset(&list, 0, sizeof(list)); - list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); - err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list, - BRCMF_ISCAN_RESULTS_FIXED_SIZE, - iscan->scan_buf, WL_ISCAN_BUF_MAX); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - results->buflen = le32_to_cpu(results_le->buflen); - results->version = le32_to_cpu(results_le->version); - results->count = le32_to_cpu(results_le->count); - WL_SCAN("results->count = %d\n", results_le->count); - WL_SCAN("results->buflen = %d\n", results_le->buflen); - *status = le32_to_cpu(list_buf->status_le); - WL_SCAN("status = %d\n", *status); - *bss_list = results; - - return err; -} - -static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - brcmf_inform_bss(cfg_priv); - brcmf_notify_iscan_complete(iscan, false); - - return err; -} - -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - - return err; -} - -static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - brcmf_inform_bss(cfg_priv); - brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); - /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - - return err; -} - -static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - brcmf_notify_iscan_complete(iscan, true); - - return err; -} - -static void brcmf_cfg80211_iscan_handler(struct work_struct *work) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = - container_of(work, struct brcmf_cfg80211_iscan_ctrl, - work); - struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); - struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; - u32 status = BRCMF_SCAN_RESULTS_PARTIAL; - - if (iscan->timer_on) { - del_timer_sync(&iscan->timer); - iscan->timer_on = 0; - } - - if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) { - status = BRCMF_SCAN_RESULTS_ABORTED; - WL_ERR("Abort iscan\n"); - } - - el->handler[status](cfg_priv); -} - -static void brcmf_iscan_timer(unsigned long data) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = - (struct brcmf_cfg80211_iscan_ctrl *)data; - - if (iscan) { - iscan->timer_on = 0; - WL_SCAN("timer expired\n"); - brcmf_wakeup_iscan(iscan); - } -} - -static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - - if (cfg_priv->iscan_on) { - iscan->state = WL_ISCAN_STATE_IDLE; - INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); - } - - return 0; -} - -static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) -{ - memset(el, 0, sizeof(*el)); - el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; - el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; - el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; - el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; - el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; -} - -static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - int err = 0; - - if (cfg_priv->iscan_on) { - iscan->ndev = cfg_to_ndev(cfg_priv); - brcmf_init_iscan_eloop(&iscan->el); - iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; - init_timer(&iscan->timer); - iscan->timer.data = (unsigned long) iscan; - iscan->timer.function = brcmf_iscan_timer; - err = brcmf_invoke_iscan(cfg_priv); - if (!err) - iscan->data = cfg_priv; - } - - return err; -} - -static void brcmf_delay(u32 ms) -{ - if (ms < 1000 / HZ) { - cond_resched(); - mdelay(ms); - } else { - msleep(ms); - } -} - -static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - - /* - * Check for WL_STATUS_READY before any function call which - * could result is bus access. Don't block the resume for - * any driver error conditions - */ - WL_TRACE("Enter\n"); - - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) - brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); - - WL_TRACE("Exit\n"); - return 0; -} - -static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, - struct cfg80211_wowlan *wow) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - - WL_TRACE("Enter\n"); - - /* - * Check for WL_STATUS_READY before any function call which - * could result is bus access. Don't block the suspend for - * any driver error conditions - */ - - /* - * While going to suspend if associated with AP disassociate - * from AP to save power while system is in suspended state - */ - if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || - test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && - test_bit(WL_STATUS_READY, &cfg_priv->status)) { - WL_INFO("Disassociating from AP" - " while entering suspend state\n"); - brcmf_link_down(cfg_priv); - - /* - * Make sure WPA_Supplicant receives all the event - * generated due to DISASSOC call to the fw to keep - * the state fw and WPA_Supplicant state consistent - */ - brcmf_delay(500); - } - - set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) - brcmf_term_iscan(cfg_priv); - - if (cfg_priv->scan_request) { - /* Indidate scan abort to cfg80211 layer */ - WL_INFO("Terminating scan in progress\n"); - cfg80211_scan_done(cfg_priv->scan_request, true); - cfg_priv->scan_request = NULL; - } - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); - - /* Turn off watchdog timer */ - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { - WL_INFO("Enable MPC\n"); - brcmf_set_mpc(ndev, 1); - } - - WL_TRACE("Exit\n"); - - return 0; -} - -static __used s32 -brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - u32 buflen; - - buflen = brcmu_mkiovar(name, buf, len, cfg_priv->dcmd_buf, - WL_DCMD_LEN_MAX); - BUG_ON(!buflen); - - return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf, - buflen); -} - -static s32 -brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf, - s32 buf_len) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - u32 len; - s32 err = 0; - - len = brcmu_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf, - WL_DCMD_LEN_MAX); - BUG_ON(!len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf, - WL_DCMD_LEN_MAX); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - memcpy(buf, cfg_priv->dcmd_buf, buf_len); - - return err; -} - -static __used s32 -brcmf_update_pmklist(struct net_device *ndev, - struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) -{ - int i, j; - - WL_CONN("No of elements %d\n", pmk_list->pmkids.npmkid); - for (i = 0; i < pmk_list->pmkids.npmkid; i++) { - WL_CONN("PMKID[%d]: %pM =\n", i, - &pmk_list->pmkids.pmkid[i].BSSID); - for (j = 0; j < WLAN_PMKID_LEN; j++) - WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); - } - - if (!err) - brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list, - sizeof(*pmk_list)); - - return err; -} - -static s32 -brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_pmksa *pmksa) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids; - s32 err = 0; - int i; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - for (i = 0; i < pmkids->npmkid; i++) - if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN)) - break; - if (i < WL_NUM_PMKIDS_MAX) { - memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN); - memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); - if (i == pmkids->npmkid) - pmkids->npmkid++; - } else - err = -EINVAL; - - WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - pmkids->pmkid[pmkids->npmkid].BSSID); - for (i = 0; i < WLAN_PMKID_LEN; i++) - WL_CONN("%02x\n", pmkids->pmkid[pmkids->npmkid].PMKID[i]); - - err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); - - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_pmksa *pmksa) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - struct pmkid_list pmkid; - s32 err = 0; - int i; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); - memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); - - WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", - &pmkid.pmkid[0].BSSID); - for (i = 0; i < WLAN_PMKID_LEN; i++) - WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]); - - for (i = 0; i < cfg_priv->pmk_list->pmkids.npmkid; i++) - if (!memcmp - (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, - ETH_ALEN)) - break; - - if ((cfg_priv->pmk_list->pmkids.npmkid > 0) - && (i < cfg_priv->pmk_list->pmkids.npmkid)) { - memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0, - sizeof(struct pmkid)); - for (; i < (cfg_priv->pmk_list->pmkids.npmkid - 1); i++) { - memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, - &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID, - ETH_ALEN); - memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID, - &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID, - WLAN_PMKID_LEN); - } - cfg_priv->pmk_list->pmkids.npmkid--; - } else - err = -EINVAL; - - err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); - - WL_TRACE("Exit\n"); - return err; - -} - -static s32 -brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) -{ - struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); - s32 err = 0; - - WL_TRACE("Enter\n"); - if (!check_sys_up(wiphy)) - return -EIO; - - memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list)); - err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); - - WL_TRACE("Exit\n"); - return err; - -} - -static struct cfg80211_ops wl_cfg80211_ops = { - .change_virtual_intf = brcmf_cfg80211_change_iface, - .scan = brcmf_cfg80211_scan, - .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, - .join_ibss = brcmf_cfg80211_join_ibss, - .leave_ibss = brcmf_cfg80211_leave_ibss, - .get_station = brcmf_cfg80211_get_station, - .set_tx_power = brcmf_cfg80211_set_tx_power, - .get_tx_power = brcmf_cfg80211_get_tx_power, - .add_key = brcmf_cfg80211_add_key, - .del_key = brcmf_cfg80211_del_key, - .get_key = brcmf_cfg80211_get_key, - .set_default_key = brcmf_cfg80211_config_default_key, - .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, - .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, - .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, - .connect = brcmf_cfg80211_connect, - .disconnect = brcmf_cfg80211_disconnect, - .suspend = brcmf_cfg80211_suspend, - .resume = brcmf_cfg80211_resume, - .set_pmksa = brcmf_cfg80211_set_pmksa, - .del_pmksa = brcmf_cfg80211_del_pmksa, - .flush_pmksa = brcmf_cfg80211_flush_pmksa -}; - -static s32 brcmf_mode_to_nl80211_iftype(s32 mode) -{ - s32 err = 0; - - switch (mode) { - case WL_MODE_BSS: - return NL80211_IFTYPE_STATION; - case WL_MODE_IBSS: - return NL80211_IFTYPE_ADHOC; - default: - return NL80211_IFTYPE_UNSPECIFIED; - } - - return err; -} - -static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, - struct device *ndev) -{ - struct wireless_dev *wdev; - s32 err = 0; - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); - - wdev->wiphy = - wiphy_new(&wl_cfg80211_ops, - sizeof(struct brcmf_cfg80211_priv) + sizeof_iface); - if (!wdev->wiphy) { - WL_ERR("Couldn not allocate wiphy device\n"); - err = -ENOMEM; - goto wiphy_new_out; - } - set_wiphy_dev(wdev->wiphy, ndev); - wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; - wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; - wdev->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set - * it as 11a by default. - * This will be updated with - * 11n phy tables in - * "ifconfig up" - * if phy has 11n capability - */ - wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wdev->wiphy->cipher_suites = __wl_cipher_suites; - wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); - wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power - * save mode - * by default - */ - err = wiphy_register(wdev->wiphy); - if (err < 0) { - WL_ERR("Couldn not register wiphy device (%d)\n", err); - goto wiphy_register_out; - } - return wdev; - -wiphy_register_out: - wiphy_free(wdev->wiphy); - -wiphy_new_out: - kfree(wdev); - - return ERR_PTR(err); -} - -static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct wireless_dev *wdev = cfg_priv->wdev; - - if (!wdev) { - WL_ERR("wdev is invalid\n"); - return; - } - wiphy_unregister(wdev->wiphy); - wiphy_free(wdev->wiphy); - kfree(wdev); - cfg_priv->wdev = NULL; -} - -static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e) -{ - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); - - if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { - WL_CONN("Processing set ssid\n"); - cfg_priv->link_up = true; - return true; - } - - return false; -} - -static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e) -{ - u32 event = be32_to_cpu(e->event_type); - u16 flags = be16_to_cpu(e->flags); - - if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { - WL_CONN("Processing link down\n"); - return true; - } - return false; -} - -static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e) -{ - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); - - if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { - WL_CONN("Processing Link %s & no network found\n", - be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? - "up" : "down"); - return true; - } - - if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) { - WL_CONN("Processing connecting & no network found\n"); - return true; - } - - return false; -} - -static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - - kfree(conn_info->req_ie); - conn_info->req_ie = NULL; - conn_info->req_ie_len = 0; - kfree(conn_info->resp_ie); - conn_info->resp_ie = NULL; - conn_info->resp_ie_len = 0; -} - -static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct net_device *ndev = cfg_to_ndev(cfg_priv); - struct brcmf_cfg80211_assoc_ielen *assoc_info; - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - u32 req_len; - u32 resp_len; - s32 err = 0; - - brcmf_clear_assoc_ies(cfg_priv); - - err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf, - WL_ASSOC_INFO_MAX); - if (err) { - WL_ERR("could not get assoc info (%d)\n", err); - return err; - } - assoc_info = (struct brcmf_cfg80211_assoc_ielen *)cfg_priv->extra_buf; - req_len = assoc_info->req_len; - resp_len = assoc_info->resp_len; - if (req_len) { - err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", - cfg_priv->extra_buf, - WL_ASSOC_INFO_MAX); - if (err) { - WL_ERR("could not get assoc req (%d)\n", err); - return err; - } - conn_info->req_ie_len = req_len; - conn_info->req_ie = - kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len, - GFP_KERNEL); - } else { - conn_info->req_ie_len = 0; - conn_info->req_ie = NULL; - } - if (resp_len) { - err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", - cfg_priv->extra_buf, - WL_ASSOC_INFO_MAX); - if (err) { - WL_ERR("could not get assoc resp (%d)\n", err); - return err; - } - conn_info->resp_ie_len = resp_len; - conn_info->resp_ie = - kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len, - GFP_KERNEL); - } else { - conn_info->resp_ie_len = 0; - conn_info->resp_ie = NULL; - } - WL_CONN("req len (%d) resp len (%d)\n", - conn_info->req_ie_len, conn_info->resp_ie_len); - - return err; -} - -static s32 -brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e) -{ - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); - struct brcmf_channel_info_le channel_le; - struct ieee80211_channel *notify_channel; - struct ieee80211_supported_band *band; - u32 freq; - s32 err = 0; - u32 target_channel; - - WL_TRACE("Enter\n"); - - brcmf_get_assoc_ies(cfg_priv); - brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID); - brcmf_update_bss_info(cfg_priv); - - brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, - sizeof(channel_le)); - - target_channel = le32_to_cpu(channel_le.target_channel); - WL_CONN("Roamed to channel %d\n", target_channel); - - if (target_channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - - freq = ieee80211_channel_to_frequency(target_channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); - - cfg80211_roamed(ndev, notify_channel, - (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID), - conn_info->req_ie, conn_info->req_ie_len, - conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); - WL_CONN("Report roaming result\n"); - - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, const struct brcmf_event_msg *e, - bool completed) -{ - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - s32 err = 0; - - WL_TRACE("Enter\n"); - - if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { - if (completed) { - brcmf_get_assoc_ies(cfg_priv); - brcmf_update_prof(cfg_priv, NULL, &e->addr, - WL_PROF_BSSID); - brcmf_update_bss_info(cfg_priv); - } - cfg80211_connect_result(ndev, - (u8 *)brcmf_read_prof(cfg_priv, - WL_PROF_BSSID), - conn_info->req_ie, - conn_info->req_ie_len, - conn_info->resp_ie, - conn_info->resp_ie_len, - completed ? WLAN_STATUS_SUCCESS : - WLAN_STATUS_AUTH_TIMEOUT, - GFP_KERNEL); - if (completed) - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); - WL_CONN("Report connect result - connection %s\n", - completed ? "succeeded" : "failed"); - } - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - s32 err = 0; - - if (brcmf_is_linkup(cfg_priv, e)) { - WL_CONN("Linkup\n"); - if (brcmf_is_ibssmode(cfg_priv)) { - brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, - WL_PROF_BSSID); - wl_inform_ibss(cfg_priv, ndev, e->addr); - cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); - } else - brcmf_bss_connect_done(cfg_priv, ndev, e, true); - } else if (brcmf_is_linkdown(cfg_priv, e)) { - WL_CONN("Linkdown\n"); - if (brcmf_is_ibssmode(cfg_priv)) { - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg_priv->status)) - brcmf_link_down(cfg_priv); - } else { - brcmf_bss_connect_done(cfg_priv, ndev, e, false); - if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg_priv->status)) { - cfg80211_disconnected(ndev, 0, NULL, 0, - GFP_KERNEL); - brcmf_link_down(cfg_priv); - } - } - brcmf_init_prof(cfg_priv->profile); - } else if (brcmf_is_nonetwork(cfg_priv, e)) { - if (brcmf_is_ibssmode(cfg_priv)) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - else - brcmf_bss_connect_done(cfg_priv, ndev, e, false); - } - - return err; -} - -static s32 -brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); - - if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { - if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) - brcmf_bss_roaming_done(cfg_priv, ndev, e); - else - brcmf_bss_connect_done(cfg_priv, ndev, e, true); - } - - return err; -} - -static s32 -brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - u16 flags = be16_to_cpu(e->flags); - enum nl80211_key_type key_type; - - if (flags & BRCMF_EVENT_MSG_GROUP) - key_type = NL80211_KEYTYPE_GROUP; - else - key_type = NL80211_KEYTYPE_PAIRWISE; - - cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, - NULL, GFP_KERNEL); - - return 0; -} - -static s32 -brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - struct brcmf_channel_info_le channel_inform_le; - struct brcmf_scan_results_le *bss_list_le; - u32 len = WL_SCAN_BUF_MAX; - s32 err = 0; - bool scan_abort = false; - u32 scan_channel; - - WL_TRACE("Enter\n"); - - if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) { - WL_TRACE("Exit\n"); - return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv)); - } - - if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { - WL_ERR("Scan complete while device not scanning\n"); - scan_abort = true; - err = -EINVAL; - goto scan_done_out; - } - - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le, - sizeof(channel_inform_le)); - if (err) { - WL_ERR("scan busy (%d)\n", err); - scan_abort = true; - goto scan_done_out; - } - scan_channel = le32_to_cpu(channel_inform_le.scan_channel); - if (scan_channel) - WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel); - cfg_priv->bss_list = cfg_priv->scan_results; - bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list; - - memset(cfg_priv->scan_results, 0, len); - bss_list_le->buflen = cpu_to_le32(len); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS, - cfg_priv->scan_results, len); - if (err) { - WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); - err = -EINVAL; - scan_abort = true; - goto scan_done_out; - } - cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); - cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version); - cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count); - - err = brcmf_inform_bss(cfg_priv); - if (err) { - scan_abort = true; - goto scan_done_out; - } - -scan_done_out: - if (cfg_priv->scan_request) { - WL_SCAN("calling cfg80211_scan_done\n"); - cfg80211_scan_done(cfg_priv->scan_request, scan_abort); - brcmf_set_mpc(ndev, 1); - cfg_priv->scan_request = NULL; - } - - WL_TRACE("Exit\n"); - - return err; -} - -static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) -{ - conf->mode = (u32)-1; - conf->frag_threshold = (u32)-1; - conf->rts_threshold = (u32)-1; - conf->retry_short = (u32)-1; - conf->retry_long = (u32)-1; - conf->tx_power = -1; -} - -static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) -{ - memset(el, 0, sizeof(*el)); - el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status; - el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; - el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; - el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; - el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; -} - -static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) -{ - kfree(cfg_priv->scan_results); - cfg_priv->scan_results = NULL; - kfree(cfg_priv->bss_info); - cfg_priv->bss_info = NULL; - kfree(cfg_priv->conf); - cfg_priv->conf = NULL; - kfree(cfg_priv->profile); - cfg_priv->profile = NULL; - kfree(cfg_priv->scan_req_int); - cfg_priv->scan_req_int = NULL; - kfree(cfg_priv->dcmd_buf); - cfg_priv->dcmd_buf = NULL; - kfree(cfg_priv->extra_buf); - cfg_priv->extra_buf = NULL; - kfree(cfg_priv->iscan); - cfg_priv->iscan = NULL; - kfree(cfg_priv->pmk_list); - cfg_priv->pmk_list = NULL; -} - -static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) -{ - cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); - if (!cfg_priv->scan_results) - goto init_priv_mem_out; - cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL); - if (!cfg_priv->conf) - goto init_priv_mem_out; - cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL); - if (!cfg_priv->profile) - goto init_priv_mem_out; - cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (!cfg_priv->bss_info) - goto init_priv_mem_out; - cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int), - GFP_KERNEL); - if (!cfg_priv->scan_req_int) - goto init_priv_mem_out; - cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); - if (!cfg_priv->dcmd_buf) - goto init_priv_mem_out; - cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); - if (!cfg_priv->extra_buf) - goto init_priv_mem_out; - cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL); - if (!cfg_priv->iscan) - goto init_priv_mem_out; - cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL); - if (!cfg_priv->pmk_list) - goto init_priv_mem_out; - - return 0; - -init_priv_mem_out: - brcmf_deinit_priv_mem(cfg_priv); - - return -ENOMEM; -} - -/* -* retrieve first queued event from head -*/ - -static struct brcmf_cfg80211_event_q *brcmf_deq_event( - struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_event_q *e = NULL; - - spin_lock_irq(&cfg_priv->evt_q_lock); - if (!list_empty(&cfg_priv->evt_q_list)) { - e = list_first_entry(&cfg_priv->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - } - spin_unlock_irq(&cfg_priv->evt_q_lock); - - return e; -} - -/* -** push event to tail of the queue -*/ - -static s32 -brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, - const struct brcmf_event_msg *msg) -{ - struct brcmf_cfg80211_event_q *e; - s32 err = 0; - - e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); - if (!e) - return -ENOMEM; - - e->etype = event; - memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); - - spin_lock_irq(&cfg_priv->evt_q_lock); - list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list); - spin_unlock_irq(&cfg_priv->evt_q_lock); - - return err; -} - -static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) -{ - kfree(e); -} - -static void brcmf_cfg80211_event_handler(struct work_struct *work) -{ - struct brcmf_cfg80211_priv *cfg_priv = - container_of(work, struct brcmf_cfg80211_priv, - event_work); - struct brcmf_cfg80211_event_q *e; - - e = brcmf_deq_event(cfg_priv); - if (unlikely(!e)) { - WL_ERR("event queue empty...\n"); - return; - } - - do { - WL_INFO("event type (%d)\n", e->etype); - if (cfg_priv->el.handler[e->etype]) - cfg_priv->el.handler[e->etype](cfg_priv, - cfg_to_ndev(cfg_priv), - &e->emsg, e->edata); - else - WL_INFO("Unknown Event (%d): ignoring\n", e->etype); - brcmf_put_event(e); - } while ((e = brcmf_deq_event(cfg_priv))); - -} - -static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) -{ - spin_lock_init(&cfg_priv->evt_q_lock); - INIT_LIST_HEAD(&cfg_priv->evt_q_list); -} - -static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_event_q *e; - - spin_lock_irq(&cfg_priv->evt_q_lock); - while (!list_empty(&cfg_priv->evt_q_list)) { - e = list_first_entry(&cfg_priv->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - kfree(e); - } - spin_unlock_irq(&cfg_priv->evt_q_lock); -} - -static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) -{ - s32 err = 0; - - cfg_priv->scan_request = NULL; - cfg_priv->pwr_save = true; - cfg_priv->iscan_on = true; /* iscan on & off switch. - we enable iscan per default */ - cfg_priv->roam_on = true; /* roam on & off switch. - we enable roam per default */ - - cfg_priv->iscan_kickstart = false; - cfg_priv->active_scan = true; /* we do active scan for - specific scan per default */ - cfg_priv->dongle_up = false; /* dongle is not up yet */ - brcmf_init_eq(cfg_priv); - err = brcmf_init_priv_mem(cfg_priv); - if (err) - return err; - INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler); - brcmf_init_eloop_handler(&cfg_priv->el); - mutex_init(&cfg_priv->usr_sync); - err = brcmf_init_iscan(cfg_priv); - if (err) - return err; - brcmf_init_conf(cfg_priv->conf); - brcmf_init_prof(cfg_priv->profile); - brcmf_link_down(cfg_priv); - - return err; -} - -static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) -{ - cancel_work_sync(&cfg_priv->event_work); - cfg_priv->dongle_up = false; /* dongle down */ - brcmf_flush_eq(cfg_priv); - brcmf_link_down(cfg_priv); - brcmf_term_iscan(cfg_priv); - brcmf_deinit_priv_mem(cfg_priv); -} - -struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, - struct device *busdev, - void *data) -{ - struct wireless_dev *wdev; - struct brcmf_cfg80211_priv *cfg_priv; - struct brcmf_cfg80211_iface *ci; - struct brcmf_cfg80211_dev *cfg_dev; - s32 err = 0; - - if (!ndev) { - WL_ERR("ndev is invalid\n"); - return NULL; - } - cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL); - if (!cfg_dev) - return NULL; - - wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev); - if (IS_ERR(wdev)) { - kfree(cfg_dev); - return NULL; - } - - wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); - cfg_priv = wdev_to_cfg(wdev); - cfg_priv->wdev = wdev; - cfg_priv->pub = data; - ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; - ci->cfg_priv = cfg_priv; - ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - wdev->netdev = ndev; - err = wl_init_priv(cfg_priv); - if (err) { - WL_ERR("Failed to init iwm_priv (%d)\n", err); - goto cfg80211_attach_out; - } - brcmf_set_drvdata(cfg_dev, ci); - - return cfg_dev; - -cfg80211_attach_out: - brcmf_free_wdev(cfg_priv); - kfree(cfg_dev); - return NULL; -} - -void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev) -{ - struct brcmf_cfg80211_priv *cfg_priv; - - cfg_priv = brcmf_priv_get(cfg_dev); - - wl_deinit_priv(cfg_priv); - brcmf_free_wdev(cfg_priv); - brcmf_set_drvdata(cfg_dev, NULL); - kfree(cfg_dev); -} - -void -brcmf_cfg80211_event(struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - u32 event_type = be32_to_cpu(e->event_type); - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - - if (!brcmf_enq_event(cfg_priv, event_type, e)) - schedule_work(&cfg_priv->event_work); -} - -static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) -{ - s32 infra = 0; - s32 err = 0; - - switch (iftype) { - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_WDS: - WL_ERR("type (%d) : currently we do not support this mode\n", - iftype); - err = -EINVAL; - return err; - case NL80211_IFTYPE_ADHOC: - infra = 0; - break; - case NL80211_IFTYPE_STATION: - infra = 1; - break; - default: - err = -EINVAL; - WL_ERR("invalid type (%d)\n", iftype); - return err; - } - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); - if (err) { - WL_ERR("WLC_SET_INFRA error (%d)\n", err); - return err; - } - - return 0; -} - -static s32 brcmf_dongle_eventmsg(struct net_device *ndev) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - s32 err = 0; - - WL_TRACE("Enter\n"); - - /* Setup event_msgs */ - brcmu_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf)); - if (err) { - WL_ERR("Get event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } - memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); - - setbit(eventmask, BRCMF_E_SET_SSID); - setbit(eventmask, BRCMF_E_ROAM); - setbit(eventmask, BRCMF_E_PRUNE); - setbit(eventmask, BRCMF_E_AUTH); - setbit(eventmask, BRCMF_E_REASSOC); - setbit(eventmask, BRCMF_E_REASSOC_IND); - setbit(eventmask, BRCMF_E_DEAUTH_IND); - setbit(eventmask, BRCMF_E_DISASSOC_IND); - setbit(eventmask, BRCMF_E_DISASSOC); - setbit(eventmask, BRCMF_E_JOIN); - setbit(eventmask, BRCMF_E_ASSOC_IND); - setbit(eventmask, BRCMF_E_PSK_SUP); - setbit(eventmask, BRCMF_E_LINK); - setbit(eventmask, BRCMF_E_NDIS_LINK); - setbit(eventmask, BRCMF_E_MIC_ERROR); - setbit(eventmask, BRCMF_E_PMKID_CACHE); - setbit(eventmask, BRCMF_E_TXFAIL); - setbit(eventmask, BRCMF_E_JOIN_START); - setbit(eventmask, BRCMF_E_SCAN_COMPLETE); - - brcmu_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); - if (err) { - WL_ERR("Set event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } - -dongle_eventmsg_out: - WL_TRACE("Exit\n"); - return err; -} - -static s32 -brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) -{ - s8 iovbuf[32]; - s32 roamtrigger[2]; - s32 roam_delta[2]; - s32 err = 0; - - /* - * Setup timeout if Beacons are lost and roam is - * off to report link down - */ - if (roamvar) { - brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), iovbuf, sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, - iovbuf, sizeof(iovbuf)); - if (err) { - WL_ERR("bcn_timeout error (%d)\n", err); - goto dongle_rom_out; - } - } - - /* - * Enable/Disable built-in roaming to allow supplicant - * to take care of roaming - */ - WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On"); - brcmu_mkiovar("roam_off", (char *)&roamvar, - sizeof(roamvar), iovbuf, sizeof(iovbuf)); - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); - if (err) { - WL_ERR("roam_off error (%d)\n", err); - goto dongle_rom_out; - } - - roamtrigger[0] = WL_ROAM_TRIGGER_LEVEL; - roamtrigger[1] = BRCM_BAND_ALL; - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER, - (void *)roamtrigger, sizeof(roamtrigger)); - if (err) { - WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err); - goto dongle_rom_out; - } - - roam_delta[0] = WL_ROAM_DELTA; - roam_delta[1] = BRCM_BAND_ALL; - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA, - (void *)roam_delta, sizeof(roam_delta)); - if (err) { - WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err); - goto dongle_rom_out; - } - -dongle_rom_out: - return err; -} - -static s32 -brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, - s32 scan_unassoc_time, s32 scan_passive_time) -{ - s32 err = 0; - - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME, - &scan_assoc_time, sizeof(scan_assoc_time)); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO("Scan assoc time is not supported\n"); - else - WL_ERR("Scan assoc time error (%d)\n", err); - goto dongle_scantime_out; - } - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME, - &scan_unassoc_time, sizeof(scan_unassoc_time)); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO("Scan unassoc time is not supported\n"); - else - WL_ERR("Scan unassoc time error (%d)\n", err); - goto dongle_scantime_out; - } - - err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME, - &scan_passive_time, sizeof(scan_passive_time)); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO("Scan passive time is not supported\n"); - else - WL_ERR("Scan passive time error (%d)\n", err); - goto dongle_scantime_out; - } - -dongle_scantime_out: - return err; -} - -static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct wiphy *wiphy; - s32 phy_list; - s8 phy; - s32 err = 0; - - err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, - &phy_list, sizeof(phy_list)); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - - phy = ((char *)&phy_list)[1]; - WL_INFO("%c phy\n", phy); - if (phy == 'n' || phy == 'a') { - wiphy = cfg_to_wiphy(cfg_priv); - wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; - } - - return err; -} - -static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) -{ - return wl_update_wiphybands(cfg_priv); -} - -static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct net_device *ndev; - struct wireless_dev *wdev; - s32 power_mode; - s32 err = 0; - - if (cfg_priv->dongle_up) - return err; - - ndev = cfg_to_ndev(cfg_priv); - wdev = ndev->ieee80211_ptr; - - brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, - WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); - - err = brcmf_dongle_eventmsg(ndev); - if (err) - goto default_conf_out; - - power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF; - err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode); - if (err) - goto default_conf_out; - WL_INFO("power save set to %s\n", - (power_mode ? "enabled" : "disabled")); - - err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1), - WL_BEACON_TIMEOUT); - if (err) - goto default_conf_out; - err = brcmf_dongle_mode(ndev, wdev->iftype); - if (err && err != -EINPROGRESS) - goto default_conf_out; - err = brcmf_dongle_probecap(cfg_priv); - if (err) - goto default_conf_out; - - /* -EINPROGRESS: Call commit handler */ - -default_conf_out: - - cfg_priv->dongle_up = true; - - return err; - -} - -static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) -{ - char buf[10+IFNAMSIZ]; - struct dentry *fd; - s32 err = 0; - - sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); - cfg_priv->debugfsdir = debugfs_create_dir(buf, - cfg_to_wiphy(cfg_priv)->debugfsdir); - - fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, - (u16 *)&cfg_priv->profile->beacon_interval); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - - fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, - (u8 *)&cfg_priv->profile->dtim_period); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - -err_out: - return err; -} - -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) -{ - debugfs_remove_recursive(cfg_priv->debugfsdir); - cfg_priv->debugfsdir = NULL; -} - -static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv) -{ - s32 err = 0; - - set_bit(WL_STATUS_READY, &cfg_priv->status); - - brcmf_debugfs_add_netdev_params(cfg_priv); - - err = brcmf_config_dongle(cfg_priv); - if (err) - return err; - - brcmf_invoke_iscan(cfg_priv); - - return err; -} - -static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) -{ - /* - * While going down, if associated with AP disassociate - * from AP to save power - */ - if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || - test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && - test_bit(WL_STATUS_READY, &cfg_priv->status)) { - WL_INFO("Disassociating from AP"); - brcmf_link_down(cfg_priv); - - /* Make sure WPA_Supplicant receives all the event - generated due to DISASSOC call to the fw to keep - the state fw and WPA_Supplicant state consistent - */ - brcmf_delay(500); - } - - set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); - brcmf_term_iscan(cfg_priv); - if (cfg_priv->scan_request) { - cfg80211_scan_done(cfg_priv->scan_request, true); - /* May need to perform this to cover rmmod */ - /* wl_set_mpc(cfg_to_ndev(wl), 1); */ - cfg_priv->scan_request = NULL; - } - clear_bit(WL_STATUS_READY, &cfg_priv->status); - clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); - - brcmf_debugfs_remove_netdev(cfg_priv); - - return 0; -} - -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev) -{ - struct brcmf_cfg80211_priv *cfg_priv; - s32 err = 0; - - cfg_priv = brcmf_priv_get(cfg_dev); - mutex_lock(&cfg_priv->usr_sync); - err = __brcmf_cfg80211_up(cfg_priv); - mutex_unlock(&cfg_priv->usr_sync); - - return err; -} - -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) -{ - struct brcmf_cfg80211_priv *cfg_priv; - s32 err = 0; - - cfg_priv = brcmf_priv_get(cfg_dev); - mutex_lock(&cfg_priv->usr_sync); - err = __brcmf_cfg80211_down(cfg_priv); - mutex_unlock(&cfg_priv->usr_sync); - - return err; -} - -static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, - u8 t, u8 l, u8 *v) -{ - struct brcmf_cfg80211_ie *ie = &cfg_priv->ie; - s32 err = 0; - - if (ie->offset + l + 2 > WL_TLV_INFO_MAX) { - WL_ERR("ei crosses buffer boundary\n"); - return -ENOSPC; - } - ie->buf[ie->offset] = t; - ie->buf[ie->offset + 1] = l; - memcpy(&ie->buf[ie->offset + 2], v, l); - ie->offset += l + 2; - - return err; -} diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h deleted file mode 100644 index e69f4f6bf946..000000000000 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _wl_cfg80211_h_ -#define _wl_cfg80211_h_ - -struct brcmf_cfg80211_conf; -struct brcmf_cfg80211_iface; -struct brcmf_cfg80211_priv; -struct brcmf_cfg80211_security; -struct brcmf_cfg80211_ibss; - -#define WL_DBG_NONE 0 -#define WL_DBG_CONN (1 << 5) -#define WL_DBG_SCAN (1 << 4) -#define WL_DBG_TRACE (1 << 3) -#define WL_DBG_INFO (1 << 1) -#define WL_DBG_ERR (1 << 0) -#define WL_DBG_MASK ((WL_DBG_INFO | WL_DBG_ERR | WL_DBG_TRACE) | \ - (WL_DBG_SCAN) | (WL_DBG_CONN)) - -#define WL_ERR(fmt, args...) \ -do { \ - if (brcmf_dbg_level & WL_DBG_ERR) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "ERROR @%s : " fmt, \ - __func__, ##args); \ - } \ - } \ -} while (0) - -#if (defined BCMDBG) -#define WL_INFO(fmt, args...) \ -do { \ - if (brcmf_dbg_level & WL_DBG_INFO) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "INFO @%s : " fmt, \ - __func__, ##args); \ - } \ - } \ -} while (0) - -#define WL_TRACE(fmt, args...) \ -do { \ - if (brcmf_dbg_level & WL_DBG_TRACE) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "TRACE @%s : " fmt, \ - __func__, ##args); \ - } \ - } \ -} while (0) - -#define WL_SCAN(fmt, args...) \ -do { \ - if (brcmf_dbg_level & WL_DBG_SCAN) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "SCAN @%s : " fmt, \ - __func__, ##args); \ - } \ - } \ -} while (0) - -#define WL_CONN(fmt, args...) \ -do { \ - if (brcmf_dbg_level & WL_DBG_CONN) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "CONN @%s : " fmt, \ - __func__, ##args); \ - } \ - } \ -} while (0) - -#else /* (defined BCMDBG) */ -#define WL_INFO(fmt, args...) -#define WL_TRACE(fmt, args...) -#define WL_SCAN(fmt, args...) -#define WL_CONN(fmt, args...) -#endif /* (defined BCMDBG) */ - -#define WL_NUM_SCAN_MAX 1 -#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used - * for 2.6.33 kernel - * or later - */ -#define WL_SCAN_BUF_MAX (1024 * 8) -#define WL_TLV_INFO_MAX 1024 -#define WL_BSS_INFO_MAX 2048 -#define WL_ASSOC_INFO_MAX 512 /* - * needs to grab assoc info from dongle to - * report it to cfg80211 through "connect" - * event - */ -#define WL_DCMD_LEN_MAX 1024 -#define WL_EXTRA_BUF_MAX 2048 -#define WL_ISCAN_BUF_MAX 2048 /* - * the buf length can be BRCMF_DCMD_MAXLEN - * to reduce iteration - */ -#define WL_ISCAN_TIMER_INTERVAL_MS 3000 -#define WL_SCAN_ERSULTS_LAST (BRCMF_SCAN_RESULTS_NO_MEM+1) -#define WL_AP_MAX 256 /* virtually unlimitted as long - * as kernel memory allows - */ - -#define WL_ROAM_TRIGGER_LEVEL -75 -#define WL_ROAM_DELTA 20 -#define WL_BEACON_TIMEOUT 3 - -#define WL_SCAN_CHANNEL_TIME 40 -#define WL_SCAN_UNASSOC_TIME 40 -#define WL_SCAN_PASSIVE_TIME 120 - -/* dongle status */ -enum wl_status { - WL_STATUS_READY, - WL_STATUS_SCANNING, - WL_STATUS_SCAN_ABORTING, - WL_STATUS_CONNECTING, - WL_STATUS_CONNECTED -}; - -/* wi-fi mode */ -enum wl_mode { - WL_MODE_BSS, - WL_MODE_IBSS, - WL_MODE_AP -}; - -/* dongle profile list */ -enum wl_prof_list { - WL_PROF_MODE, - WL_PROF_SSID, - WL_PROF_SEC, - WL_PROF_IBSS, - WL_PROF_BAND, - WL_PROF_BSSID, - WL_PROF_ACT, - WL_PROF_BEACONINT, - WL_PROF_DTIMPERIOD -}; - -/* dongle iscan state */ -enum wl_iscan_state { - WL_ISCAN_STATE_IDLE, - WL_ISCAN_STATE_SCANING -}; - -/* dongle configuration */ -struct brcmf_cfg80211_conf { - u32 mode; /* adhoc , infrastructure or ap */ - u32 frag_threshold; - u32 rts_threshold; - u32 retry_short; - u32 retry_long; - s32 tx_power; - struct ieee80211_channel channel; -}; - -/* cfg80211 main event loop */ -struct brcmf_cfg80211_event_loop { - s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, - void *data); -}; - -/* representing interface of cfg80211 plane */ -struct brcmf_cfg80211_iface { - struct brcmf_cfg80211_priv *cfg_priv; -}; - -struct brcmf_cfg80211_dev { - void *driver_data; /* to store cfg80211 object information */ -}; - -/* basic structure of scan request */ -struct brcmf_cfg80211_scan_req { - struct brcmf_ssid_le ssid_le; -}; - -/* basic structure of information element */ -struct brcmf_cfg80211_ie { - u16 offset; - u8 buf[WL_TLV_INFO_MAX]; -}; - -/* event queue for cfg80211 main event */ -struct brcmf_cfg80211_event_q { - struct list_head evt_q_list; - u32 etype; - struct brcmf_event_msg emsg; - s8 edata[1]; -}; - -/* security information with currently associated ap */ -struct brcmf_cfg80211_security { - u32 wpa_versions; - u32 auth_type; - u32 cipher_pairwise; - u32 cipher_group; - u32 wpa_auth; -}; - -/* ibss information for currently joined ibss network */ -struct brcmf_cfg80211_ibss { - u8 beacon_interval; /* in millisecond */ - u8 atim; /* in millisecond */ - s8 join_only; - u8 band; - u8 channel; -}; - -/* dongle profile */ -struct brcmf_cfg80211_profile { - u32 mode; - struct brcmf_ssid ssid; - u8 bssid[ETH_ALEN]; - u16 beacon_interval; - u8 dtim_period; - struct brcmf_cfg80211_security sec; - struct brcmf_cfg80211_ibss ibss; - s32 band; -}; - -/* dongle iscan event loop */ -struct brcmf_cfg80211_iscan_eloop { - s32 (*handler[WL_SCAN_ERSULTS_LAST]) - (struct brcmf_cfg80211_priv *cfg_priv); -}; - -/* dongle iscan controller */ -struct brcmf_cfg80211_iscan_ctrl { - struct net_device *ndev; - struct timer_list timer; - u32 timer_ms; - u32 timer_on; - s32 state; - struct work_struct work; - struct brcmf_cfg80211_iscan_eloop el; - void *data; - s8 dcmd_buf[BRCMF_DCMD_SMLEN]; - s8 scan_buf[WL_ISCAN_BUF_MAX]; -}; - -/* association inform */ -struct brcmf_cfg80211_connect_info { - u8 *req_ie; - s32 req_ie_len; - u8 *resp_ie; - s32 resp_ie_len; -}; - -/* assoc ie length */ -struct brcmf_cfg80211_assoc_ielen { - u32 req_len; - u32 resp_len; -}; - -/* wpa2 pmk list */ -struct brcmf_cfg80211_pmk_list { - struct pmkid_list pmkids; - struct pmkid foo[MAXPMKID - 1]; -}; - -/* dongle private data of cfg80211 interface */ -struct brcmf_cfg80211_priv { - struct wireless_dev *wdev; /* representing wl cfg80211 device */ - struct brcmf_cfg80211_conf *conf; /* dongle configuration */ - struct cfg80211_scan_request *scan_request; /* scan request - object */ - struct brcmf_cfg80211_event_loop el; /* main event loop */ - struct list_head evt_q_list; /* used for event queue */ - spinlock_t evt_q_lock; /* for event queue synchronization */ - struct mutex usr_sync; /* maily for dongle up/down synchronization */ - struct brcmf_scan_results *bss_list; /* bss_list holding scanned - ap information */ - struct brcmf_scan_results *scan_results; - struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object - for internal purpose */ - struct wl_cfg80211_bss_info *bss_info; /* bss information for - cfg80211 layer */ - struct brcmf_cfg80211_ie ie; /* information element object for - internal purpose */ - struct brcmf_cfg80211_profile *profile; /* holding dongle profile */ - struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */ - struct brcmf_cfg80211_connect_info conn_info; /* association info */ - struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */ - struct work_struct event_work; /* event handler work struct */ - unsigned long status; /* current dongle status */ - void *pub; - u32 channel; /* current channel */ - bool iscan_on; /* iscan on/off switch */ - bool iscan_kickstart; /* indicate iscan already started */ - bool active_scan; /* current scan mode */ - bool ibss_starter; /* indicates this sta is ibss starter */ - bool link_up; /* link/connection up flag */ - bool pwr_save; /* indicate whether dongle to support - power save mode */ - bool dongle_up; /* indicate whether dongle up or not */ - bool roam_on; /* on/off switch for dongle self-roaming */ - bool scan_tried; /* indicates if first scan attempted */ - u8 *dcmd_buf; /* dcmd buffer */ - u8 *extra_buf; /* maily to grab assoc information */ - struct dentry *debugfsdir; - u8 ci[0] __aligned(NETDEV_ALIGN); -}; - -static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w) -{ - return w->wdev->wiphy; -} - -static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w) -{ - return (struct brcmf_cfg80211_priv *)(wiphy_priv(w)); -} - -static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd) -{ - return (struct brcmf_cfg80211_priv *)(wdev_priv(wd)); -} - -static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg) -{ - return cfg->wdev->netdev; -} - -static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev) -{ - return wdev_to_cfg(ndev->ieee80211_ptr); -} - -#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data)) -#define cfg_to_iscan(w) (w->iscan) - -static inline struct -brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg) -{ - return &cfg->conn_info; -} - -static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list, - struct brcmf_bss_info *bss) -{ - return bss = bss ? - (struct brcmf_bss_info *)((unsigned long)bss + - le32_to_cpu(bss->length)) : - list->bss_info; -} - -extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, - struct device *busdev, - void *data); -extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); - -/* event handler from dongle */ -extern void brcmf_cfg80211_event(struct net_device *ndev, - const struct brcmf_event_msg *e, void *data); -extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev); -extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev); - -#endif /* _wl_cfg80211_h_ */ |