diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-11-28 10:56:03 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-11-28 10:56:03 -0500 |
commit | 79d38f7d6cf545ff838dd5227869f3916d1d100d (patch) | |
tree | 859c8071aab68fd32f36ffb9ebc04cf12db6e5e0 /drivers/net/wireless/brcm80211/brcmfmac | |
parent | 03f52a0a554210d5049eeed9f1bb29047dc807cb (diff) | |
parent | 0751f8654602e4255f0b9c17784d8100d5896010 (diff) | |
download | op-kernel-dev-79d38f7d6cf545ff838dd5227869f3916d1d100d.zip op-kernel-dev-79d38f7d6cf545ff838dd5227869f3916d1d100d.tar.gz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/iwlwifi/pcie/tx.c
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac')
19 files changed, 1442 insertions, 2407 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index fe80b63..1a6661a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_BRCMFMAC) += brcmfmac.o brcmfmac-objs += \ wl_cfg80211.o \ fwil.o \ + fweh.o \ dhd_cdc.o \ dhd_common.o \ dhd_linux.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 3b2c4c2..334ddab 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -42,7 +42,8 @@ #ifdef CONFIG_BRCMFMAC_SDIO_OOB static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id) { - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id); + struct brcmf_bus *bus_if = dev_get_drvdata(dev_id); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(INTR, "oob intr triggered\n"); @@ -71,7 +72,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq); ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler, sdiodev->irq_flags, "brcmf_oob_intr", - &sdiodev->func[1]->card->dev); + &sdiodev->func[1]->dev); if (ret != 0) return ret; spin_lock_init(&sdiodev->irq_en_lock); @@ -84,6 +85,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) return ret; sdiodev->irq_wake = true; + sdio_claim_host(sdiodev->func[1]); + /* must configure SDIO_CCCR_IENx to enable irq */ data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret); data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; @@ -95,6 +98,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) data |= SDIO_SEPINT_ACT_HI; brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); + sdio_release_host(sdiodev->func[1]); + return 0; } @@ -102,14 +107,16 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) { brcmf_dbg(TRACE, "Entering\n"); + sdio_claim_host(sdiodev->func[1]); brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); + sdio_release_host(sdiodev->func[1]); if (sdiodev->irq_wake) { disable_irq_wake(sdiodev->irq); sdiodev->irq_wake = false; } - free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev); + free_irq(sdiodev->irq, &sdiodev->func[1]->dev); sdiodev->irq_en = false; return 0; @@ -117,7 +124,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) #else /* CONFIG_BRCMFMAC_SDIO_OOB */ static void brcmf_sdio_irqhandler(struct sdio_func *func) { - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(INTR, "ib intr triggered\n"); @@ -249,9 +257,7 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) int retval; brcmf_dbg(INFO, "addr:0x%08x\n", addr); - sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); - sdio_release_host(sdiodev->func[1]); brcmf_dbg(INFO, "data:0x%02x\n", data); if (ret) @@ -266,9 +272,7 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) int retval; brcmf_dbg(INFO, "addr:0x%08x\n", addr); - sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); - sdio_release_host(sdiodev->func[1]); brcmf_dbg(INFO, "data:0x%08x\n", data); if (ret) @@ -283,9 +287,7 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, int retval; brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data); - sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); - sdio_release_host(sdiodev->func[1]); if (ret) *ret = retval; @@ -297,9 +299,7 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, int retval; brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data); - sdio_claim_host(sdiodev->func[1]); retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); - sdio_release_host(sdiodev->func[1]); if (ret) *ret = retval; @@ -364,8 +364,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, pkt->len); - sdio_claim_host(sdiodev->func[1]); - width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); if (err) @@ -376,8 +374,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, fn, addr, pkt); done: - sdio_release_host(sdiodev->func[1]); - return err; } @@ -391,8 +387,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, pktq->qlen); - sdio_claim_host(sdiodev->func[1]); - width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); if (err) @@ -403,8 +397,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, pktq); done: - sdio_release_host(sdiodev->func[1]); - return err; } @@ -446,8 +438,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, if (flags & SDIO_REQ_ASYNC) return -ENOTSUPP; - sdio_claim_host(sdiodev->func[1]); - if (bar0 != sdiodev->sbwad) { err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); if (err) @@ -467,8 +457,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, addr, pkt); done: - sdio_release_host(sdiodev->func[1]); - return err; } @@ -510,10 +498,8 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) brcmf_dbg(TRACE, "Enter\n"); /* issue abort cmd52 command through F0 */ - sdio_claim_host(sdiodev->func[1]); brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, SDIO_CCCR_ABORT, &t_func); - sdio_release_host(sdiodev->func[1]); brcmf_dbg(TRACE, "Exit\n"); return 0; @@ -530,9 +516,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) 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(regs, sdiodev); if (!sdiodev->bus) { @@ -551,6 +534,8 @@ EXPORT_SYMBOL(brcmf_sdio_probe); int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) { + sdiodev->bus_if->state = BRCMF_BUS_DOWN; + if (sdiodev->bus) { brcmf_sdbrcm_disconnect(sdiodev->bus); sdiodev->bus = NULL; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index c3247d5..a800502 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -372,9 +372,7 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) } /* 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); @@ -393,16 +391,14 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) 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; @@ -411,6 +407,7 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) brcmf_sdioh_enablefuncs(sdiodev); out: + sdio_release_host(sdiodev->func[1]); brcmf_dbg(TRACE, "Done\n"); return err_ret; } @@ -459,95 +456,106 @@ static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev) #endif /* CONFIG_BRCMFMAC_SDIO_OOB */ static int brcmf_ops_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) + const struct sdio_device_id *id) { - int ret = 0; + int err; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; 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; - } - bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); - if (!bus_if) - return -ENOMEM; - sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); - if (!sdiodev) { - kfree(bus_if); - return -ENOMEM; - } - sdiodev->func[0] = func; - sdiodev->func[1] = func; - sdiodev->bus_if = bus_if; - bus_if->bus_priv.sdio = sdiodev; - bus_if->type = SDIO_BUS; - bus_if->align = BRCMF_SDALIGN; - 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_chain_wait); - init_waitqueue_head(&sdiodev->request_buffer_wait); + brcmf_dbg(TRACE, "Class=%x\n", func->class); + brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor); + brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device); + brcmf_dbg(TRACE, "Function#: %d\n", func->num); + + /* Consume func num 1 but dont do anything with it. */ + if (func->num == 1) + return 0; + + /* Ignore anything but func 2 */ + if (func->num != 2) + return -ENODEV; + + bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); + if (!bus_if) + return -ENOMEM; + sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); + if (!sdiodev) { + kfree(bus_if); + return -ENOMEM; } - if (func->num == 2) { - sdiodev = dev_get_drvdata(&func->card->dev); - if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) - return -ENODEV; - - ret = brcmf_sdio_getintrcfg(sdiodev); - if (ret) - return ret; - sdiodev->func[2] = func; + sdiodev->func[0] = func->card->sdio_func[0]; + sdiodev->func[1] = func->card->sdio_func[0]; + sdiodev->func[2] = func; - bus_if = sdiodev->bus_if; - sdiodev->dev = &func->dev; - dev_set_drvdata(&func->dev, bus_if); + sdiodev->bus_if = bus_if; + bus_if->bus_priv.sdio = sdiodev; + bus_if->align = BRCMF_SDALIGN; + dev_set_drvdata(&func->dev, bus_if); + dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); + sdiodev->dev = &sdiodev->func[1]->dev; - brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); - ret = brcmf_sdio_probe(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_chain_wait); + init_waitqueue_head(&sdiodev->request_buffer_wait); + err = brcmf_sdio_getintrcfg(sdiodev); + if (err) + goto fail; + + brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); + err = brcmf_sdio_probe(sdiodev); + if (err) { + brcmf_dbg(ERROR, "F2 error, probe failed %d...\n", err); + goto fail; } + brcmf_dbg(TRACE, "F2 init completed...\n"); + return 0; - return ret; +fail: + dev_set_drvdata(&func->dev, NULL); + dev_set_drvdata(&sdiodev->func[1]->dev, NULL); + kfree(sdiodev); + kfree(bus_if); + return err; } static void brcmf_ops_sdio_remove(struct sdio_func *func) { struct brcmf_bus *bus_if; 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); + brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor); + brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device); + brcmf_dbg(TRACE, "Function: %d\n", func->num); - if (func->num == 2) { - bus_if = dev_get_drvdata(&func->dev); + if (func->num != 1 && func->num != 2) + return; + + bus_if = dev_get_drvdata(&func->dev); + if (bus_if) { sdiodev = bus_if->bus_priv.sdio; - brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); brcmf_sdio_remove(sdiodev); - dev_set_drvdata(&func->card->dev, NULL); - dev_set_drvdata(&func->dev, NULL); + + dev_set_drvdata(&sdiodev->func[1]->dev, NULL); + dev_set_drvdata(&sdiodev->func[2]->dev, NULL); + kfree(bus_if); kfree(sdiodev); } + + brcmf_dbg(TRACE, "Exit\n"); } #ifdef CONFIG_PM_SLEEP static int brcmf_sdio_suspend(struct device *dev) { mmc_pm_flag_t sdio_flags; - struct sdio_func *func = dev_to_sdio_func(dev); - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; int ret = 0; brcmf_dbg(TRACE, "\n"); @@ -573,8 +581,8 @@ static int brcmf_sdio_suspend(struct device *dev) static int brcmf_sdio_resume(struct device *dev) { - struct sdio_func *func = dev_to_sdio_func(dev); - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_sdio_wdtmr_enable(sdiodev, true); atomic_set(&sdiodev->suspend, false); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 8704daa..24bc4e3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -23,6 +23,8 @@ #define BRCMF_VERSION_STR "4.218.248.5" +#include "fweh.h" + /******************************************************************************* * IO codes that are interpreted by dongle firmware ******************************************************************************/ @@ -38,8 +40,11 @@ #define BRCMF_C_GET_SSID 25 #define BRCMF_C_SET_SSID 26 #define BRCMF_C_GET_CHANNEL 29 +#define BRCMF_C_SET_CHANNEL 30 #define BRCMF_C_GET_SRL 31 +#define BRCMF_C_SET_SRL 32 #define BRCMF_C_GET_LRL 33 +#define BRCMF_C_SET_LRL 34 #define BRCMF_C_GET_RADIO 37 #define BRCMF_C_SET_RADIO 38 #define BRCMF_C_GET_PHYTYPE 39 @@ -58,6 +63,7 @@ #define BRCMF_C_SET_COUNTRY 84 #define BRCMF_C_GET_PM 85 #define BRCMF_C_SET_PM 86 +#define BRCMF_C_GET_CURR_RATESET 114 #define BRCMF_C_GET_AP 117 #define BRCMF_C_SET_AP 118 #define BRCMF_C_GET_RSSI 127 @@ -65,6 +71,7 @@ #define BRCMF_C_SET_WSEC 134 #define BRCMF_C_GET_PHY_NOISE 135 #define BRCMF_C_GET_BSS_INFO 136 +#define BRCMF_C_GET_PHYLIST 180 #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 #define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 @@ -100,29 +107,8 @@ #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 @@ -130,10 +116,6 @@ #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 - #define BRCMF_ESCAN_REQ_VERSION 1 #define WLC_BSS_RSSI_ON_CHANNEL 0x0002 @@ -141,108 +123,6 @@ #define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */ #define BRCMF_STA_ASSOC 0x10 /* Associated */ -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]; - u8 ifidx; - u8 bsscfgidx; -} __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; - -/* 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 @@ -403,7 +283,7 @@ struct brcm_rateset_le { /* # rates in this set */ __le32 count; /* rates in 500kbps units w/hi bit set if basic */ - u8 rates[WL_NUMRATES]; + u8 rates[BRCMF_MAXRATES_IN_SET]; }; struct brcmf_ssid { @@ -452,14 +332,6 @@ struct brcmf_scan_params_le { __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; @@ -467,12 +339,6 @@ struct brcmf_scan_results { struct brcmf_bss_info_le bss_info_le[]; }; -struct brcmf_scan_results_le { - __le32 buflen; - __le32 version; - __le32 count; -}; - struct brcmf_escan_params_le { __le32 version; __le16 action; @@ -508,23 +374,6 @@ struct brcmf_join_params { struct brcmf_assoc_params_le params_le; }; -/* 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 \ - (sizeof(struct brcmf_scan_results) + \ - offsetof(struct brcmf_iscan_results, results)) - struct brcmf_wsec_key { u32 index; /* key index */ u32 len; /* key length */ @@ -661,10 +510,11 @@ struct brcmf_pub { struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; - struct work_struct setmacaddr_work; - struct work_struct multicast_work; u8 macvalue[ETH_ALEN]; atomic_t pend_8021x_cnt; + wait_queue_head_t pend_8021x_wait; + + struct brcmf_fweh_info fweh; #ifdef DEBUG struct dentry *dbgfs_dir; #endif @@ -701,6 +551,8 @@ struct brcmf_if { struct brcmf_cfg80211_vif *vif; struct net_device *ndev; struct net_device_stats stats; + struct work_struct setmacaddr_work; + struct work_struct multicast_work; int idx; s32 bssidx; u8 mac_addr[ETH_ALEN]; @@ -714,9 +566,6 @@ static inline s32 brcmf_ndev_bssidx(struct net_device *ndev) extern const struct bcmevent_name bcmevent_names[]; -extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, - char *buf, uint len); - extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); /* Return pointer to interface name */ @@ -728,14 +577,9 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len); -extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name); -extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx, - void *pktdata, struct brcmf_event_msg *, - void **data_ptr); - extern int brcmf_net_attach(struct brcmf_if *ifp); -extern struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, - char *name, u8 *mac_addr); +extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, + s32 bssidx, char *name, u8 *mac_addr); extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); #endif /* _BRCMF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 265580f..b8f2487 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -45,7 +45,6 @@ struct brcmf_bus_dcmd { /* interface structure between common and bus layer */ struct brcmf_bus { - u8 type; /* bus type */ union { struct brcmf_sdio_dev *sdio; struct brcmf_usbdev *usb; @@ -85,7 +84,7 @@ extern bool brcmf_c_prec_enq(struct device *dev, 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 device *dev, int ifidx, +extern void brcmf_rx_frame(struct device *dev, u8 ifidx, struct sk_buff_head *rxlist); static inline void brcmf_rx_packet(struct device *dev, int ifidx, struct sk_buff *pkt) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index b9d8a5a..87536d3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -23,8 +23,6 @@ #include <linux/types.h> #include <linux/netdevice.h> -#include <linux/sched.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> @@ -277,76 +275,6 @@ 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->bus_if->state == BRCMF_BUS_DOWN) { - brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); - return ret; - } - mutex_lock(&drvr->proto_block); - - 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: - mutex_unlock(&drvr->proto_block); - - return ret; -} - static bool pkt_sum_needed(struct sk_buff *skb) { return skb->ip_summed == CHECKSUM_PARTIAL; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 866b669..eee7175 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -18,10 +18,7 @@ #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" @@ -30,9 +27,6 @@ #include "dhd_dbg.h" #include "fwil.h" -#define BRCM_OUI "\x00\x10\x18" -#define DOT11_OUI_LEN 3 -#define BCMILCP_BCM_SUBTYPE_EVENT 1 #define PKTFILTER_BUF_SIZE 128 #define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ #define BRCMF_DEFAULT_BCN_TIMEOUT 3 @@ -40,12 +34,6 @@ #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 #define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00" -#define MSGTRACE_VERSION 1 - -#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u) -#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \ - offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern) - #ifdef DEBUG static const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " @@ -55,43 +43,6 @@ 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; - - -uint -brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) -{ - uint len; - - len = strlen(name) + 1; - - if ((len + datalen) > buflen) - return 0; - - strncpy(buf, name, buflen); - - /* append data onto the end of the name string */ - if (data && datalen) { - memcpy(&buf[len], data, datalen); - len += datalen; - } - - return len; -} bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec) @@ -143,405 +94,6 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, return p != NULL; } -#ifdef DEBUG -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"}, { - BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"} - }; - 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_ESCAN_RESULT: - brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); - datalen = 0; - 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'; - pr_debug("%s\n", p); - p = s + 1; - } - pr_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 */ - brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data"); -} -#endif /* DEBUG */ - -int -brcmf_c_host_event(struct brcmf_pub *drvr, 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; - struct brcmf_if *ifp; - 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) { - ifp = brcmf_add_if(drvr->dev, ifevent->ifidx, - ifevent->bssidx, - event->ifname, - pvt_data->eth.h_dest); - if (IS_ERR(ifp)) - return PTR_ERR(ifp); - brcmf_net_attach(ifp); - } else { - brcmf_del_if(drvr, 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, 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, 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 DEBUG - if (BRCMF_EVENT_ON()) - brcmf_c_show_host_event(event, event_data); -#endif /* DEBUG */ - - return 0; -} - /* Convert user's input in hex pattern to byte-size mask */ static int brcmf_c_pattern_atoh(char *src, char *dst) { @@ -686,8 +238,8 @@ static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg) } pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size); - buf_len = sizeof(*pkt_filter); - buf_len -= sizeof(pkt_filter->u.pattern.mask_and_pattern); + buf_len = offsetof(struct brcmf_pkt_filter_le, + u.pattern.mask_and_pattern); buf_len += mask_size + pattern_size; err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index 862d2ac..7e58e8c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -14,18 +14,12 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/debugfs.h> -#include <linux/if_ether.h> -#include <linux/if.h> #include <linux/netdevice.h> -#include <linux/ieee80211.h> #include <linux/module.h> -#include <linux/netdevice.h> -#include <defs.h> #include <brcmu_wifi.h> #include <brcmu_utils.h> #include "dhd.h" -#include "dhd_bus.h" #include "dhd_dbg.h" static struct dentry *root_folder; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index eefa6c2..a0e18a1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -27,11 +27,11 @@ #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 -#define BRCMF_FIL_VAL 0x4000 +#define BRCMF_GLOM_VAL 0x0200 +#define BRCMF_EVENT_VAL 0x0400 +#define BRCMF_BTA_VAL 0x0800 +#define BRCMF_FIL_VAL 0x1000 +#define BRCMF_USB_VAL 0x2000 #if defined(DEBUG) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 2976523..b6c86b0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -16,27 +16,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#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 <linux/module.h> #include <net/cfg80211.h> #include <net/rtnetlink.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> @@ -45,35 +29,19 @@ #include "dhd_proto.h" #include "dhd_dbg.h" #include "wl_cfg80211.h" +#include "fwil.h" MODULE_AUTHOR("Broadcom Corporation"); -MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); -MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards"); +MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards"); MODULE_LICENSE("Dual BSD/GPL"); +#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */ /* Error bits */ int brcmf_msg_level = BRCMF_ERROR_VAL; module_param(brcmf_msg_level, int, 0); -int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name) -{ - int i = BRCMF_MAX_IFS; - struct brcmf_if *ifp; - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) { - ifp = drvr->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) { @@ -95,38 +63,33 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) static void _brcmf_set_multicast_list(struct work_struct *work) { + struct brcmf_if *ifp; struct net_device *ndev; struct netdev_hw_addr *ha; - u32 dcmd_value, cnt; + u32 cmd_value, cnt; __le32 cnt_le; - __le32 dcmd_le_value; - - struct brcmf_dcmd dcmd; char *buf, *bufp; - uint buflen; - int ret; + u32 buflen; + s32 err; - struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, - multicast_work); + brcmf_dbg(TRACE, "enter\n"); - ndev = drvr->iflist[0]->ndev; - cnt = netdev_mc_count(ndev); + ifp = container_of(work, struct brcmf_if, multicast_work); + ndev = ifp->ndev; /* Determine initial value of allmulti flag */ - dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false; + cmd_value = (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) + cnt = netdev_mc_count(ndev); + buflen = sizeof(cnt) + (cnt * ETH_ALEN); + buf = kmalloc(buflen, GFP_ATOMIC); + if (!buf) return; - - strcpy(bufp, "mcast_list"); - bufp += strlen("mcast_list") + 1; + bufp = buf; cnt_le = cpu_to_le32(cnt); - memcpy(bufp, &cnt_le, sizeof(cnt)); + memcpy(bufp, &cnt_le, sizeof(cnt_le)); bufp += sizeof(cnt_le); netdev_for_each_mc_addr(ha, ndev) { @@ -137,129 +100,66 @@ static void _brcmf_set_multicast_list(struct work_struct *work) 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, 0, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n", - brcmf_ifname(drvr, 0), cnt); - dcmd_value = cnt ? true : dcmd_value; + err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen); + if (err < 0) { + brcmf_dbg(ERROR, "Setting mcast_list failed, %d\n", err); + cmd_value = cnt ? true : cmd_value; } kfree(buf); - /* Now send the allmulti setting. This is based on the setting in the + /* + * 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(dcmd_value); - buf = kmalloc(buflen, GFP_ATOMIC); - if (!buf) - return; - - dcmd_le_value = cpu_to_le32(dcmd_value); - - if (!brcmf_c_mkiovar - ("allmulti", (void *)&dcmd_le_value, - sizeof(dcmd_le_value), buf, buflen)) { - brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n", - brcmf_ifname(drvr, 0), - (int)sizeof(dcmd_value), 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, 0, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: set allmulti %d failed\n", - brcmf_ifname(drvr, 0), - le32_to_cpu(dcmd_le_value)); - } - - kfree(buf); - - /* Finally, pick up the PROMISC flag as well, like the NIC - driver does */ - - dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false; - dcmd_le_value = cpu_to_le32(dcmd_value); - - memset(&dcmd, 0, sizeof(dcmd)); - dcmd.cmd = BRCMF_C_SET_PROMISC; - dcmd.buf = &dcmd_le_value; - dcmd.len = sizeof(dcmd_le_value); - dcmd.set = true; - - ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: set promisc %d failed\n", - brcmf_ifname(drvr, 0), - le32_to_cpu(dcmd_le_value)); - } + err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value); + if (err < 0) + brcmf_dbg(ERROR, "Setting allmulti failed, %d\n", err); + + /*Finally, pick up the PROMISC flag */ + cmd_value = (ndev->flags & IFF_PROMISC) ? true : false; + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value); + if (err < 0) + brcmf_dbg(ERROR, "Setting BRCMF_C_SET_PROMISC failed, %d\n", + err); } static void _brcmf_set_mac_address(struct work_struct *work) { - char buf[32]; - struct brcmf_dcmd dcmd; - int ret; - - struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, - setmacaddr_work); + struct brcmf_if *ifp; + s32 err; brcmf_dbg(TRACE, "enter\n"); - if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr->macvalue, - ETH_ALEN, buf, 32)) { - brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n", - brcmf_ifname(drvr, 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, 0, &dcmd, dcmd.len); - if (ret < 0) - brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n", - brcmf_ifname(drvr, 0)); - else - memcpy(drvr->iflist[0]->ndev->dev_addr, - drvr->macvalue, ETH_ALEN); - - return; + ifp = container_of(work, struct brcmf_if, setmacaddr_work); + err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, + ETH_ALEN); + if (err < 0) { + brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err); + } else { + brcmf_dbg(TRACE, "MAC address updated to %pM\n", + ifp->mac_addr); + memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN); + } } static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_pub *drvr = ifp->drvr; struct sockaddr *sa = (struct sockaddr *)addr; - memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN); - schedule_work(&drvr->setmacaddr_work); + memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN); + schedule_work(&ifp->setmacaddr_work); return 0; } static void brcmf_netdev_set_multicast_list(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_pub *drvr = ifp->drvr; - schedule_work(&drvr->multicast_work); + schedule_work(&ifp->multicast_work); } static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) @@ -272,7 +172,7 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Reject if down */ if (!drvr->bus_if->drvr_up || - (drvr->bus_if->state == BRCMF_BUS_DOWN)) { + (drvr->bus_if->state != BRCMF_BUS_DATA)) { brcmf_dbg(ERROR, "xmit rejected drvup=%d state=%d\n", drvr->bus_if->drvr_up, drvr->bus_if->state); @@ -350,32 +250,13 @@ void brcmf_txflowblock(struct device *dev, bool state) } } -static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx, - void *pktdata, struct brcmf_event_msg *event, - void **data) -{ - int bcmerror = 0; - - bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data); - if (bcmerror != 0) - return bcmerror; - - if (drvr->iflist[*ifidx]->ndev) - brcmf_cfg80211_event(drvr->iflist[*ifidx]->ndev, - event, *data); - - return bcmerror; -} - -void brcmf_rx_frame(struct device *dev, int ifidx, +void brcmf_rx_frame(struct device *dev, u8 ifidx, struct sk_buff_head *skb_list) { unsigned char *eth; uint len; - void *data; struct sk_buff *skb, *pnext; struct brcmf_if *ifp; - struct brcmf_event_msg event; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; @@ -422,10 +303,7 @@ void brcmf_rx_frame(struct device *dev, int ifidx, 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, &ifidx, - skb_mac_header(skb), - &event, &data); + brcmf_fweh_process_skb(drvr, skb, &ifidx); if (drvr->iflist[ifidx]) { ifp = drvr->iflist[ifidx]; @@ -461,9 +339,11 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) eh = (struct ethhdr *)(txp->data); type = ntohs(eh->h_proto); - if (type == ETH_P_PAE) + if (type == ETH_P_PAE) { atomic_dec(&drvr->pend_8021x_cnt); - + if (waitqueue_active(&drvr->pend_8021x_wait)) + wake_up(&drvr->pend_8021x_wait); + } } static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) @@ -487,83 +367,26 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) 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_pub *drvr, int ifidx, u32 *toe_ol) -{ - struct brcmf_dcmd dcmd; - __le32 toe_le; - 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, 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, ifidx)); - return -EOPNOTSUPP; - } - - brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n", - brcmf_ifname(drvr, ifidx), ret); - return ret; - } - - memcpy(&toe_le, buf, sizeof(u32)); - *toe_ol = le32_to_cpu(toe_le); - return 0; -} - -/* Set current toe component enables in toe_ol iovar, - and set toe global enable iovar */ -static int brcmf_toe_set(struct brcmf_pub *drvr, int ifidx, u32 toe_ol) +/* + * Set current toe component enables in toe_ol iovar, + * and set toe global enable iovar + */ +static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol) { - struct brcmf_dcmd dcmd; - char buf[32]; - int ret; - __le32 toe_le = cpu_to_le32(toe_ol); - - memset(&dcmd, 0, sizeof(dcmd)); + s32 err; - 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_le, sizeof(u32)); - - ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n", - brcmf_ifname(drvr, ifidx), ret); - return ret; + err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol); + if (err < 0) { + brcmf_dbg(ERROR, "Setting toe_ol failed, %d\n", err); + return err; } - /* Enable toe globally only if any components are enabled. */ - toe_le = cpu_to_le32(toe_ol != 0); + err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0)); + if (err < 0) + brcmf_dbg(ERROR, "Setting toe failed, %d\n", err); - strcpy(buf, "toe"); - memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32)); + return err; - ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len); - if (ret < 0) { - brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n", - brcmf_ifname(drvr, ifidx), ret); - return ret; - } - - return 0; } static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, @@ -581,8 +404,9 @@ static const struct ethtool_ops brcmf_ethtool_ops = { .get_drvinfo = brcmf_ethtool_get_drvinfo, }; -static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr) +static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) { + struct brcmf_pub *drvr = ifp->drvr; struct ethtool_drvinfo info; char drvname[sizeof(info.driver)]; u32 cmd; @@ -633,7 +457,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr) /* Get toe offload components from dongle */ case ETHTOOL_GRXCSUM: case ETHTOOL_GTXCSUM: - ret = brcmf_toe_get(drvr, 0, &toe_cmpnt); + ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); if (ret < 0) return ret; @@ -654,7 +478,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr) return -EFAULT; /* Read the current settings, update and write back */ - ret = brcmf_toe_get(drvr, 0, &toe_cmpnt); + ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); if (ret < 0) return ret; @@ -666,18 +490,16 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr) else toe_cmpnt &= ~csum_dir; - ret = brcmf_toe_set(drvr, 0, toe_cmpnt); + ret = brcmf_toe_set(ifp, 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->iflist[0]->ndev->features |= - NETIF_F_IP_CSUM; + ifp->ndev->features |= NETIF_F_IP_CSUM; else - drvr->iflist[0]->ndev->features &= - ~NETIF_F_IP_CSUM; + ifp->ndev->features &= ~NETIF_F_IP_CSUM; } break; @@ -701,7 +523,7 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, return -1; if (cmd == SIOCETHTOOL) - return brcmf_ethtool(drvr, ifr->ifr_data); + return brcmf_ethtool(ifp, ifr->ifr_data); return -EOPNOTSUPP; } @@ -712,10 +534,12 @@ static int brcmf_netdev_stop(struct net_device *ndev) struct brcmf_pub *drvr = ifp->drvr; brcmf_dbg(TRACE, "Enter\n"); - brcmf_cfg80211_down(drvr->config); + if (drvr->bus_if->drvr_up == 0) return 0; + brcmf_cfg80211_down(ndev); + /* Set state and stop OS transmissions */ drvr->bus_if->drvr_up = false; netif_stop_queue(ndev); @@ -730,38 +554,35 @@ static int brcmf_netdev_open(struct net_device *ndev) struct brcmf_bus *bus_if = drvr->bus_if; u32 toe_ol; s32 ret = 0; - uint up = 0; brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); - if (ifp->idx == 0) { /* do it only for primary eth0 */ - /* If bus is not ready, can't continue */ - if (bus_if->state != BRCMF_BUS_DATA) { - brcmf_dbg(ERROR, "failed bus is not ready\n"); - return -EAGAIN; - } + /* If bus is not ready, can't continue */ + if (bus_if->state != BRCMF_BUS_DATA) { + brcmf_dbg(ERROR, "failed bus is not ready\n"); + return -EAGAIN; + } - atomic_set(&drvr->pend_8021x_cnt, 0); + atomic_set(&drvr->pend_8021x_cnt, 0); - memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); + memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); - /* Get current TOE mode from dongle */ - if (brcmf_toe_get(drvr, ifp->idx, &toe_ol) >= 0 - && (toe_ol & TOE_TX_CSUM_OL) != 0) - drvr->iflist[ifp->idx]->ndev->features |= - NETIF_F_IP_CSUM; - else - drvr->iflist[ifp->idx]->ndev->features &= - ~NETIF_F_IP_CSUM; - } + /* Get current TOE mode from dongle */ + if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 + && (toe_ol & TOE_TX_CSUM_OL) != 0) + drvr->iflist[ifp->idx]->ndev->features |= + NETIF_F_IP_CSUM; + else + drvr->iflist[ifp->idx]->ndev->features &= + ~NETIF_F_IP_CSUM; /* make sure RF is ready for work */ - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); /* Allow transmit calls */ netif_start_queue(ndev); drvr->bus_if->drvr_up = true; - if (brcmf_cfg80211_up(drvr->config)) { + if (brcmf_cfg80211_up(ndev)) { brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); return -1; } @@ -779,39 +600,38 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { .ndo_set_rx_mode = brcmf_netdev_set_multicast_list }; +static const struct net_device_ops brcmf_netdev_ops_virt = { + .ndo_open = brcmf_cfg80211_up, + .ndo_stop = brcmf_cfg80211_down, + .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_rx_mode = brcmf_netdev_set_multicast_list +}; + int brcmf_net_attach(struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; struct net_device *ndev; - u8 temp_addr[ETH_ALEN]; - - brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); - ndev = drvr->iflist[ifp->idx]->ndev; - ndev->netdev_ops = &brcmf_netdev_ops_pri; + brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); + ndev = ifp->ndev; - /* - * determine mac address to use - */ - if (is_valid_ether_addr(ifp->mac_addr)) - memcpy(temp_addr, ifp->mac_addr, ETH_ALEN); + /* set appropriate operations */ + if (!ifp->idx) + ndev->netdev_ops = &brcmf_netdev_ops_pri; else - memcpy(temp_addr, drvr->mac, ETH_ALEN); - - if (ifp->idx == 1) { - brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); - /* ACCESSPOINT INTERFACE CASE */ - temp_addr[0] |= 0X02; /* set bit 2 , - - Locally Administered address */ + ndev->netdev_ops = &brcmf_netdev_ops_virt; - } ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; ndev->ethtool_ops = &brcmf_ethtool_ops; drvr->rxsz = ndev->mtu + ndev->hard_header_len + drvr->hdrlen; - memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); + /* set the mac address */ + memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); if (register_netdev(ndev) != 0) { brcmf_dbg(ERROR, "couldn't register the net device\n"); @@ -824,17 +644,15 @@ int brcmf_net_attach(struct brcmf_if *ifp) fail: ndev->netdev_ops = NULL; - free_netdev(ndev); return -EBADE; } -struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, - char *name, u8 *mac_addr) +struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, + char *name, u8 *addr_mask) { struct brcmf_if *ifp; struct net_device *ndev; - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pub *drvr = bus_if->drvr; + int i; brcmf_dbg(TRACE, "idx %d\n", ifidx); @@ -844,12 +662,17 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, * in case we missed the BRCMF_E_IF_DEL event. */ if (ifp) { - brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", + brcmf_dbg(ERROR, "ERROR: netdev:%s already exists\n", ifp->ndev->name); - netif_stop_queue(ifp->ndev); - unregister_netdev(ifp->ndev); - free_netdev(ifp->ndev); - drvr->iflist[ifidx] = NULL; + if (ifidx) { + netif_stop_queue(ifp->ndev); + unregister_netdev(ifp->ndev); + free_netdev(ifp->ndev); + drvr->iflist[ifidx] = NULL; + } else { + brcmf_dbg(ERROR, "ignore IF event\n"); + return ERR_PTR(-EINVAL); + } } /* Allocate netdev, including space for private structure */ @@ -865,11 +688,16 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx, drvr->iflist[ifidx] = ifp; ifp->idx = ifidx; ifp->bssidx = bssidx; - if (mac_addr != NULL) - memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); - brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", - current->pid, ifp->ndev->name); + INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); + INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); + + if (addr_mask != NULL) + for (i = 0; i < ETH_ALEN; i++) + ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; + + brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", + current->pid, ifp->ndev->name, ifp->mac_addr); return ifp; } @@ -896,6 +724,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) netif_stop_queue(ifp->ndev); } + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); + unregister_netdev(ifp->ndev); drvr->iflist[ifidx] = NULL; if (ifidx == 0) @@ -934,11 +765,13 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) goto fail; } - INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address); - INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list); + /* attach firmware event handler */ + brcmf_fweh_attach(drvr); INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); + init_waitqueue_head(&drvr->pend_8021x_wait); + return ret; fail: @@ -964,7 +797,7 @@ int brcmf_bus_start(struct device *dev) } /* add primary networking interface */ - ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL); + ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL); if (IS_ERR(ifp)) return PTR_ERR(ifp); @@ -974,15 +807,25 @@ int brcmf_bus_start(struct device *dev) /* Bus is ready, do any initialization */ ret = brcmf_c_preinit_dcmds(ifp); if (ret < 0) - return ret; + goto fail; drvr->config = brcmf_cfg80211_attach(drvr); - if (drvr->config == NULL) - return -ENOMEM; + if (drvr->config == NULL) { + ret = -ENOMEM; + goto fail; + } + + ret = brcmf_fweh_activate_events(ifp); + if (ret < 0) + goto fail; ret = brcmf_net_attach(ifp); +fail: if (ret < 0) { - brcmf_dbg(ERROR, "brcmf_net_attach failed"); + brcmf_dbg(ERROR, "failed: %d\n", ret); + if (drvr->config) + brcmf_cfg80211_detach(drvr->config); + free_netdev(drvr->iflist[0]->ndev); drvr->iflist[0] = NULL; return ret; } @@ -1011,6 +854,11 @@ void brcmf_detach(struct device *dev) brcmf_dbg(TRACE, "Enter\n"); + if (drvr == NULL) + return; + + /* stop firmware event handling */ + brcmf_fweh_detach(drvr); /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) @@ -1020,8 +868,6 @@ void brcmf_detach(struct device *dev) brcmf_bus_detach(drvr); if (drvr->prot) { - cancel_work_sync(&drvr->setmacaddr_work); - cancel_work_sync(&drvr->multicast_work); brcmf_proto_detach(drvr); } @@ -1035,26 +881,19 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr) return atomic_read(&drvr->pend_8021x_cnt); } -#define MAX_WAIT_FOR_8021X_TX 10 - int brcmf_netdev_wait_pend8021x(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - int timeout = 10 * HZ / 1000; - int ntimes = MAX_WAIT_FOR_8021X_TX; - int pend = brcmf_get_pend_8021x_cnt(drvr); - - 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); - } - return pend; + int err; + + err = wait_event_timeout(drvr->pend_8021x_wait, + !brcmf_get_pend_8021x_cnt(drvr), + msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); + + WARN_ON(!err); + + return !err; } static void brcmf_driver_init(struct work_struct *work) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h index 7fe6779..48fa703 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h @@ -36,14 +36,7 @@ extern void brcmf_proto_stop(struct brcmf_pub *drvr); extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, struct sk_buff *txp); -/* Use protocol to issue command to dongle */ -extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, - struct brcmf_dcmd *dcmd, int len); - /* Sets dongle media info (drv_version, mac address). */ extern int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); -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/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 415f2be..4572545 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -533,9 +533,11 @@ struct brcmf_sdio { u8 *rxbuf; /* Buffer for receiving control packets */ uint rxblen; /* Allocated length of rxbuf */ u8 *rxctl; /* Aligned pointer into rxbuf */ + u8 *rxctl_orig; /* pointer for freeing rxctl */ u8 *databuf; /* Buffer for receiving big glom packet */ u8 *dataptr; /* Aligned pointer into databuf */ uint rxlen; /* Length of valid data in buffer */ + spinlock_t rxctl_lock; /* protection lock for ctrl frame resources */ u8 sdpcm_ver; /* Bus protocol reported by dongle */ @@ -582,8 +584,6 @@ struct brcmf_sdio { struct list_head dpc_tsklst; spinlock_t dpc_tl_lock; - struct semaphore sdsem; - const struct firmware *firmware; u32 fw_ptr; @@ -1037,9 +1037,9 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) } } -static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, - struct brcmf_sdio_read *rd, - enum brcmf_sdio_frmtype type) +static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, + struct brcmf_sdio_read *rd, + enum brcmf_sdio_frmtype type) { u16 len, checksum; u8 rx_seq, fc, tx_seq_max; @@ -1054,26 +1054,26 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, /* All zero means no more to read */ if (!(len | checksum)) { bus->rxpending = false; - return false; + return -ENODATA; } if ((u16)(~(len ^ checksum))) { brcmf_dbg(ERROR, "HW header checksum error\n"); bus->sdcnt.rx_badhdr++; brcmf_sdbrcm_rxfail(bus, false, false); - return false; + return -EIO; } if (len < SDPCM_HDRLEN) { brcmf_dbg(ERROR, "HW header length error\n"); - return false; + return -EPROTO; } if (type == BRCMF_SDIO_FT_SUPER && (roundup(len, bus->blocksize) != rd->len)) { brcmf_dbg(ERROR, "HW superframe header length error\n"); - return false; + return -EPROTO; } if (type == BRCMF_SDIO_FT_SUB && len > rd->len) { brcmf_dbg(ERROR, "HW subframe header length error\n"); - return false; + return -EPROTO; } rd->len = len; @@ -1091,7 +1091,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) { brcmf_dbg(ERROR, "Glom descriptor found in superframe head\n"); rd->len = 0; - return false; + return -EINVAL; } rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]); rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); @@ -1102,18 +1102,18 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, bus->sdcnt.rx_toolong++; brcmf_sdbrcm_rxfail(bus, false, false); rd->len = 0; - return false; + return -EPROTO; } if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) { brcmf_dbg(ERROR, "Wrong channel for superframe\n"); rd->len = 0; - return false; + return -EINVAL; } if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL && rd->channel != SDPCM_EVENT_CHANNEL) { brcmf_dbg(ERROR, "Wrong channel for subframe\n"); rd->len = 0; - return false; + return -EINVAL; } rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]); if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { @@ -1121,7 +1121,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, bus->sdcnt.rx_badhdr++; brcmf_sdbrcm_rxfail(bus, false, false); rd->len = 0; - return false; + return -ENXIO; } if (rd->seq_num != rx_seq) { brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n", @@ -1131,7 +1131,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, } /* no need to check the reset for subframe */ if (type == BRCMF_SDIO_FT_SUB) - return true; + return 0; rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) { /* only warm for NON glom packet */ @@ -1155,7 +1155,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, } bus->tx_max = tx_seq_max; - return true; + return 0; } static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) @@ -1272,6 +1272,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) * read directly into the chained packet, or allocate a large * packet and and copy into the chain. */ + sdio_claim_host(bus->sdiodev->func[1]); if (usechain) { errcode = brcmf_sdcard_recv_chain(bus->sdiodev, bus->sdiodev->sbwad, @@ -1293,6 +1294,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) dlen); errcode = -1; } + sdio_release_host(bus->sdiodev->func[1]); bus->sdcnt.f2rxdata++; /* On failure, kill the superframe, allow a couple retries */ @@ -1301,6 +1303,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) dlen, errcode); bus->sdiodev->bus_if->dstats.rx_errors++; + sdio_claim_host(bus->sdiodev->func[1]); if (bus->glomerr++ < 3) { brcmf_sdbrcm_rxfail(bus, true, true); } else { @@ -1309,6 +1312,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) bus->sdcnt.rxglomfail++; brcmf_sdbrcm_free_glom(bus); } + sdio_release_host(bus->sdiodev->func[1]); return 0; } @@ -1318,8 +1322,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) rd_new.seq_num = rxseq; rd_new.len = dlen; - errcode = -!brcmf_sdio_hdparser(bus, pfirst->data, &rd_new, - BRCMF_SDIO_FT_SUPER); + sdio_claim_host(bus->sdiodev->func[1]); + errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new, + BRCMF_SDIO_FT_SUPER); + sdio_release_host(bus->sdiodev->func[1]); bus->cur_read.len = rd_new.len_nxtfrm << 4; /* Remove superframe header, remember offset */ @@ -1335,9 +1341,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) rd_new.len = pnext->len; rd_new.seq_num = rxseq++; - errcode = -!brcmf_sdio_hdparser(bus, pnext->data, - &rd_new, - BRCMF_SDIO_FT_SUB); + sdio_claim_host(bus->sdiodev->func[1]); + errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new, + BRCMF_SDIO_FT_SUB); + sdio_release_host(bus->sdiodev->func[1]); brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), pnext->data, 32, "subframe:\n"); @@ -1347,6 +1354,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) if (errcode) { /* Terminate frame on error, request a couple retries */ + sdio_claim_host(bus->sdiodev->func[1]); if (bus->glomerr++ < 3) { /* Restore superframe header space */ skb_push(pfirst, sfdoff); @@ -1357,6 +1365,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) bus->sdcnt.rxglomfail++; brcmf_sdbrcm_free_glom(bus); } + sdio_release_host(bus->sdiodev->func[1]); bus->cur_read.len = 0; return 0; } @@ -1397,11 +1406,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) pfirst->prev); } /* sent any remaining packets up */ - if (bus->glom.qlen) { - up(&bus->sdsem); + if (bus->glom.qlen) brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom); - down(&bus->sdsem); - } bus->sdcnt.rxglomframes++; bus->sdcnt.rxglompkts += bus->glom.qlen; @@ -1442,21 +1448,24 @@ static void brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) { uint rdlen, pad; - + u8 *buf = NULL, *rbuf; 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 (bus->rxblen) + buf = vzalloc(bus->rxblen); + if (!buf) { + brcmf_dbg(ERROR, "no memory for control frame\n"); + goto done; + } + rbuf = bus->rxbuf; + pad = ((unsigned long)rbuf % BRCMF_SDALIGN); if (pad) - bus->rxctl += (BRCMF_SDALIGN - pad); - bus->rxctl -= BRCMF_FIRSTREAD; + rbuf += (BRCMF_SDALIGN - pad); /* Copy the already-read portion over */ - memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); + memcpy(buf, hdr, BRCMF_FIRSTREAD); if (len <= BRCMF_FIRSTREAD) goto gotpkt; @@ -1493,11 +1502,11 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) goto done; } - /* Read remainder of frame body into the rxctl buffer */ + /* Read remain of frame body */ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, - F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen); + F2SYNC, rbuf, rdlen); bus->sdcnt.f2rxdata++; /* Control frame failures need retransmission */ @@ -1507,16 +1516,26 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) bus->sdcnt.rxc_errors++; brcmf_sdbrcm_rxfail(bus, true, true); goto done; - } + } else + memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen); gotpkt: brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), - bus->rxctl, len, "RxCtrl:\n"); + buf, len, "RxCtrl:\n"); /* Point to valid data and indicate its length */ - bus->rxctl += doff; + spin_lock_bh(&bus->rxctl_lock); + if (bus->rxctl) { + brcmf_dbg(ERROR, "last control frame is being processed.\n"); + spin_unlock_bh(&bus->rxctl_lock); + vfree(buf); + goto done; + } + bus->rxctl = buf + doff; + bus->rxctl_orig = buf; bus->rxlen = len - doff; + spin_unlock_bh(&bus->rxctl_lock); done: /* Awake any waiters */ @@ -1571,6 +1590,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) rd->len_left = rd->len; /* read header first for unknow frame length */ + sdio_claim_host(bus->sdiodev->func[1]); if (!rd->len) { sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, @@ -1583,6 +1603,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) sdret); bus->sdcnt.rx_hdrfail++; brcmf_sdbrcm_rxfail(bus, true, true); + sdio_release_host(bus->sdiodev->func[1]); continue; } @@ -1590,8 +1611,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); - if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd, - BRCMF_SDIO_FT_NORMAL)) { + if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd, + BRCMF_SDIO_FT_NORMAL)) { + sdio_release_host(bus->sdiodev->func[1]); if (!bus->rxpending) break; else @@ -1607,6 +1629,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) rd->len_nxtfrm = 0; /* treat all packet as event if we don't know */ rd->channel = SDPCM_EVENT_CHANNEL; + sdio_release_host(bus->sdiodev->func[1]); continue; } rd->len_left = rd->len > BRCMF_FIRSTREAD ? @@ -1624,6 +1647,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) bus->sdiodev->bus_if->dstats.rx_dropped++; brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(rd->channel)); + sdio_release_host(bus->sdiodev->func[1]); continue; } skb_pull(pkt, head_read); @@ -1632,14 +1656,17 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, pkt); bus->sdcnt.f2rxdata++; + sdio_release_host(bus->sdiodev->func[1]); if (sdret < 0) { brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n", rd->len, rd->channel, sdret); brcmu_pkt_buf_free_skb(pkt); bus->sdiodev->bus_if->dstats.rx_errors++; + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(rd->channel)); + sdio_release_host(bus->sdiodev->func[1]); continue; } @@ -1650,8 +1677,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) } else { memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN); rd_new.seq_num = rd->seq_num; - if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new, - BRCMF_SDIO_FT_NORMAL)) { + sdio_claim_host(bus->sdiodev->func[1]); + if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new, + BRCMF_SDIO_FT_NORMAL)) { rd->len = 0; brcmu_pkt_buf_free_skb(pkt); } @@ -1662,9 +1690,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) roundup(rd_new.len, 16) >> 4); rd->len = 0; brcmf_sdbrcm_rxfail(bus, true, true); + sdio_release_host(bus->sdiodev->func[1]); brcmu_pkt_buf_free_skb(pkt); continue; } + sdio_release_host(bus->sdiodev->func[1]); rd->len_nxtfrm = rd_new.len_nxtfrm; rd->channel = rd_new.channel; rd->dat_offset = rd_new.dat_offset; @@ -1680,7 +1710,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) rd_new.seq_num); /* Force retry w/normal header read */ rd->len = 0; + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_rxfail(bus, false, true); + sdio_release_host(bus->sdiodev->func[1]); brcmu_pkt_buf_free_skb(pkt); continue; } @@ -1703,7 +1735,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) } else { brcmf_dbg(ERROR, "%s: glom superframe w/o " "descriptor!\n", __func__); + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_rxfail(bus, false, false); + sdio_release_host(bus->sdiodev->func[1]); } /* prepare the descriptor for the next read */ rd->len = rd->len_nxtfrm << 4; @@ -1734,10 +1768,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) continue; } - /* Unlock during rx call */ - up(&bus->sdsem); brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); - down(&bus->sdsem); } rxcount = maxframes - rxleft; @@ -1755,15 +1786,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) } static void -brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar) -{ - up(&bus->sdsem); - wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2); - down(&bus->sdsem); - return; -} - -static void brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) { if (waitqueue_active(&bus->ctrl_wait)) @@ -1864,6 +1886,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, if (len & (ALIGNMENT - 1)) len = roundup(len, ALIGNMENT); + sdio_claim_host(bus->sdiodev->func[1]); ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, pkt); bus->sdcnt.f2txdata++; @@ -1891,15 +1914,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, } } + sdio_release_host(bus->sdiodev->func[1]); 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->sdiodev->dev, pkt, ret != 0); - down(&bus->sdsem); if (free_pkt) brcmu_pkt_buf_free_skb(pkt); @@ -1940,9 +1962,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) /* In poll mode, need to check for other events */ if (!bus->intr && cnt) { /* Check device status, signal pending interrupt */ + sdio_claim_host(bus->sdiodev->func[1]); ret = r_sdreg32(bus, &intstatus, offsetof(struct sdpcmd_regs, intstatus)); + sdio_release_host(bus->sdiodev->func[1]); bus->sdcnt.f2txdata++; if (ret != 0) break; @@ -1979,7 +2003,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) bus->watchdog_tsk = NULL; } - down(&bus->sdsem); + sdio_claim_host(bus->sdiodev->func[1]); /* Enable clock for device interrupts */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -2013,6 +2037,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) /* Turn off the backplane clock (only) */ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + sdio_release_host(bus->sdiodev->func[1]); /* Clear the data packet queues */ brcmu_pktq_flush(&bus->txq, true, NULL, NULL); @@ -2023,14 +2048,14 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) brcmf_sdbrcm_free_glom(bus); /* Clear rx control and wake any waiters */ + spin_lock_bh(&bus->rxctl_lock); bus->rxlen = 0; + spin_unlock_bh(&bus->rxctl_lock); brcmf_sdbrcm_dcmd_resp_wake(bus); /* Reset some F2 state stuff */ bus->rxskip = false; bus->tx_seq = bus->rx_seq = 0; - - up(&bus->sdsem); } #ifdef CONFIG_BRCMFMAC_SDIO_OOB @@ -2114,7 +2139,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); - down(&bus->sdsem); + sdio_claim_host(bus->sdiodev->func[1]); /* If waiting for HTAVAIL, check status */ if (bus->clkstate == CLK_PENDING) { @@ -2168,9 +2193,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) /* Pending interrupt indicates new device status */ if (atomic_read(&bus->ipend) > 0) { atomic_set(&bus->ipend, 0); - sdio_claim_host(bus->sdiodev->func[1]); err = brcmf_sdio_intr_rstatus(bus); - sdio_release_host(bus->sdiodev->func[1]); } /* Start with leftover status bits */ @@ -2199,6 +2222,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) intstatus |= brcmf_sdbrcm_hostmail(bus); } + sdio_release_host(bus->sdiodev->func[1]); + /* Generally don't ask for these, can get CRC errors... */ if (intstatus & I_WR_OOSYNC) { brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); @@ -2245,6 +2270,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) (bus->clkstate == CLK_AVAIL)) { int i; + sdio_claim_host(bus->sdiodev->func[1]); err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf, (u32) bus->ctrl_frame_len); @@ -2278,6 +2304,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) } else { bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; } + sdio_release_host(bus->sdiodev->func[1]); bus->ctrl_frame_stat = false; brcmf_sdbrcm_wait_event_wakeup(bus); } @@ -2307,10 +2334,10 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) if ((bus->clkstate != CLK_PENDING) && bus->idletime == BRCMF_IDLE_IMMEDIATE) { bus->activity = false; + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + sdio_release_host(bus->sdiodev->func[1]); } - - up(&bus->sdsem); } static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) @@ -2601,11 +2628,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ - /* Need to lock here to protect txseq and SDIO tx calls */ - down(&bus->sdsem); - /* Make sure backplane clock is on */ + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + sdio_release_host(bus->sdiodev->func[1]); /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ *(__le16 *) frame = cpu_to_le16((u16) msglen); @@ -2628,7 +2654,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) bus->ctrl_frame_buf = frame; bus->ctrl_frame_len = len; - brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); + wait_event_interruptible_timeout(bus->ctrl_wait, + !bus->ctrl_frame_stat, + msecs_to_jiffies(2000)); if (!bus->ctrl_frame_stat) { brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); @@ -2647,7 +2675,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) frame, min_t(u16, len, 16), "TxHdr:\n"); do { + sdio_claim_host(bus->sdiodev->func[1]); ret = brcmf_tx_frame(bus, frame, len); + sdio_release_host(bus->sdiodev->func[1]); } while (ret < 0 && retries++ < TXRETRIES); } @@ -2657,13 +2687,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); bus->activity = false; + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); + sdio_release_host(bus->sdiodev->func[1]); } else { spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); } - up(&bus->sdsem); - if (ret) bus->sdcnt.tx_ctlerrs++; else @@ -2693,8 +2723,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, * Read last word in socram to determine * address of sdpcm_shared structure */ + sdio_claim_host(bus->sdiodev->func[1]); rv = brcmf_sdbrcm_membytes(bus, false, shaddr, (u8 *)&addr_le, 4); + sdio_claim_host(bus->sdiodev->func[1]); if (rv < 0) return rv; @@ -2713,8 +2745,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, } /* Read hndrte_shared structure */ + sdio_claim_host(bus->sdiodev->func[1]); rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, sizeof(struct sdpcm_shared_le)); + sdio_release_host(bus->sdiodev->func[1]); if (rv < 0) return rv; @@ -2817,12 +2851,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, if ((sh->flags & SDPCM_SHARED_TRAP) == 0) return 0; + sdio_claim_host(bus->sdiodev->func[1]); error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, sizeof(struct brcmf_trap_info)); if (error < 0) return error; nbytes = brcmf_sdio_dump_console(bus, sh, data, count); + sdio_release_host(bus->sdiodev->func[1]); if (nbytes < 0) return nbytes; @@ -2868,6 +2904,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus, return 0; } + sdio_claim_host(bus->sdiodev->func[1]); if (sh->assert_file_addr != 0) { error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr, (u8 *)file, 80); @@ -2880,6 +2917,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus, if (error < 0) return error; } + sdio_release_host(bus->sdiodev->func[1]); res = scnprintf(buf, sizeof(buf), "dongle assert: %s:%d: assert(%s)\n", @@ -2892,9 +2930,7 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) int error; struct sdpcm_shared sh; - down(&bus->sdsem); error = brcmf_sdio_readshared(bus, &sh); - up(&bus->sdsem); if (error < 0) return error; @@ -2921,7 +2957,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data, if (pos != 0) return 0; - down(&bus->sdsem); error = brcmf_sdio_readshared(bus, &sh); if (error < 0) goto done; @@ -2938,7 +2973,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data, error += nbytes; *ppos += error; done: - up(&bus->sdsem); return error; } @@ -2989,6 +3023,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) int timeleft; uint rxlen = 0; bool pending; + u8 *buf; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; @@ -2998,11 +3033,15 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) /* Wait until control frame is available */ timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); - down(&bus->sdsem); + spin_lock_bh(&bus->rxctl_lock); rxlen = bus->rxlen; memcpy(msg, bus->rxctl, min(msglen, rxlen)); + bus->rxctl = NULL; + buf = bus->rxctl_orig; + bus->rxctl_orig = NULL; bus->rxlen = 0; - up(&bus->sdsem); + spin_unlock_bh(&bus->rxctl_lock); + vfree(buf); if (rxlen) { brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n", @@ -3338,13 +3377,16 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) { bool ret; - /* Download the firmware */ + sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); ret = _brcmf_sdbrcm_download_firmware(bus) == 0; brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + sdio_release_host(bus->sdiodev->func[1]); + return ret; } @@ -3373,7 +3415,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) bus->sdcnt.tickcnt = 0; brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - down(&bus->sdsem); + sdio_claim_host(bus->sdiodev->func[1]); /* Make sure backplane clock is on, needed to generate F2 interrupt */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -3442,7 +3484,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); exit: - up(&bus->sdsem); + sdio_release_host(bus->sdiodev->func[1]); return ret; } @@ -3489,8 +3531,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) brcmf_dbg(TIMER, "Enter\n"); - down(&bus->sdsem); - /* Poll period: check device if appropriate. */ if (bus->poll && (++bus->polltick >= bus->pollrate)) { u32 intstatus = 0; @@ -3507,9 +3547,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) u8 devpend; spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); + sdio_claim_host(bus->sdiodev->func[1]); devpend = brcmf_sdio_regrb(bus->sdiodev, SDIO_CCCR_INTx, NULL); + sdio_release_host(bus->sdiodev->func[1]); intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); @@ -3534,16 +3576,18 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) } #ifdef DEBUG /* Poll for console output periodically */ - if (bus_if->state == BRCMF_BUS_DATA && + if (bus_if && bus_if->state == 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; + sdio_claim_host(bus->sdiodev->func[1]); /* 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; + sdio_release_host(bus->sdiodev->func[1]); } } #endif /* DEBUG */ @@ -3556,13 +3600,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) bus->activity = false; brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); } else { + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + sdio_release_host(bus->sdiodev->func[1]); } } } - up(&bus->sdsem); - return (atomic_read(&bus->ipend) > 0); } @@ -3657,6 +3701,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) bus->alp_only = true; + sdio_claim_host(bus->sdiodev->func[1]); + pr_debug("F1 signature read @0x18000000=0x%4x\n", brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); @@ -3704,6 +3750,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL); brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL); + sdio_release_host(bus->sdiodev->func[1]); + brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); /* Locate an appropriately-aligned portion of hdrbuf */ @@ -3719,6 +3767,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) return true; fail: + sdio_release_host(bus->sdiodev->func[1]); return false; } @@ -3726,6 +3775,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) { brcmf_dbg(TRACE, "Enter\n"); + sdio_claim_host(bus->sdiodev->func[1]); + /* Disable F2 to clear any intermediate frame state on the dongle */ brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1, NULL); @@ -3736,6 +3787,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) /* Done with backplane-dependent accesses, can drop clock... */ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + sdio_release_host(bus->sdiodev->func[1]); + /* ...and initialize clock/power states */ bus->clkstate = CLK_SDONLY; bus->idletime = BRCMF_IDLE_INTERVAL; @@ -3791,8 +3844,10 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); if (bus->ci) { + sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + sdio_release_host(bus->sdiodev->func[1]); brcmf_sdio_chip_detach(&bus->ci); if (bus->vars && bus->varsz) kfree(bus->vars); @@ -3812,7 +3867,8 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) brcmf_sdio_intr_unregister(bus->sdiodev); cancel_work_sync(&bus->datawork); - destroy_workqueue(bus->brcmf_wq); + if (bus->brcmf_wq) + destroy_workqueue(bus->brcmf_wq); if (bus->sdiodev->bus_if->drvr) { brcmf_detach(bus->sdiodev->dev); @@ -3854,31 +3910,29 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->txminmax = BRCMF_TXMINMAX; bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; + INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); + bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); + if (bus->brcmf_wq == NULL) { + brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); + goto fail; + } + /* 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->rxctl_lock); spin_lock_init(&bus->txqlock); init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->dcmd_resp_wait); - bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); - if (bus->brcmf_wq == NULL) { - brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); - goto fail; - } - INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); - /* 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, @@ -3941,10 +3995,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); if (ret != 0) { - if (ret == -ENOLINK) { - brcmf_dbg(ERROR, "dongle is not responding\n"); - goto fail; - } + brcmf_dbg(ERROR, "dongle is not responding\n"); + goto fail; } return bus; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c new file mode 100644 index 0000000..fa8fc44 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2012 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/netdevice.h> + +#include "brcmu_wifi.h" +#include "brcmu_utils.h" + +#include "dhd.h" +#include "dhd_dbg.h" +#include "fweh.h" +#include "fwil.h" + +/** + * struct brcm_ethhdr - broadcom specific ether header. + * + * @subtype: subtype for this packet. + * @length: TODO: length of appended data. + * @version: version indication. + * @oui: OUI of this packet. + * @usr_subtype: subtype for this OUI. + */ +struct brcm_ethhdr { + __be16 subtype; + __be16 length; + u8 version; + u8 oui[3]; + __be16 usr_subtype; +} __packed; + +struct brcmf_event_msg_be { + __be16 version; + __be16 flags; + __be32 event_type; + __be32 status; + __be32 reason; + __be32 auth_type; + __be32 datalen; + u8 addr[ETH_ALEN]; + char ifname[IFNAMSIZ]; + u8 ifidx; + u8 bsscfgidx; +} __packed; + +/** + * struct brcmf_event - contents of broadcom event packet. + * + * @eth: standard ether header. + * @hdr: broadcom specific ether header. + * @msg: common part of the actual event message. + */ +struct brcmf_event { + struct ethhdr eth; + struct brcm_ethhdr hdr; + struct brcmf_event_msg_be msg; +} __packed; + +/** + * struct brcmf_fweh_queue_item - event item on event queue. + * + * @q: list element for queuing. + * @code: event code. + * @ifidx: interface index related to this event. + * @ifaddr: ethernet address for interface. + * @emsg: common parameters of the firmware event message. + * @data: event specific data part of the firmware event. + */ +struct brcmf_fweh_queue_item { + struct list_head q; + enum brcmf_fweh_event_code code; + u8 ifidx; + u8 ifaddr[ETH_ALEN]; + struct brcmf_event_msg_be emsg; + u8 data[0]; +}; + +/** + * struct brcmf_fweh_event_name - code, name mapping entry. + */ +struct brcmf_fweh_event_name { + enum brcmf_fweh_event_code code; + const char *name; +}; + +#ifdef DEBUG +/* array for mapping code to event name */ +static struct brcmf_fweh_event_name fweh_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_IF, "IF" }, + { BRCMF_E_RSSI, "RSSI" }, + { BRCMF_E_PFN_SCAN_COMPLETE, "PFN_SCAN_COMPLETE" }, + { BRCMF_E_EXTLOG_MSG, "EXTLOG_MSG" }, + { BRCMF_E_ACTION_FRAME, "ACTION_FRAME" }, + { BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, + { BRCMF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND" }, + { BRCMF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND" }, + { BRCMF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" }, + { BRCMF_E_AP_STARTED, "AP_STARTED" }, + { BRCMF_E_DFS_AP_STOP, "DFS_AP_STOP" }, + { BRCMF_E_DFS_AP_RESUME, "DFS_AP_RESUME" }, + { BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT" }, + { BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRM_OFF_CHAN_CMPLT" }, + { BRCMF_E_DCS_REQUEST, "DCS_REQUEST" }, + { BRCMF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"} +}; + +/** + * brcmf_fweh_event_name() - returns name for given event code. + * + * @code: code to lookup. + */ +static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) +{ + int i; + for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) { + if (fweh_event_names[i].code == code) + return fweh_event_names[i].name; + } + return "unknown"; +} +#else +static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) +{ + return "nodebug"; +} +#endif + +/** + * brcmf_fweh_queue_event() - create and queue event. + * + * @fweh: firmware event handling info. + * @event: event queue entry. + */ +static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, + struct brcmf_fweh_queue_item *event) +{ + ulong flags; + + spin_lock_irqsave(&fweh->evt_q_lock, flags); + list_add_tail(&event->q, &fweh->event_q); + spin_unlock_irqrestore(&fweh->evt_q_lock, flags); + schedule_work(&fweh->event_work); +} + +static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp, + enum brcmf_fweh_event_code code, + struct brcmf_event_msg *emsg, + void *data) +{ + struct brcmf_fweh_info *fweh; + int err = -EINVAL; + + if (ifp) { + fweh = &ifp->drvr->fweh; + + /* handle the event if valid interface and handler */ + if (ifp->ndev && fweh->evt_handler[code]) + err = fweh->evt_handler[code](ifp, emsg, data); + else + brcmf_dbg(ERROR, "unhandled event %d ignored\n", code); + } else { + brcmf_dbg(ERROR, "no interface object\n"); + } + return err; +} + +/** + * brcmf_fweh_handle_if_event() - handle IF event. + * + * @drvr: driver information object. + * @item: queue entry. + * @ifpp: interface object (may change upon ADD action). + */ +static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, + struct brcmf_event_msg *emsg, + void *data) +{ + struct brcmf_if_event *ifevent = data; + struct brcmf_if *ifp; + int err = 0; + + brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n", + ifevent->action, ifevent->ifidx, + ifevent->bssidx, ifevent->flags); + + if (ifevent->ifidx >= BRCMF_MAX_IFS) { + brcmf_dbg(ERROR, "invalid interface index: %u\n", + ifevent->ifidx); + return; + } + + ifp = drvr->iflist[ifevent->ifidx]; + + if (ifevent->action == BRCMF_E_IF_ADD) { + brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, + emsg->addr); + ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, + emsg->ifname, emsg->addr); + if (IS_ERR(ifp)) + return; + + if (!drvr->fweh.evt_handler[BRCMF_E_IF]) + err = brcmf_net_attach(ifp); + } + + err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); + + if (ifevent->action == BRCMF_E_IF_DEL) + brcmf_del_if(drvr, ifevent->ifidx); +} + +/** + * brcmf_fweh_dequeue_event() - get event from the queue. + * + * @fweh: firmware event handling info. + */ +static struct brcmf_fweh_queue_item * +brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh) +{ + struct brcmf_fweh_queue_item *event = NULL; + ulong flags; + + spin_lock_irqsave(&fweh->evt_q_lock, flags); + if (!list_empty(&fweh->event_q)) { + event = list_first_entry(&fweh->event_q, + struct brcmf_fweh_queue_item, q); + list_del(&event->q); + } + spin_unlock_irqrestore(&fweh->evt_q_lock, flags); + + return event; +} + +/** + * brcmf_fweh_event_worker() - firmware event worker. + * + * @work: worker object. + */ +static void brcmf_fweh_event_worker(struct work_struct *work) +{ + struct brcmf_pub *drvr; + struct brcmf_if *ifp; + struct brcmf_fweh_info *fweh; + struct brcmf_fweh_queue_item *event; + int err = 0; + struct brcmf_event_msg_be *emsg_be; + struct brcmf_event_msg emsg; + + fweh = container_of(work, struct brcmf_fweh_info, event_work); + drvr = container_of(fweh, struct brcmf_pub, fweh); + + while ((event = brcmf_fweh_dequeue_event(fweh))) { + ifp = drvr->iflist[event->ifidx]; + + brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n", + brcmf_fweh_event_name(event->code), event->code, + event->emsg.ifidx, event->emsg.bsscfgidx, + event->emsg.addr); + + /* convert event message */ + emsg_be = &event->emsg; + emsg.version = be16_to_cpu(emsg_be->version); + emsg.flags = be16_to_cpu(emsg_be->flags); + emsg.event_code = event->code; + emsg.status = be32_to_cpu(emsg_be->status); + emsg.reason = be32_to_cpu(emsg_be->reason); + emsg.auth_type = be32_to_cpu(emsg_be->auth_type); + emsg.datalen = be32_to_cpu(emsg_be->datalen); + memcpy(emsg.addr, emsg_be->addr, ETH_ALEN); + memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname)); + emsg.ifidx = emsg_be->ifidx; + emsg.bsscfgidx = emsg_be->bsscfgidx; + + brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n", + emsg.version, emsg.flags, emsg.status, emsg.reason); + brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, + min_t(u32, emsg.datalen, 64), + "appended:"); + + /* special handling of interface event */ + if (event->code == BRCMF_E_IF) { + brcmf_fweh_handle_if_event(drvr, &emsg, event->data); + goto event_free; + } + + err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, + event->data); + if (err) { + brcmf_dbg(ERROR, "event handler failed (%d)\n", + event->code); + err = 0; + } +event_free: + kfree(event); + } +} + +/** + * brcmf_fweh_attach() - initialize firmware event handling. + * + * @drvr: driver information object. + */ +void brcmf_fweh_attach(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh = &drvr->fweh; + INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); + spin_lock_init(&fweh->evt_q_lock); + INIT_LIST_HEAD(&fweh->event_q); +} + +/** + * brcmf_fweh_detach() - cleanup firmware event handling. + * + * @drvr: driver information object. + */ +void brcmf_fweh_detach(struct brcmf_pub *drvr) +{ + struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_if *ifp = drvr->iflist[0]; + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + + if (ifp) { + /* clear all events */ + memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN); + (void)brcmf_fil_iovar_data_set(ifp, "event_msgs", + eventmask, + BRCMF_EVENTING_MASK_LEN); + } + /* cancel the worker */ + cancel_work_sync(&fweh->event_work); + WARN_ON(!list_empty(&fweh->event_q)); + memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler)); +} + +/** + * brcmf_fweh_register() - register handler for given event code. + * + * @drvr: driver information object. + * @code: event code. + * @handler: handler for the given event code. + */ +int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, + brcmf_fweh_handler_t handler) +{ + if (drvr->fweh.evt_handler[code]) { + brcmf_dbg(ERROR, "event code %d already registered\n", code); + return -ENOSPC; + } + drvr->fweh.evt_handler[code] = handler; + brcmf_dbg(TRACE, "event handler registered for %s\n", + brcmf_fweh_event_name(code)); + return 0; +} + +/** + * brcmf_fweh_unregister() - remove handler for given code. + * + * @drvr: driver information object. + * @code: event code. + */ +void brcmf_fweh_unregister(struct brcmf_pub *drvr, + enum brcmf_fweh_event_code code) +{ + brcmf_dbg(TRACE, "event handler cleared for %s\n", + brcmf_fweh_event_name(code)); + drvr->fweh.evt_handler[code] = NULL; +} + +/** + * brcmf_fweh_activate_events() - enables firmware events registered. + * + * @ifp: primary interface object. + */ +int brcmf_fweh_activate_events(struct brcmf_if *ifp) +{ + int i, err; + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + + for (i = 0; i < BRCMF_E_LAST; i++) { + if (ifp->drvr->fweh.evt_handler[i]) { + brcmf_dbg(EVENT, "enable event %s\n", + brcmf_fweh_event_name(i)); + setbit(eventmask, i); + } + } + + /* want to handle IF event as well */ + brcmf_dbg(EVENT, "enable event IF\n"); + setbit(eventmask, BRCMF_E_IF); + + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", + eventmask, BRCMF_EVENTING_MASK_LEN); + if (err) + brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err); + + return err; +} + +/** + * brcmf_fweh_process_event() - process skb as firmware event. + * + * @drvr: driver information object. + * @event_packet: event packet to process. + * @ifidx: index of the firmware interface (may change). + * + * If the packet buffer contains a firmware event message it will + * dispatch the event to a registered handler (using worker). + */ +void brcmf_fweh_process_event(struct brcmf_pub *drvr, + struct brcmf_event *event_packet, u8 *ifidx) +{ + enum brcmf_fweh_event_code code; + struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_queue_item *event; + gfp_t alloc_flag = GFP_KERNEL; + void *data; + u32 datalen; + + /* get event info */ + code = get_unaligned_be32(&event_packet->msg.event_type); + datalen = get_unaligned_be32(&event_packet->msg.datalen); + *ifidx = event_packet->msg.ifidx; + data = &event_packet[1]; + + if (code >= BRCMF_E_LAST) + return; + + if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + return; + + if (in_interrupt()) + alloc_flag = GFP_ATOMIC; + + event = kzalloc(sizeof(*event) + datalen, alloc_flag); + if (!event) + return; + + event->code = code; + event->ifidx = *ifidx; + + /* use memcpy to get aligned event message */ + memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); + memcpy(event->data, data, datalen); + memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); + + brcmf_fweh_queue_event(fweh, event); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h new file mode 100644 index 0000000..b39246a --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2012 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 FWEH_H_ +#define FWEH_H_ + +#include <asm/unaligned.h> +#include <linux/skbuff.h> +#include <linux/if_ether.h> +#include <linux/if.h> + +/* formward declarations */ +struct brcmf_pub; +struct brcmf_if; +struct brcmf_cfg80211_info; +struct brcmf_event; + +/* firmware event codes sent by the dongle */ +enum brcmf_fweh_event_code { + BRCMF_E_SET_SSID = 0, + BRCMF_E_JOIN = 1, + BRCMF_E_START = 2, + BRCMF_E_AUTH = 3, + BRCMF_E_AUTH_IND = 4, + BRCMF_E_DEAUTH = 5, + BRCMF_E_DEAUTH_IND = 6, + BRCMF_E_ASSOC = 7, + BRCMF_E_ASSOC_IND = 8, + BRCMF_E_REASSOC = 9, + BRCMF_E_REASSOC_IND = 10, + BRCMF_E_DISASSOC = 11, + BRCMF_E_DISASSOC_IND = 12, + BRCMF_E_QUIET_START = 13, + BRCMF_E_QUIET_END = 14, + BRCMF_E_BEACON_RX = 15, + BRCMF_E_LINK = 16, + BRCMF_E_MIC_ERROR = 17, + BRCMF_E_NDIS_LINK = 18, + BRCMF_E_ROAM = 19, + BRCMF_E_TXFAIL = 20, + BRCMF_E_PMKID_CACHE = 21, + BRCMF_E_RETROGRADE_TSF = 22, + BRCMF_E_PRUNE = 23, + BRCMF_E_AUTOAUTH = 24, + BRCMF_E_EAPOL_MSG = 25, + BRCMF_E_SCAN_COMPLETE = 26, + BRCMF_E_ADDTS_IND = 27, + BRCMF_E_DELTS_IND = 28, + BRCMF_E_BCNSENT_IND = 29, + BRCMF_E_BCNRX_MSG = 30, + BRCMF_E_BCNLOST_MSG = 31, + BRCMF_E_ROAM_PREP = 32, + BRCMF_E_PFN_NET_FOUND = 33, + BRCMF_E_PFN_NET_LOST = 34, + BRCMF_E_RESET_COMPLETE = 35, + BRCMF_E_JOIN_START = 36, + BRCMF_E_ROAM_START = 37, + BRCMF_E_ASSOC_START = 38, + BRCMF_E_IBSS_ASSOC = 39, + BRCMF_E_RADIO = 40, + BRCMF_E_PSM_WATCHDOG = 41, + BRCMF_E_PROBREQ_MSG = 44, + BRCMF_E_SCAN_CONFIRM_IND = 45, + BRCMF_E_PSK_SUP = 46, + BRCMF_E_COUNTRY_CODE_CHANGED = 47, + BRCMF_E_EXCEEDED_MEDIUM_TIME = 48, + BRCMF_E_ICV_ERROR = 49, + BRCMF_E_UNICAST_DECODE_ERROR = 50, + BRCMF_E_MULTICAST_DECODE_ERROR = 51, + BRCMF_E_TRACE = 52, + BRCMF_E_IF = 54, + BRCMF_E_RSSI = 56, + BRCMF_E_PFN_SCAN_COMPLETE = 57, + BRCMF_E_EXTLOG_MSG = 58, + BRCMF_E_ACTION_FRAME = 59, + BRCMF_E_ACTION_FRAME_COMPLETE = 60, + BRCMF_E_PRE_ASSOC_IND = 61, + BRCMF_E_PRE_REASSOC_IND = 62, + BRCMF_E_CHANNEL_ADOPTED = 63, + BRCMF_E_AP_STARTED = 64, + BRCMF_E_DFS_AP_STOP = 65, + BRCMF_E_DFS_AP_RESUME = 66, + BRCMF_E_ESCAN_RESULT = 69, + BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE = 70, + BRCMF_E_DCS_REQUEST = 73, + BRCMF_E_FIFO_CREDIT_MAP = 74, + BRCMF_E_LAST +}; + +/* flags field values in struct brcmf_event_msg */ +#define BRCMF_EVENT_MSG_LINK 0x01 +#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 +#define BRCMF_EVENT_MSG_GROUP 0x04 + +/** + * definitions for event packet validation. + */ +#define BRCMF_EVENT_OUI_OFFSET 19 +#define BRCM_OUI "\x00\x10\x18" +#define DOT11_OUI_LEN 3 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 + + +/** + * struct brcmf_event_msg - firmware event message. + * + * @version: version information. + * @flags: event flags. + * @event_code: firmware event code. + * @status: status information. + * @reason: reason code. + * @auth_type: authentication type. + * @datalen: lenght of event data buffer. + * @addr: ether address. + * @ifname: interface name. + * @ifidx: interface index. + * @bsscfgidx: bsscfg index. + */ +struct brcmf_event_msg { + u16 version; + u16 flags; + u32 event_code; + u32 status; + u32 reason; + s32 auth_type; + u32 datalen; + u8 addr[ETH_ALEN]; + char ifname[IFNAMSIZ]; + u8 ifidx; + u8 bsscfgidx; +}; + +typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data); + +/** + * struct brcmf_fweh_info - firmware event handling information. + * + * @event_work: event worker. + * @evt_q_lock: lock for event queue protection. + * @event_q: event queue. + * @evt_handler: registered event handlers. + */ +struct brcmf_fweh_info { + struct work_struct event_work; + struct spinlock evt_q_lock; + struct list_head event_q; + int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data); +}; + +void brcmf_fweh_attach(struct brcmf_pub *drvr); +void brcmf_fweh_detach(struct brcmf_pub *drvr); +int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, + int (*handler)(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data)); +void brcmf_fweh_unregister(struct brcmf_pub *drvr, + enum brcmf_fweh_event_code code); +int brcmf_fweh_activate_events(struct brcmf_if *ifp); +void brcmf_fweh_process_event(struct brcmf_pub *drvr, + struct brcmf_event *event_packet, u8 *ifidx); + +static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr, + struct sk_buff *skb, u8 *ifidx) +{ + struct brcmf_event *event_packet; + u8 *data; + u16 usr_stype; + + /* only process events when protocol matches */ + if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL)) + return; + + /* check for BRCM oui match */ + event_packet = (struct brcmf_event *)skb_mac_header(skb); + data = (u8 *)event_packet; + data += BRCMF_EVENT_OUI_OFFSET; + if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN)) + return; + + /* final match on usr_subtype */ + data += DOT11_OUI_LEN; + usr_stype = get_unaligned_be16(data); + if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT) + return; + + brcmf_fweh_process_event(drvr, event_packet, ifidx); +} + +#endif /* FWEH_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 4b272c3..51a1450 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/netdevice.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> #include "dhd.h" @@ -29,13 +28,16 @@ #include "fwil.h" +#define MAX_HEX_DUMP_LEN 64 + + static s32 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) { struct brcmf_pub *drvr = ifp->drvr; s32 err; - if (drvr->bus_if->state == BRCMF_BUS_DOWN) { + if (drvr->bus_if->state != BRCMF_BUS_DATA) { brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); return -EIO; } @@ -64,7 +66,8 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) mutex_lock(&ifp->drvr->proto_block); brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); err = brcmf_fil_cmd_data(ifp, cmd, data, len, true); mutex_unlock(&ifp->drvr->proto_block); @@ -81,7 +84,8 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); mutex_unlock(&ifp->drvr->proto_block); @@ -147,7 +151,8 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, mutex_lock(&drvr->proto_block); brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf, sizeof(drvr->proto_buf)); @@ -186,7 +191,8 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, } brcmf_dbg(FIL, "name=%s, len=%d\n", name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); mutex_unlock(&drvr->proto_block); return err; @@ -268,7 +274,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, mutex_lock(&drvr->proto_block); brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len, drvr->proto_buf, sizeof(drvr->proto_buf)); @@ -294,7 +301,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, mutex_lock(&drvr->proto_block); - buflen = brcmf_create_bsscfg(ifp->bssidx, name, NULL, len, + buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len, drvr->proto_buf, sizeof(drvr->proto_buf)); if (buflen) { err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf, @@ -306,7 +313,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, brcmf_dbg(ERROR, "Creating bsscfg failed\n"); } brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len); - brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data"); + brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, + min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); mutex_unlock(&drvr->proto_block); return err; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 484a6e4..39a5baa 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -14,24 +14,12 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/kthread.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/uaccess.h> #include <linux/firmware.h> #include <linux/usb.h> #include <linux/vmalloc.h> -#include <net/cfg80211.h> -#include <defs.h> #include <brcmu_utils.h> #include <brcmu_wifi.h> #include <dhd_bus.h> @@ -42,13 +30,11 @@ #define IOCTL_RESP_TIMEOUT 2000 -#define BRCMF_USB_DLIMAGE_SPINWAIT 100 /* in unit of ms */ -#define BRCMF_USB_DLIMAGE_LIMIT 500 /* spinwait limit (ms) */ +#define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */ +#define BRCMF_USB_RESET_GETVER_LOOP_CNT 10 #define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */ -#define BRCMF_USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */ - #define BRCMF_USB_NRXQ 50 #define BRCMF_USB_NTXQ 50 @@ -69,16 +55,6 @@ #define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin" #define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" -enum usbdev_suspend_state { - USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow - suspend */ - USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be - * suspended. Wating PM to - * suspend the device - */ - USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */ -}; - struct brcmf_usb_image { struct list_head list; s8 *fwname; @@ -99,10 +75,8 @@ struct brcmf_usbdev_info { struct list_head rx_postq; struct list_head tx_freeq; struct list_head tx_postq; - enum usbdev_suspend_state suspend_state; uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; - bool activity; int rx_low_watermark; int tx_low_watermark; int tx_high_watermark; @@ -170,6 +144,7 @@ static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo) static void brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status) { + brcmf_dbg(USB, "Enter, status=%d\n", status); if (unlikely(devinfo == NULL)) return; @@ -197,6 +172,7 @@ brcmf_usb_ctlread_complete(struct urb *urb) struct brcmf_usbdev_info *devinfo = (struct brcmf_usbdev_info *)urb->context; + brcmf_dbg(USB, "Enter\n"); devinfo->ctl_urb_actual_length = urb->actual_length; brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ, urb->status); @@ -208,33 +184,22 @@ brcmf_usb_ctlwrite_complete(struct urb *urb) struct brcmf_usbdev_info *devinfo = (struct brcmf_usbdev_info *)urb->context; + brcmf_dbg(USB, "Enter\n"); brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE, urb->status); } -static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state) -{ - return 0; -} - static int brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) { int ret; u16 size; + brcmf_dbg(USB, "Enter\n"); if (devinfo == NULL || buf == NULL || len == 0 || devinfo->ctl_urb == NULL) return -EINVAL; - /* If the USB/HSIC bus in sleep state, wake it up */ - if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) - if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) { - brcmf_dbg(ERROR, "Could not Resume the bus!\n"); - return -EIO; - } - - devinfo->activity = true; size = len; devinfo->ctl_write.wLength = cpu_to_le16p(&size); devinfo->ctl_urb->transfer_buffer_length = size; @@ -262,6 +227,7 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) int ret; u16 size; + brcmf_dbg(USB, "Enter\n"); if ((devinfo == NULL) || (buf == NULL) || (len == 0) || (devinfo->ctl_urb == NULL)) return -EINVAL; @@ -295,10 +261,9 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) int timeout = 0; struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - /* TODO: handle suspend/resume */ + brcmf_dbg(USB, "Enter\n"); + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) return -EIO; - } if (test_and_set_bit(0, &devinfo->ctl_op)) return -EIO; @@ -325,10 +290,10 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) int timeout = 0; struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - /* TODO: handle suspend/resume */ + brcmf_dbg(USB, "Enter\n"); + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) return -EIO; - } + if (test_and_set_bit(0, &devinfo->ctl_op)) return -EIO; @@ -453,6 +418,8 @@ static void brcmf_usb_tx_complete(struct urb *urb) struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; struct brcmf_usbdev_info *devinfo = req->devinfo; + brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, + req->skb); brcmf_usb_del_fromq(devinfo, req); if (urb->status == 0) devinfo->bus_pub.bus->dstats.tx_packets++; @@ -478,6 +445,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) struct sk_buff *skb; int ifidx = 0; + brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); brcmf_usb_del_fromq(devinfo, req); skb = req->skb; req->skb = NULL; @@ -491,7 +459,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) return; } - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) { + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { skb_put(skb, urb->actual_length); if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { brcmf_dbg(ERROR, "rx protocol error\n"); @@ -544,8 +512,8 @@ static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo) { struct brcmf_usbreq *req; - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - brcmf_dbg(ERROR, "bus is not up\n"); + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) { + brcmf_dbg(ERROR, "bus is not up=%d\n", devinfo->bus_pub.state); return; } while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL) @@ -558,29 +526,24 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state) struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus; int old_state; + brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n", + devinfo->bus_pub.state, state); if (devinfo->bus_pub.state == state) return; old_state = devinfo->bus_pub.state; - brcmf_dbg(TRACE, "dbus state change from %d to to %d\n", - old_state, state); - - /* Don't update state if it's PnP firmware re-download */ - if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */ - devinfo->bus_pub.state = state; - - if ((old_state == BCMFMAC_USB_STATE_SLEEP) - && (state == BCMFMAC_USB_STATE_UP)) { - brcmf_usb_rx_fill_all(devinfo); - } + devinfo->bus_pub.state = state; /* update state of upper layer */ - if (state == BCMFMAC_USB_STATE_DOWN) { - brcmf_dbg(INFO, "DBUS is down\n"); + if (state == BRCMFMAC_USB_STATE_DOWN) { + brcmf_dbg(USB, "DBUS is down\n"); bcmf_bus->state = BRCMF_BUS_DOWN; + } else if (state == BRCMFMAC_USB_STATE_UP) { + brcmf_dbg(USB, "DBUS is up\n"); + bcmf_bus->state = BRCMF_BUS_DATA; } else { - brcmf_dbg(INFO, "DBUS current state=%d\n", state); + brcmf_dbg(USB, "DBUS current state=%d\n", state); } } @@ -589,30 +552,32 @@ brcmf_usb_intr_complete(struct urb *urb) { struct brcmf_usbdev_info *devinfo = (struct brcmf_usbdev_info *)urb->context; - bool killed; + int err; + + brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); if (devinfo == NULL) return; if (unlikely(urb->status)) { - if (devinfo->suspend_state == - USBOS_SUSPEND_STATE_SUSPEND_PENDING) - killed = true; - - if ((urb->status == -ENOENT && (!killed)) - || urb->status == -ESHUTDOWN || - urb->status == -ENODEV) { - brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN); + if (urb->status == -ENOENT || + urb->status == -ESHUTDOWN || + urb->status == -ENODEV) { + brcmf_usb_state_change(devinfo, + BRCMFMAC_USB_STATE_DOWN); } } - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) { + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) { brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n"); return; } - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) - usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { + err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); + if (err) + brcmf_dbg(ERROR, "usb_submit_urb, err=%d\n", err); + } } static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) @@ -621,10 +586,9 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) struct brcmf_usbreq *req; int ret; - if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { - /* TODO: handle suspend/resume */ + brcmf_dbg(USB, "Enter, skb=%p\n", skb); + if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) return -EIO; - } req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq, &devinfo->tx_freecount); @@ -664,25 +628,16 @@ static int brcmf_usb_up(struct device *dev) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); u16 ifnum; + int ret; - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) + brcmf_dbg(USB, "Enter\n"); + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) return 0; - /* If the USB/HSIC bus in sleep state, wake it up */ - if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) { - if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) { - brcmf_dbg(ERROR, "Could not Resume the bus!\n"); - return -EIO; - } - } - devinfo->activity = true; - /* Success, indicate devinfo is fully up */ - brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP); + brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP); if (devinfo->intr_urb) { - int ret; - usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev, devinfo->intr_pipe, &devinfo->intr, @@ -727,14 +682,14 @@ static void brcmf_usb_down(struct device *dev) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + brcmf_dbg(USB, "Enter\n"); if (devinfo == NULL) return; - brcmf_dbg(TRACE, "enter\n"); - if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) return; - brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN); + brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN); if (devinfo->intr_urb) usb_kill_urb(devinfo->intr_urb); @@ -808,27 +763,25 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo) struct bootrom_id_le id; u32 chipid, chiprev; - brcmf_dbg(TRACE, "enter\n"); + brcmf_dbg(USB, "Enter\n"); if (devinfo == NULL) return false; /* Check if firmware downloaded already by querying runtime ID */ id.chip = cpu_to_le32(0xDEAD); - brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, - sizeof(struct bootrom_id_le)); + brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id)); chipid = le32_to_cpu(id.chip); chiprev = le32_to_cpu(id.chiprev); if ((chipid & 0x4300) == 0x4300) - brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev); + brcmf_dbg(USB, "chip %x rev 0x%x\n", chipid, chiprev); else - brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev); + brcmf_dbg(USB, "chip %d rev 0x%x\n", chipid, chiprev); if (chipid == BRCMF_POSTBOOT_ID) { - brcmf_dbg(INFO, "firmware already downloaded\n"); - brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, - sizeof(struct bootrom_id_le)); + brcmf_dbg(USB, "firmware already downloaded\n"); + brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id)); return false; } else { devinfo->bus_pub.devid = chipid; @@ -841,38 +794,29 @@ static int brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo) { struct bootrom_id_le id; - u16 wait = 0, wait_time; + u32 loop_cnt; - brcmf_dbg(TRACE, "enter\n"); - - if (devinfo == NULL) - return -EINVAL; + brcmf_dbg(USB, "Enter\n"); - /* Give dongle chance to boot */ - wait_time = BRCMF_USB_DLIMAGE_SPINWAIT; - while (wait < BRCMF_USB_DLIMAGE_LIMIT) { - mdelay(wait_time); - wait += wait_time; + loop_cnt = 0; + do { + mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT); + loop_cnt++; id.chip = cpu_to_le32(0xDEAD); /* Get the ID */ - brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, - sizeof(struct bootrom_id_le)); + brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id)); if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) break; - } + } while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT); if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) { - brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n", - wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev)); - - brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, - sizeof(struct bootrom_id_le)); + brcmf_dbg(USB, "postboot chip 0x%x/rev 0x%x\n", + le32_to_cpu(id.chip), le32_to_cpu(id.chiprev)); - /* XXX this wait may not be necessary */ - mdelay(BRCMF_USB_RESETCFG_SPINWAIT); + brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id)); return 0; } else { brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n", - wait); + BRCMF_USB_RESET_GETVER_SPINWAIT * loop_cnt); return -EINVAL; } } @@ -911,7 +855,8 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) struct rdl_state_le state; u32 rdlstate, rdlbytes; int err = 0; - brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen); + + brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen); bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC); if (bulkchunk == NULL) { @@ -986,7 +931,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) fail: kfree(bulkchunk); - brcmf_dbg(TRACE, "err=%d\n", err); + brcmf_dbg(USB, "Exit, err=%d\n", err); return err; } @@ -994,7 +939,7 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len) { int err; - brcmf_dbg(TRACE, "enter\n"); + brcmf_dbg(USB, "Enter\n"); if (devinfo == NULL) return -EINVAL; @@ -1004,10 +949,10 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len) err = brcmf_usb_dl_writeimage(devinfo, fw, len); if (err == 0) - devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE; + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_DONE; else - devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING; - brcmf_dbg(TRACE, "exit: err=%d\n", err); + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_FAIL; + brcmf_dbg(USB, "Exit, err=%d\n", err); return err; } @@ -1016,7 +961,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo) { struct rdl_state_le state; - brcmf_dbg(TRACE, "enter\n"); + brcmf_dbg(USB, "Enter\n"); if (!devinfo) return -EINVAL; @@ -1039,7 +984,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo) brcmf_dbg(ERROR, "Dongle not runnable\n"); return -EINVAL; } - brcmf_dbg(TRACE, "exit\n"); + brcmf_dbg(USB, "Exit\n"); return 0; } @@ -1066,7 +1011,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo) int devid, chiprev; int err; - brcmf_dbg(TRACE, "enter\n"); + brcmf_dbg(USB, "Enter\n"); if (devinfo == NULL) return -ENODEV; @@ -1094,7 +1039,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo) static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo) { - brcmf_dbg(TRACE, "devinfo %p\n", devinfo); + brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo); /* free the URBS */ brcmf_usb_free_q(&devinfo->rx_freeq, false); @@ -1129,6 +1074,7 @@ static int check_file(const u8 *headers) struct trx_header_le *trx; int actual_len = -1; + brcmf_dbg(USB, "Enter\n"); /* Extract trx header */ trx = (struct trx_header_le *) headers; if (trx->magic != cpu_to_le32(TRX_MAGIC)) @@ -1150,6 +1096,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) struct brcmf_usb_image *fw_image; int err; + brcmf_dbg(USB, "Enter\n"); switch (devinfo->bus_pub.devid) { case 43143: fwname = BRCMF_USB_43143_FW_NAME; @@ -1166,7 +1113,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) return -EINVAL; break; } - + brcmf_dbg(USB, "Loading FW %s\n", fwname); list_for_each_entry(fw_image, &fw_image_list, list) { if (fw_image->fwname == fwname) { devinfo->image = fw_image->image; @@ -1211,10 +1158,13 @@ static struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, int nrxq, int ntxq) { + brcmf_dbg(USB, "Enter\n"); + devinfo->bus_pub.nrxq = nrxq; devinfo->rx_low_watermark = nrxq / 2; devinfo->bus_pub.devinfo = devinfo; devinfo->bus_pub.ntxq = ntxq; + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DOWN; /* flow control when too many tx urbs posted */ devinfo->tx_low_watermark = ntxq / 4; @@ -1263,7 +1213,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, if (!brcmf_usb_dlneeded(devinfo)) return &devinfo->bus_pub; - brcmf_dbg(TRACE, "start fw downloading\n"); + brcmf_dbg(USB, "Start fw downloading\n"); if (brcmf_usb_get_fw(devinfo)) goto error; @@ -1278,14 +1228,14 @@ error: return NULL; } -static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, - const char *desc, u32 bustype, u32 hdrlen) +static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) { struct brcmf_bus *bus = NULL; struct brcmf_usbdev *bus_pub = NULL; int ret; struct device *dev = devinfo->dev; + brcmf_dbg(USB, "Enter\n"); bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ); if (!bus_pub) return -ENODEV; @@ -1302,14 +1252,13 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, bus->brcmf_bus_stop = brcmf_usb_down; bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt; bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt; - bus->type = bustype; bus->bus_priv.usb = bus_pub; dev_set_drvdata(dev, bus); /* Attach to the common driver interface */ - ret = brcmf_attach(hdrlen, dev); + ret = brcmf_attach(0, dev); if (ret) { - brcmf_dbg(ERROR, "dhd_attach failed\n"); + brcmf_dbg(ERROR, "brcmf_attach failed\n"); goto fail; } @@ -1333,7 +1282,7 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo) { if (!devinfo) return; - brcmf_dbg(TRACE, "enter: bus_pub %p\n", devinfo); + brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo); brcmf_detach(devinfo->dev); kfree(devinfo->bus_pub.bus); @@ -1351,7 +1300,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) u8 endpoint_num; struct brcmf_usbdev_info *devinfo; - brcmf_dbg(TRACE, "enter\n"); + brcmf_dbg(USB, "Enter\n"); devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC); if (devinfo == NULL) @@ -1452,11 +1401,11 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) devinfo->interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval; if (usb->speed == USB_SPEED_HIGH) - brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n"); + brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n"); else - brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n"); + brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n"); - ret = brcmf_usb_probe_cb(devinfo, "", USB_BUS, 0); + ret = brcmf_usb_probe_cb(devinfo); if (ret) goto fail; @@ -1476,40 +1425,55 @@ brcmf_usb_disconnect(struct usb_interface *intf) { struct brcmf_usbdev_info *devinfo; - brcmf_dbg(TRACE, "enter\n"); + brcmf_dbg(USB, "Enter\n"); devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf); brcmf_usb_disconnect_cb(devinfo); kfree(devinfo); + brcmf_dbg(USB, "Exit\n"); } /* - * only need to signal the bus being down and update the suspend state. + * only need to signal the bus being down and update the state. */ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state) { struct usb_device *usb = interface_to_usbdev(intf); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); - brcmf_dbg(TRACE, "enter\n"); - devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN; - devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; + brcmf_dbg(USB, "Enter\n"); + devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP; + brcmf_detach(&usb->dev); return 0; } /* - * mark suspend state active and crank up the bus. + * (re-) start the bus. */ static int brcmf_usb_resume(struct usb_interface *intf) { struct usb_device *usb = interface_to_usbdev(intf); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); - brcmf_dbg(TRACE, "enter\n"); - devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; - brcmf_bus_start(&usb->dev); + brcmf_dbg(USB, "Enter\n"); + if (!brcmf_attach(0, devinfo->dev)) + return brcmf_bus_start(&usb->dev); + return 0; } +static int brcmf_usb_reset_resume(struct usb_interface *intf) +{ + struct usb_device *usb = interface_to_usbdev(intf); + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); + + brcmf_dbg(USB, "Enter\n"); + + if (!brcmf_usb_fw_download(devinfo)) + return brcmf_usb_resume(intf); + + return -EIO; +} + #define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c #define BRCMF_USB_DEVICE_ID_43143 0xbd1e #define BRCMF_USB_DEVICE_ID_43236 0xbd17 @@ -1529,7 +1493,6 @@ MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME); -/* TODO: suspend and resume entries */ static struct usb_driver brcmf_usbdrvr = { .name = KBUILD_MODNAME, .probe = brcmf_usb_probe, @@ -1537,6 +1500,7 @@ static struct usb_driver brcmf_usbdrvr = { .id_table = brcmf_usb_devid_table, .suspend = brcmf_usb_suspend, .resume = brcmf_usb_resume, + .reset_resume = brcmf_usb_reset_resume, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, }; @@ -1554,12 +1518,14 @@ static void brcmf_release_fw(struct list_head *q) void brcmf_usb_exit(void) { + brcmf_dbg(USB, "Enter\n"); usb_deregister(&brcmf_usbdrvr); brcmf_release_fw(&fw_image_list); } void brcmf_usb_init(void) { + brcmf_dbg(USB, "Enter\n"); INIT_LIST_HEAD(&fw_image_list); usb_register(&brcmf_usbdrvr); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h index acfa5e8..f483a8c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.h @@ -17,19 +17,11 @@ #define BRCMFMAC_USB_H enum brcmf_usb_state { - BCMFMAC_USB_STATE_DL_PENDING, - BCMFMAC_USB_STATE_DL_DONE, - BCMFMAC_USB_STATE_UP, - BCMFMAC_USB_STATE_DOWN, - BCMFMAC_USB_STATE_PNP_FWDL, - BCMFMAC_USB_STATE_DISCONNECT, - BCMFMAC_USB_STATE_SLEEP -}; - -enum brcmf_usb_pnp_state { - BCMFMAC_USB_PNP_DISCONNECT, - BCMFMAC_USB_PNP_SLEEP, - BCMFMAC_USB_PNP_RESUME, + BRCMFMAC_USB_STATE_DOWN, + BRCMFMAC_USB_STATE_DL_FAIL, + BRCMFMAC_USB_STATE_DL_DONE, + BRCMFMAC_USB_STATE_UP, + BRCMFMAC_USB_STATE_SLEEP }; struct brcmf_stats { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 6d55424..2044fdb5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -19,14 +19,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #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 <net/netlink.h> @@ -486,13 +479,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, if (ap) { set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); - if (!cfg->ap_info) - cfg->ap_info = kzalloc(sizeof(*cfg->ap_info), - GFP_KERNEL); - if (!cfg->ap_info) { - err = -ENOMEM; - goto done; - } WL_INFO("IF Type = AP\n"); } else { err = brcmf_fil_cmd_int_set(netdev_priv(ndev), @@ -529,185 +515,6 @@ static void brcmf_set_mpc(struct net_device *ndev, int mpc) } } -static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le, - struct brcmf_ssid *ssid) -{ - memset(params_le->bssid, 0xFF, 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) { - params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len); - memcpy(¶ms_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len); - } -} - -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); - - brcmf_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_fil_iovar_data_set(netdev_priv(iscan->ndev), "iscan", - params, params_size); - 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_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - struct net_device *ndev = cfg_to_ndev(cfg); - struct brcmf_ssid ssid; - u32 passive_scan; - s32 err = 0; - - /* Broadcast scan by default */ - memset(&ssid, 0, sizeof(ssid)); - - iscan->state = WL_ISCAN_STATE_SCANING; - - passive_scan = cfg->active_scan ? 0 : 1; - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), - BRCMF_C_SET_PASSIVE_SCAN, passive_scan); - if (err) { - WL_ERR("error (%d)\n", err); - return err; - } - brcmf_set_mpc(ndev, 0); - cfg->iscan_kickstart = true; - err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); - if (err) { - brcmf_set_mpc(ndev, 1); - cfg->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_iscan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); - struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; - u32 passive_scan; - bool iscan_req; - bool spec_scan; - s32 err = 0; - u32 SSID_len; - - if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status); - return -EAGAIN; - } - if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) { - WL_ERR("Scanning being aborted: status (%lu)\n", - cfg->scan_status); - return -EAGAIN; - } - if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { - WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state); - return -EAGAIN; - } - - iscan_req = false; - spec_scan = false; - if (request) { - /* scan bss */ - ssids = request->ssids; - if (cfg->iscan_on && (!ssids || !ssids->ssid_len)) - iscan_req = true; - } else { - /* scan in ibss */ - /* we don't do iscan in ibss */ - ssids = this_ssid; - } - - cfg->scan_request = request; - set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); - if (iscan_req) { - err = brcmf_do_iscan(cfg); - 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->active_scan ? 0 : 1; - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN, - passive_scan); - if (err) { - WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); - goto scan_out; - } - brcmf_set_mpc(ndev, 0); - err = brcmf_fil_cmd_data_set(ifp, 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(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); - cfg->scan_request = NULL; - return err; -} - static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, struct cfg80211_scan_request *request) { @@ -931,7 +738,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); struct cfg80211_ssid *ssids; - struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int; + struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int; u32 passive_scan; bool escan_req; bool spec_scan; @@ -973,9 +780,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); if (escan_req) { err = brcmf_do_escan(cfg, wiphy, ndev, request); - if (!err) - return err; - else + if (err) goto scan_out; } else { WL_SCAN("ssid \"%s\", ssid_len (%d)\n", @@ -1027,7 +832,6 @@ static s32 brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct net_device *ndev = request->wdev->netdev; - struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev); s32 err = 0; WL_TRACE("Enter\n"); @@ -1036,10 +840,7 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) struct brcmf_cfg80211_vif, wdev))) return -EIO; - if (cfg->iscan_on) - err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL); - else if (cfg->escan_on) - err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL); + err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL); if (err) WL_ERR("scan error (%d)\n", err); @@ -1075,7 +876,7 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) 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); + u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL); err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry); if (err) { @@ -1212,8 +1013,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, else WL_CONN("No BSSID specified\n"); - if (params->channel) - WL_CONN("channel: %d\n", params->channel->center_freq); + if (params->chandef.chan) + WL_CONN("channel: %d\n", params->chandef.chan->center_freq); else WL_CONN("no channel specified\n"); @@ -1258,7 +1059,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, else bcnprd = 100; - err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd); if (err) { WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); goto done; @@ -1286,12 +1087,12 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, } /* Channel */ - if (params->channel) { + if (params->chandef.chan) { u32 target_channel; cfg->channel = ieee80211_frequency_to_channel( - params->channel->center_freq); + params->chandef.chan->center_freq); if (params->channel_fixed) { /* adding chanspec */ brcmf_ch_to_chanspec(cfg->channel, @@ -1300,7 +1101,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, /* set channel for starter */ target_channel = cfg->channel; - err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL, + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL, target_channel); if (err) { WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); @@ -1721,7 +1522,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, } static s32 -brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, +brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, s32 mbm) { @@ -1770,7 +1571,9 @@ done: return err; } -static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + s32 *dbm) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); @@ -2014,6 +1817,12 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; + if (key_idx >= DOT11_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + WL_ERR("invalid key index (%d)\n", key_idx); + return -EINVAL; + } + memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -2024,15 +1833,6 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, /* 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; - } WL_TRACE("Exit\n"); return err; @@ -2239,7 +2039,7 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, /* addr param is always NULL. ignore it */ /* Get current rateset */ - err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET, + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET, &rateset_le, sizeof(rateset_le)); if (err) { WL_ERR("could not get current rateset (%d)\n", err); @@ -2354,13 +2154,14 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg) int i; bss_list = cfg->bss_list; - if (bss_list->version != BRCMF_BSS_INFO_VERSION) { + if (bss_list->count != 0 && + 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++) { + for (i = 0; i < bss_list->count; i++) { bi = next_bss_le(bss_list, bi); err = brcmf_inform_single_bss(cfg, bi); if (err) @@ -2582,33 +2383,10 @@ update_bss_info_out: static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); struct escan_info *escan = &cfg->escan_info; - struct brcmf_ssid ssid; set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); - if (cfg->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); - - if (cfg->scan_request) { - /* Indidate scan abort to cfg80211 layer */ - WL_INFO("Terminating scan in progress\n"); - cfg80211_scan_done(cfg->scan_request, true); - cfg->scan_request = NULL; - } - } - if (cfg->escan_on && cfg->scan_request) { + if (cfg->scan_request) { escan->escan_state = WL_ESCAN_STATE_IDLE; brcmf_notify_escan_complete(cfg, escan->ndev, true, true); } @@ -2616,198 +2394,6 @@ static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); } -static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, - bool aborted) -{ - struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan); - struct net_device *ndev = cfg_to_ndev(cfg); - - if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - WL_ERR("Scan complete while device not scanning\n"); - return; - } - if (cfg->scan_request) { - WL_SCAN("ISCAN Completed scan: %s\n", - aborted ? "Aborted" : "Done"); - cfg80211_scan_done(cfg->scan_request, aborted); - brcmf_set_mpc(ndev, 1); - cfg->scan_request = NULL; - } - cfg->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_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_le->buflen = cpu_to_le32(sizeof(iscan->scan_buf)); - results_le->version = 0; - results_le->count = 0; - - err = brcmf_fil_iovar_data_get(netdev_priv(iscan->ndev), "iscanresults", - iscan->scan_buf, - sizeof(iscan->scan_buf)); - 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_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - brcmf_inform_bss(cfg); - brcmf_notify_iscan_complete(iscan, false); - - return err; -} - -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->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_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan; - s32 err = 0; - - brcmf_inform_bss(cfg); - 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_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->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_info *cfg = 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->bss_list)) { - status = BRCMF_SCAN_RESULTS_ABORTED; - WL_ERR("Abort iscan\n"); - } - - el->handler[status](cfg); -} - -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_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - - if (cfg->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_info *cfg) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg); - int err = 0; - - if (cfg->iscan_on) { - iscan->ndev = cfg_to_ndev(cfg); - 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); - if (!err) - iscan->data = cfg; - } - - return err; -} - static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) { struct brcmf_cfg80211_info *cfg = @@ -2825,8 +2411,7 @@ static void brcmf_escan_timeout(unsigned long data) if (cfg->scan_request) { WL_ERR("timer expired\n"); - if (cfg->escan_on) - schedule_work(&cfg->escan_timeout_work); + schedule_work(&cfg->escan_timeout_work); } } @@ -2863,10 +2448,11 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, } static s32 -brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct net_device *ndev = ifp->ndev; s32 status; s32 err = 0; struct brcmf_escan_result_le *escan_result_le; @@ -2877,13 +2463,11 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg, u32 i; bool aborted; - status = be32_to_cpu(e->status); + status = e->status; - if (!ndev || !cfg->escan_on || - !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n", - ndev, cfg->escan_on, - !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)); + if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + WL_ERR("scan not ready ndev %p drv_status %x\n", ndev, + !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)); return -EPERM; } @@ -2960,18 +2544,15 @@ exit: static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) { - - if (cfg->escan_on) { - cfg->el.handler[BRCMF_E_ESCAN_RESULT] = - brcmf_cfg80211_escan_handler; - cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - /* Init scan_timeout timer */ - init_timer(&cfg->escan_timeout); - cfg->escan_timeout.data = (unsigned long) cfg; - cfg->escan_timeout.function = brcmf_escan_timeout; - INIT_WORK(&cfg->escan_timeout_work, - brcmf_cfg80211_escan_timeout_worker); - } + brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT, + brcmf_cfg80211_escan_handler); + cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + /* Init scan_timeout timer */ + init_timer(&cfg->escan_timeout); + cfg->escan_timeout.data = (unsigned long) cfg; + cfg->escan_timeout.function = brcmf_escan_timeout; + INIT_WORK(&cfg->escan_timeout_work, + brcmf_cfg80211_escan_timeout_worker); } static __always_inline void brcmf_delay(u32 ms) @@ -2986,20 +2567,8 @@ static __always_inline void brcmf_delay(u32 ms) static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); - - /* - * Check for BRCMF_VIF_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 (check_vif_up(ifp->vif)) - brcmf_invoke_iscan(cfg); - - WL_TRACE("Exit\n"); return 0; } @@ -3198,10 +2767,11 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) * cfg80211_scan_request one out of the received PNO event. */ static s32 -brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_sched_scan_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct net_device *ndev = ifp->ndev; struct brcmf_pno_net_info_le *netinfo, *netinfo_start; struct cfg80211_scan_request *request = NULL; struct cfg80211_ssid *ssid = NULL; @@ -3216,7 +2786,7 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg, WL_SCAN("Enter\n"); - if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) { + if (e->event_code == BRCMF_E_PFN_NET_LOST) { WL_SCAN("PFN NET LOST event. Do Nothing\n"); return 0; } @@ -3309,7 +2879,6 @@ out_err: return err; } -#ifndef CONFIG_BRCMISCAN static int brcmf_dev_pno_clean(struct net_device *ndev) { int ret; @@ -3446,7 +3015,6 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, brcmf_notify_escan_complete(cfg, ndev, true, true); return 0; } -#endif /* CONFIG_BRCMISCAN */ #ifdef CONFIG_NL80211_TESTMODE static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) @@ -3512,7 +3080,7 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie) static s32 brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, - bool is_rsn_ie, s32 bssidx) + bool is_rsn_ie) { struct brcmf_if *ifp = netdev_priv(ndev); u32 auth = 0; /* d11 open authentication */ @@ -3689,7 +3257,7 @@ exit: } static s32 -brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len, +brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, struct parsed_vndr_ies *vndr_ies) { s32 err = 0; @@ -3768,13 +3336,12 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) return ie_len + VNDR_IE_HDR_SIZE; } -static s32 -brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, s32 pktflag, - u8 *vndr_ie_buf, u32 vndr_ie_len) +static +s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, + const u8 *vndr_ie_buf, u32 vndr_ie_len) { - struct brcmf_if *ifp = netdev_priv(ndev); - struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie; + struct brcmf_if *ifp; + struct vif_saved_ie *saved_ie; s32 err = 0; u8 *iovar_ie_buf; u8 *curr_ie_buf; @@ -3791,8 +3358,12 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg, u8 *ptr; int remained_buf_len; - WL_TRACE("bssidx %d, pktflag : 0x%02X\n", - brcmf_ndev_bssidx(ndev), pktflag); + if (!vif) + return -ENODEV; + ifp = vif->ifp; + saved_ie = &vif->saved_ie; + + WL_TRACE("bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag); iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!iovar_ie_buf) return -ENOMEM; @@ -3932,13 +3503,13 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_tlv *rsn_ie; struct brcmf_vs_tlv *wpa_ie; struct brcmf_join_params join_params; - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); s32 bssidx = 0; WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", - settings->channel_type, settings->beacon_interval, + cfg80211_get_chandef_type(&settings->chandef), + settings->beacon_interval, settings->dtim_period); - WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n", + WL_TRACE("ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n", settings->ssid, settings->ssid_len, settings->auth_type, settings->inactivity_timeout); @@ -3990,55 +3561,39 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, settings->beacon.tail_len); - kfree(cfg->ap_info->rsn_ie); - cfg->ap_info->rsn_ie = NULL; - kfree(cfg->ap_info->wpa_ie); - cfg->ap_info->wpa_ie = NULL; - if ((wpa_ie != NULL || rsn_ie != NULL)) { WL_TRACE("WPA(2) IE is found\n"); if (wpa_ie != NULL) { /* WPA IE */ - err = brcmf_configure_wpaie(ndev, wpa_ie, false, - bssidx); + err = brcmf_configure_wpaie(ndev, wpa_ie, false); if (err < 0) goto exit; - cfg->ap_info->wpa_ie = kmemdup(wpa_ie, - wpa_ie->len + - TLV_HDR_LEN, - GFP_KERNEL); } else { /* RSN IE */ err = brcmf_configure_wpaie(ndev, - (struct brcmf_vs_tlv *)rsn_ie, true, bssidx); + (struct brcmf_vs_tlv *)rsn_ie, true); if (err < 0) goto exit; - cfg->ap_info->rsn_ie = kmemdup(rsn_ie, - rsn_ie->len + - TLV_HDR_LEN, - GFP_KERNEL); } - cfg->ap_info->security_mode = true; } else { WL_TRACE("No WPA(2) IEs found\n"); brcmf_configure_opensecurity(ndev, bssidx); - cfg->ap_info->security_mode = false; } /* Set Beacon IEs to FW */ - err = brcmf_set_management_ie(cfg, ndev, - VNDR_IE_BEACON_FLAG, - (u8 *)settings->beacon.tail, - settings->beacon.tail_len); + err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), + VNDR_IE_BEACON_FLAG, + settings->beacon.tail, + settings->beacon.tail_len); if (err) WL_ERR("Set Beacon IE Failed\n"); else WL_TRACE("Applied Vndr IEs for Beacon\n"); /* Set Probe Response IEs to FW */ - err = brcmf_set_management_ie(cfg, ndev, - VNDR_IE_PRBRSP_FLAG, - (u8 *)settings->beacon.proberesp_ies, - settings->beacon.proberesp_ies_len); + err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), + VNDR_IE_PRBRSP_FLAG, + settings->beacon.proberesp_ies, + settings->beacon.proberesp_ies_len); if (err) WL_ERR("Set Probe Resp IE Failed\n"); else @@ -4169,11 +3724,8 @@ static struct cfg80211_ops wl_cfg80211_ops = { .start_ap = brcmf_cfg80211_start_ap, .stop_ap = brcmf_cfg80211_stop_ap, .del_station = brcmf_cfg80211_del_station, -#ifndef CONFIG_BRCMISCAN - /* scheduled scan need e-scan, which is mutual exclusive with i-scan */ .sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, -#endif #ifdef CONFIG_NL80211_TESTMODE .testmode_cmd = brcmf_cfg80211_testmode #endif @@ -4197,13 +3749,11 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode) static void brcmf_wiphy_pno_params(struct wiphy *wiphy) { -#ifndef CONFIG_BRCMISCAN /* scheduled scan settings */ wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -#endif } static struct wiphy *brcmf_setup_wiphy(struct device *phydev) @@ -4302,8 +3852,8 @@ static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { WL_CONN("Processing set ssid\n"); @@ -4317,8 +3867,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u16 flags = be16_to_cpu(e->flags); + u32 event = e->event_code; + u16 flags = e->flags; if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { WL_CONN("Processing link down\n"); @@ -4330,13 +3880,12 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e) { - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = 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"); + e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down"); return true; } @@ -4524,9 +4073,9 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, const struct brcmf_event_msg *e, void *data) { s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 reason = be32_to_cpu(e->reason); - u32 len = be32_to_cpu(e->datalen); + u32 event = e->event_code; + u32 reason = e->reason; + u32 len = e->datalen; static int generation; struct station_info sinfo; @@ -4558,11 +4107,11 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, } static s32 -brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_connect_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + struct net_device *ndev = ifp->ndev; struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; s32 err = 0; @@ -4610,31 +4159,29 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg, } static s32 -brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_roaming_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); + u32 event = e->event_code; + u32 status = e->status; if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) - brcmf_bss_roaming_done(cfg, ndev, e); + brcmf_bss_roaming_done(cfg, ifp->ndev, e); else - brcmf_bss_connect_done(cfg, ndev, e, true); + brcmf_bss_connect_done(cfg, ifp->ndev, e, true); } return err; } static s32 -brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, +brcmf_notify_mic_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - u16 flags = be16_to_cpu(e->flags); + u16 flags = e->flags; enum nl80211_key_type key_type; if (flags & BRCMF_EVENT_MSG_GROUP) @@ -4642,84 +4189,12 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg, else key_type = NL80211_KEYTYPE_PAIRWISE; - cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, + cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1, NULL, GFP_KERNEL); return 0; } -static s32 -brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - struct brcmf_if *ifp = netdev_priv(ndev); - 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->iscan_on && cfg->iscan_kickstart) { - WL_TRACE("Exit\n"); - return brcmf_wakeup_iscan(cfg_to_iscan(cfg)); - } - - if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - WL_ERR("Scan complete while device not scanning\n"); - scan_abort = true; - err = -EINVAL; - goto scan_done_out; - } - - err = brcmf_fil_cmd_data_get(ifp, 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->bss_list = cfg->scan_results; - bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list; - - memset(cfg->scan_results, 0, len); - bss_list_le->buflen = cpu_to_le32(len); - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS, - cfg->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->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); - cfg->scan_results->version = le32_to_cpu(bss_list_le->version); - cfg->scan_results->count = le32_to_cpu(bss_list_le->count); - - err = brcmf_inform_bss(cfg); - if (err) - scan_abort = true; - -scan_done_out: - if (cfg->scan_request) { - WL_SCAN("calling cfg80211_scan_done\n"); - cfg80211_scan_done(cfg->scan_request, scan_abort); - brcmf_set_mpc(ndev, 1); - cfg->scan_request = NULL; - } - - WL_TRACE("Exit\n"); - - return err; -} - static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { conf->mode = (u32)-1; @@ -4730,77 +4205,53 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) 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_DEAUTH_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status; - el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status; - el->handler[BRCMF_E_REASSOC_IND] = 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; - el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; +static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) +{ + brcmf_fweh_register(cfg->pub, BRCMF_E_LINK, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM, + brcmf_notify_roaming_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR, + brcmf_notify_mic_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID, + brcmf_notify_connect_status); + brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, + brcmf_notify_sched_scan_results); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) { - kfree(cfg->scan_results); - cfg->scan_results = NULL; - kfree(cfg->bss_info); - cfg->bss_info = NULL; kfree(cfg->conf); cfg->conf = NULL; - kfree(cfg->scan_req_int); - cfg->scan_req_int = NULL; kfree(cfg->escan_ioctl_buf); cfg->escan_ioctl_buf = NULL; - kfree(cfg->dcmd_buf); - cfg->dcmd_buf = NULL; kfree(cfg->extra_buf); cfg->extra_buf = NULL; - kfree(cfg->iscan); - cfg->iscan = NULL; kfree(cfg->pmk_list); cfg->pmk_list = NULL; - if (cfg->ap_info) { - kfree(cfg->ap_info->wpa_ie); - kfree(cfg->ap_info->rsn_ie); - kfree(cfg->ap_info); - cfg->ap_info = NULL; - } } static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) { - cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); - if (!cfg->scan_results) - goto init_priv_mem_out; cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL); if (!cfg->conf) goto init_priv_mem_out; - cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (!cfg->bss_info) - goto init_priv_mem_out; - cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int), - GFP_KERNEL); - if (!cfg->scan_req_int) - goto init_priv_mem_out; cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); if (!cfg->escan_ioctl_buf) goto init_priv_mem_out; - cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); - if (!cfg->dcmd_buf) - goto init_priv_mem_out; cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (!cfg->extra_buf) goto init_priv_mem_out; - cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL); - if (!cfg->iscan) - goto init_priv_mem_out; cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL); if (!cfg->pmk_list) goto init_priv_mem_out; @@ -4813,149 +4264,22 @@ init_priv_mem_out: return -ENOMEM; } -/* -* retrieve first queued event from head -*/ - -static struct brcmf_cfg80211_event_q *brcmf_deq_event( - struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_event_q *e = NULL; - - spin_lock_irq(&cfg->evt_q_lock); - if (!list_empty(&cfg->evt_q_list)) { - e = list_first_entry(&cfg->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - } - spin_unlock_irq(&cfg->evt_q_lock); - - return e; -} - -/* -* push event to tail of the queue -* -* remark: this function may not sleep as it is called in atomic context. -*/ - -static s32 -brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event, - const struct brcmf_event_msg *msg, void *data) -{ - struct brcmf_cfg80211_event_q *e; - s32 err = 0; - ulong flags; - u32 data_len; - u32 total_len; - - total_len = sizeof(struct brcmf_cfg80211_event_q); - if (data) - data_len = be32_to_cpu(msg->datalen); - else - data_len = 0; - total_len += data_len; - e = kzalloc(total_len, GFP_ATOMIC); - if (!e) - return -ENOMEM; - - e->etype = event; - memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); - if (data) - memcpy(&e->edata, data, data_len); - - spin_lock_irqsave(&cfg->evt_q_lock, flags); - list_add_tail(&e->evt_q_list, &cfg->evt_q_list); - spin_unlock_irqrestore(&cfg->evt_q_lock, flags); - - 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_info *cfg = - container_of(work, struct brcmf_cfg80211_info, - event_work); - struct brcmf_cfg80211_event_q *e; - - e = brcmf_deq_event(cfg); - if (unlikely(!e)) { - WL_ERR("event queue empty...\n"); - return; - } - - do { - WL_INFO("event type (%d)\n", e->etype); - if (cfg->el.handler[e->etype]) - cfg->el.handler[e->etype](cfg, - cfg_to_ndev(cfg), - &e->emsg, e->edata); - else - WL_INFO("Unknown Event (%d): ignoring\n", e->etype); - brcmf_put_event(e); - } while ((e = brcmf_deq_event(cfg))); - -} - -static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg) -{ - spin_lock_init(&cfg->evt_q_lock); - INIT_LIST_HEAD(&cfg->evt_q_list); -} - -static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg) -{ - struct brcmf_cfg80211_event_q *e; - - spin_lock_irq(&cfg->evt_q_lock); - while (!list_empty(&cfg->evt_q_list)) { - e = list_first_entry(&cfg->evt_q_list, - struct brcmf_cfg80211_event_q, evt_q_list); - list_del(&e->evt_q_list); - kfree(e); - } - spin_unlock_irq(&cfg->evt_q_lock); -} - static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) { s32 err = 0; cfg->scan_request = NULL; cfg->pwr_save = true; -#ifdef CONFIG_BRCMISCAN - cfg->iscan_on = true; /* iscan on & off switch. - we enable iscan per default */ - cfg->escan_on = false; /* escan on & off switch. - we disable escan per default */ -#else - cfg->iscan_on = false; /* iscan on & off switch. - we disable iscan per default */ - cfg->escan_on = true; /* escan on & off switch. - we enable escan per default */ -#endif cfg->roam_on = true; /* roam on & off switch. we enable roam per default */ - - cfg->iscan_kickstart = false; cfg->active_scan = true; /* we do active scan for specific scan per default */ cfg->dongle_up = false; /* dongle is not up yet */ - brcmf_init_eq(cfg); err = brcmf_init_priv_mem(cfg); if (err) return err; - INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler); - brcmf_init_eloop_handler(&cfg->el); + brcmf_register_event_handlers(cfg); mutex_init(&cfg->usr_sync); - err = brcmf_init_iscan(cfg); - if (err) - return err; brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); brcmf_link_down(cfg); @@ -4965,9 +4289,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) { - cancel_work_sync(&cfg->event_work); cfg->dongle_up = false; /* dongle down */ - brcmf_flush_eq(cfg); brcmf_link_down(cfg); brcmf_abort_scanning(cfg); brcmf_deinit_priv_mem(cfg); @@ -5029,66 +4351,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) } } -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_info *cfg = ndev_to_cfg(ndev); - - if (!brcmf_enq_event(cfg, event_type, e, data)) - schedule_work(&cfg->event_work); -} - -static s32 brcmf_dongle_eventmsg(struct net_device *ndev) -{ - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - s32 err = 0; - - WL_TRACE("Enter\n"); - - /* Setup event_msgs */ - err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); - if (err) { - WL_ERR("Get event_msgs error (%d)\n", err); - goto dongle_eventmsg_out; - } - - 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); - setbit(eventmask, BRCMF_E_ESCAN_RESULT); - setbit(eventmask, BRCMF_E_PFN_NET_FOUND); - - err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); - 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) { @@ -5190,7 +4452,7 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg) s8 phy; s32 err = 0; - err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST, + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST, &phy_list, sizeof(phy_list)); if (err) { WL_ERR("error (%d)\n", err); @@ -5228,10 +4490,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) 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->pwr_save ? PM_FAST : PM_OFF; err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM, power_mode); @@ -5262,26 +4520,18 @@ default_conf_out: } -static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) +static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp) { - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); - s32 err = 0; - set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state); + if (ifp->idx) + return 0; - err = brcmf_config_dongle(cfg); - if (err) - return err; - - brcmf_invoke_iscan(cfg); - - return err; + return brcmf_config_dongle(ifp->drvr->config); } -static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) +static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) { - struct net_device *ndev = cfg_to_ndev(cfg); - struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; /* * While going down, if associated with AP disassociate @@ -5306,23 +4556,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) return 0; } -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg) +s32 brcmf_cfg80211_up(struct net_device *ndev) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; mutex_lock(&cfg->usr_sync); - err = __brcmf_cfg80211_up(cfg); + err = __brcmf_cfg80211_up(ifp); mutex_unlock(&cfg->usr_sync); return err; } -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg) +s32 brcmf_cfg80211_down(struct net_device *ndev) { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err = 0; mutex_lock(&cfg->usr_sync); - err = __brcmf_cfg80211_down(cfg); + err = __brcmf_cfg80211_down(ifp); mutex_unlock(&cfg->usr_sync); return err; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 1dd96f1..e2ef851 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -84,31 +84,12 @@ do { \ #define WL_CONN(fmt, args...) #endif /* (defined DEBUG) */ -#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_NUM_SCAN_MAX 10 +#define WL_NUM_PMKIDS_MAX MAXPMKID #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_ASSOC_INFO_MAX 512 /* assoc related fil max buf */ +#define WL_EXTRA_BUF_MAX 2048 #define WL_ROAM_TRIGGER_LEVEL -75 #define WL_ROAM_DELTA 20 #define WL_BEACON_TIMEOUT 3 @@ -145,12 +126,6 @@ enum wl_mode { WL_MODE_AP }; -/* 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 */ @@ -162,17 +137,6 @@ struct brcmf_cfg80211_conf { struct ieee80211_channel channel; }; -/* forward declaration */ -struct brcmf_cfg80211_info; - -/* cfg80211 main event loop */ -struct brcmf_cfg80211_event_loop { - s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_info *cfg, - struct net_device *ndev, - const struct brcmf_event_msg *e, - void *data); -}; - /* basic structure of scan request */ struct brcmf_cfg80211_scan_req { struct brcmf_ssid_le ssid_le; @@ -184,14 +148,6 @@ struct brcmf_cfg80211_ie { 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; @@ -270,26 +226,6 @@ struct brcmf_cfg80211_vif { struct list_head list; }; -/* dongle iscan event loop */ -struct brcmf_cfg80211_iscan_eloop { - s32 (*handler[WL_SCAN_ERSULTS_LAST]) - (struct brcmf_cfg80211_info *cfg); -}; - -/* 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; @@ -323,17 +259,6 @@ struct escan_info { struct net_device *ndev; }; -/* Structure to hold WPS, WPA IEs for a AP */ -struct ap_info { - u8 probe_res_ie[IE_MAX_LEN]; - u8 beacon_ie[IE_MAX_LEN]; - u32 probe_res_ie_len; - u32 beacon_ie_len; - u8 *wpa_ie; - u8 *rsn_ie; - bool security_mode; -}; - /** * struct brcmf_pno_param_le - PNO scan configuration parameters * @@ -421,24 +346,16 @@ struct brcmf_pno_scanresults_le { * @wiphy: wiphy object for cfg80211 interface. * @conf: dongle configuration. * @scan_request: cfg80211 scan request object. - * @el: main event loop. - * @evt_q_list: used for event queue. - * @evt_q_lock: for event queue synchronization. * @usr_sync: mainly for dongle up/down synchronization. * @bss_list: bss_list holding scanned ap information. - * @scan_results: results of the last scan. * @scan_req_int: internal scan request object. * @bss_info: bss information for cfg80211 layer. * @ie: information element object for internal purpose. - * @iscan: iscan controller information. * @conn_info: association info. * @pmk_list: wpa2 pmk list. - * @event_work: event handler work struct. * @scan_status: scan activity on the dongle. * @pub: common driver information. * @channel: current channel. - * @iscan_on: iscan on/off switch. - * @iscan_kickstart: indicate iscan already started. * @active_scan: current scan mode. * @sched_escan: e-scan for scheduled scan support running. * @ibss_starter: indicates this sta is ibss starter. @@ -450,12 +367,10 @@ struct brcmf_pno_scanresults_le { * @dcmd_buf: dcmd buffer. * @extra_buf: mainly to grab assoc information. * @debugfsdir: debugfs folder for this device. - * @escan_on: escan on/off switch. * @escan_info: escan information. * @escan_timeout: Timer for catch scan timeout. * @escan_timeout_work: scan timeout worker. * @escan_ioctl_buf: dongle command buffer for escan commands. - * @ap_info: host ap information. * @vif_list: linked list of vif instances. * @vif_cnt: number of vif instances. */ @@ -463,24 +378,16 @@ struct brcmf_cfg80211_info { struct wiphy *wiphy; struct brcmf_cfg80211_conf *conf; struct cfg80211_scan_request *scan_request; - struct brcmf_cfg80211_event_loop el; - struct list_head evt_q_list; - spinlock_t evt_q_lock; struct mutex usr_sync; struct brcmf_scan_results *bss_list; - struct brcmf_scan_results *scan_results; - struct brcmf_cfg80211_scan_req *scan_req_int; + struct brcmf_cfg80211_scan_req scan_req_int; struct wl_cfg80211_bss_info *bss_info; struct brcmf_cfg80211_ie ie; - struct brcmf_cfg80211_iscan_ctrl *iscan; struct brcmf_cfg80211_connect_info conn_info; struct brcmf_cfg80211_pmk_list *pmk_list; - struct work_struct event_work; unsigned long scan_status; struct brcmf_pub *pub; u32 channel; - bool iscan_on; - bool iscan_kickstart; bool active_scan; bool sched_escan; bool ibss_starter; @@ -492,12 +399,10 @@ struct brcmf_cfg80211_info { u8 *dcmd_buf; u8 *extra_buf; struct dentry *debugfsdir; - bool escan_on; struct escan_info escan_info; struct timer_list escan_timeout; struct work_struct escan_timeout_work; u8 *escan_ioctl_buf; - struct ap_info *ap_info; struct list_head vif_list; u8 vif_cnt; }; @@ -536,8 +441,11 @@ static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd) return &ifp->vif->profile; } -#define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data)) -#define cfg_to_iscan(w) (w->iscan) +static inline struct brcmf_cfg80211_vif *ndev_to_vif(struct net_device *ndev) +{ + struct brcmf_if *ifp = netdev_priv(ndev); + return ifp->vif; +} static inline struct brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) @@ -547,11 +455,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr); void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); - -/* event handler from dongle */ -void brcmf_cfg80211_event(struct net_device *ndev, - const struct brcmf_event_msg *e, void *data); -s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg); -s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg); +s32 brcmf_cfg80211_up(struct net_device *ndev); +s32 brcmf_cfg80211_down(struct net_device *ndev); #endif /* _wl_cfg80211_h_ */ |