diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211')
29 files changed, 2223 insertions, 440 deletions
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index cd6375de2a60..c5104533e24e 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -26,16 +26,25 @@ config BRCMFMAC it'll be called brcmfmac.ko. config BRCMFMAC_SDIO - bool "SDIO bus interface support for FullMAC" + bool "SDIO bus interface support for FullMAC driver" depends on MMC depends on BRCMFMAC select FW_LOADER default y ---help--- This option enables the SDIO bus interface support for Broadcom - FullMAC WLAN driver. - Say Y if you want to use brcmfmac for a compatible SDIO interface - wireless card. + IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to + use the driver for a SDIO wireless card. + +config BRCMFMAC_USB + bool "USB bus interface support for FullMAC driver" + depends on USB + depends on BRCMFMAC + select FW_LOADER + ---help--- + This option enables the USB bus interface support for Broadcom + IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to + use the driver for an USB wireless card. config BRCMDBG bool "Broadcom driver debug functions" diff --git a/drivers/net/wireless/brcm80211/Makefile b/drivers/net/wireless/brcm80211/Makefile index f41c047eca82..b987920e982e 100644 --- a/drivers/net/wireless/brcm80211/Makefile +++ b/drivers/net/wireless/brcm80211/Makefile @@ -16,7 +16,7 @@ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # common flags -subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG +subdir-ccflags-$(CONFIG_BRCMDBG) += -DDEBUG obj-$(CONFIG_BRCMUTIL) += brcmutil/ obj-$(CONFIG_BRCMFMAC) += brcmfmac/ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 9ca9ea1135ea..abb48032753b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -19,6 +19,8 @@ ccflags-y += \ -Idrivers/net/wireless/brcm80211/brcmfmac \ -Idrivers/net/wireless/brcm80211/include +ccflags-y += -D__CHECK_ENDIAN__ + obj-$(CONFIG_BRCMFMAC) += brcmfmac.o brcmfmac-objs += \ wl_cfg80211.o \ @@ -30,5 +32,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ bcmsdh.o \ bcmsdh_sdmmc.o \ sdio_chip.o - -ccflags-y += -D__CHECK_ENDIAN__ +brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ + usb.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 4bc8d251acf8..e925290b432b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -15,6 +15,8 @@ */ /* ****************** SDIO CARD Interface Functions **************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/types.h> #include <linux/netdevice.h> #include <linux/export.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 9b8c0ed833d4..4688904908ec 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -13,6 +13,9 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/types.h> #include <linux/netdevice.h> #include <linux/mmc/sdio.h> @@ -291,13 +294,14 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt) { int status; - uint pkt_len = pkt->len; + uint pkt_len; bool fifo = (fix_inc == SDIOH_DATA_FIX); brcmf_dbg(TRACE, "Enter\n"); if (pkt == NULL) return -EINVAL; + pkt_len = pkt->len; brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); if (brcmf_pm_resume_error(sdiodev)) @@ -485,7 +489,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, sdiodev->func[0] = func->card->sdio_func[0]; sdiodev->func[1] = func; sdiodev->bus_if = bus_if; - bus_if->bus_priv = sdiodev; + bus_if->bus_priv.sdio = sdiodev; bus_if->type = SDIO_BUS; bus_if->align = BRCMF_SDALIGN; dev_set_drvdata(&func->card->dev, sdiodev); @@ -526,7 +530,7 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) if (func->num == 2) { bus_if = dev_get_drvdata(&func->dev); - sdiodev = bus_if->bus_priv; + 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); @@ -593,14 +597,14 @@ static struct sdio_driver brcmf_sdmmc_driver = { #endif /* CONFIG_PM_SLEEP */ }; -static void __exit brcmf_sdio_exit(void) +void brcmf_sdio_exit(void) { brcmf_dbg(TRACE, "Enter\n"); sdio_unregister_driver(&brcmf_sdmmc_driver); } -static int __init brcmf_sdio_init(void) +void brcmf_sdio_init(void) { int ret; @@ -610,9 +614,4 @@ static int __init brcmf_sdio_init(void) if (ret) brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret); - - return ret; } - -module_init(brcmf_sdio_init); -module_exit(brcmf_sdio_exit); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index e58ea40a75b0..07686a748d3c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -644,9 +644,9 @@ extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len); -#ifdef BCMDBG +#ifdef DEBUG extern int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size); -#endif /* BCMDBG */ +#endif /* DEBUG */ extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name); extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index ad9be2410b59..366916494be4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -39,8 +39,11 @@ struct dngl_stats { /* interface structure between common and bus layer */ struct brcmf_bus { u8 type; /* bus type */ - void *bus_priv; /* pointer to bus private structure */ - void *drvr; /* pointer to driver pub structure brcmf_pub */ + union { + struct brcmf_sdio_dev *sdio; + struct brcmf_usbdev *usb; + } bus_priv; + struct brcmf_pub *drvr; /* pointer to driver pub structure brcmf_pub */ enum brcmf_bus_state state; uint maxctl; /* Max size rxctl request from proto to bus */ bool drvr_up; /* Status flag of driver up/down */ @@ -102,4 +105,14 @@ extern int brcmf_bus_start(struct device *dev); extern int brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr); + +#ifdef CONFIG_BRCMFMAC_SDIO +extern void brcmf_sdio_exit(void); +extern void brcmf_sdio_init(void); +#endif +#ifdef CONFIG_BRCMFMAC_USB +extern void brcmf_usb_exit(void); +extern void brcmf_usb_init(void); +#endif + #endif /* _BRCMF_BUS_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index ac8d1f437888..b3e3b7f25d82 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -19,6 +19,8 @@ * For certain dcmd codes, the dongle interprets string data from the host. ******************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/types.h> #include <linux/netdevice.h> #include <linux/sched.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index a51d8f5d36fc..4187435220f3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -13,6 +13,9 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/string.h> #include <linux/sched.h> @@ -38,7 +41,7 @@ #define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \ offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern) -#ifdef BCMDBG +#ifdef DEBUG static const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " __DATE__ " at " __TIME__; @@ -133,7 +136,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, return p != NULL; } -#ifdef BCMDBG +#ifdef DEBUG static void brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) { @@ -399,10 +402,10 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) p = (char *)&buf[sizeof(struct msgtrace_hdr)]; while ((s = strstr(p, "\n")) != NULL) { *s = '\0'; - printk(KERN_DEBUG"%s\n", p); + pr_debug("%s\n", p); p = s + 1; } - printk(KERN_DEBUG "%s\n", p); + pr_debug("%s\n", p); /* Reset datalen to avoid display below */ datalen = 0; @@ -430,7 +433,7 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) brcmf_dbg(EVENT, "\n"); } } -#endif /* BCMDBG */ +#endif /* DEBUG */ int brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata, @@ -518,9 +521,9 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata, break; } -#ifdef BCMDBG +#ifdef DEBUG brcmf_c_show_host_event(event, event_data); -#endif /* BCMDBG */ +#endif /* DEBUG */ return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index bb26ee36bc68..a2c4576cf9ff 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -32,20 +32,20 @@ #define BRCMF_BTA_VAL 0x1000 #define BRCMF_ISCAN_VAL 0x2000 -#if defined(BCMDBG) +#if defined(DEBUG) #define brcmf_dbg(level, fmt, ...) \ do { \ if (BRCMF_ERROR_VAL == BRCMF_##level##_VAL) { \ if (brcmf_msg_level & BRCMF_##level##_VAL) { \ if (net_ratelimit()) \ - printk(KERN_DEBUG "%s: " fmt, \ - __func__, ##__VA_ARGS__); \ + pr_debug("%s: " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } else { \ if (brcmf_msg_level & BRCMF_##level##_VAL) { \ - printk(KERN_DEBUG "%s: " fmt, \ - __func__, ##__VA_ARGS__); \ + pr_debug("%s: " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } \ } while (0) @@ -56,7 +56,7 @@ do { \ #define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) -#else /* (defined BCMDBG) || (defined BCMDBG) */ +#else /* (defined DEBUG) || (defined DEBUG) */ #define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__) @@ -66,7 +66,13 @@ do { \ #define BRCMF_BYTES_ON() 0 #define BRCMF_GLOM_ON() 0 -#endif /* defined(BCMDBG) */ +#endif /* defined(DEBUG) */ + +#define brcmf_dbg_hex_dump(test, data, len, fmt, ...) \ +do { \ + if (test) \ + brcmu_dbg_hex_dump(data, len, fmt, ##__VA_ARGS__); \ +} while (0) extern int brcmf_msg_level; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index eb9eb766ac27..2a1e5ae0c402 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -14,6 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/init.h> #include <linux/kernel.h> #include <linux/kthread.h> @@ -590,8 +592,8 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, sprintf(info->bus_info, "%s", dev_name(drvr->dev)); } -static struct ethtool_ops brcmf_ethtool_ops = { - .get_drvinfo = brcmf_ethtool_get_drvinfo +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) @@ -794,18 +796,19 @@ static int brcmf_netdev_open(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_bus *bus_if = drvr->bus_if; u32 toe_ol; s32 ret = 0; brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); if (ifp->idx == 0) { /* do it only for primary eth0 */ - /* try to bring up bus */ - ret = brcmf_bus_start(drvr->dev); - if (ret != 0) { - brcmf_dbg(ERROR, "failed with code %d\n", ret); - return -1; + /* 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); memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); @@ -977,12 +980,6 @@ int brcmf_bus_start(struct device *dev) return ret; } - /* If bus is not ready, can't come up */ - if (bus_if->state != BRCMF_BUS_DATA) { - brcmf_dbg(ERROR, "failed bus is not ready\n"); - return -ENODEV; - } - brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf, @@ -1019,6 +1016,8 @@ int brcmf_bus_start(struct device *dev) if (ret < 0) return ret; + /* signal bus ready */ + bus_if->state = BRCMF_BUS_DATA; return 0; } @@ -1107,13 +1106,13 @@ void brcmf_detach(struct device *dev) if (drvr->iflist[i]) brcmf_del_if(drvr, i); - cancel_work_sync(&drvr->setmacaddr_work); - cancel_work_sync(&drvr->multicast_work); - brcmf_bus_detach(drvr); - if (drvr->prot) + if (drvr->prot) { + cancel_work_sync(&drvr->setmacaddr_work); + cancel_work_sync(&drvr->multicast_work); brcmf_proto_detach(drvr); + } bus_if->drvr = NULL; kfree(drvr); @@ -1146,7 +1145,7 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) return pend; } -#ifdef BCMDBG +#ifdef DEBUG int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size) { int ret = 0; @@ -1180,4 +1179,38 @@ exit: return ret; } -#endif /* BCMDBG */ +#endif /* DEBUG */ + +static void brcmf_driver_init(struct work_struct *work) +{ +#ifdef CONFIG_BRCMFMAC_SDIO + brcmf_sdio_init(); +#endif +#ifdef CONFIG_BRCMFMAC_USB + brcmf_usb_init(); +#endif +} +static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init); + +static int __init brcmfmac_module_init(void) +{ + if (!schedule_work(&brcmf_driver_work)) + return -EBUSY; + + return 0; +} + +static void __exit brcmfmac_module_exit(void) +{ + cancel_work_sync(&brcmf_driver_work); + +#ifdef CONFIG_BRCMFMAC_SDIO + brcmf_sdio_exit(); +#endif +#ifdef CONFIG_BRCMFMAC_USB + brcmf_usb_exit(); +#endif +} + +module_init(brcmfmac_module_init); +module_exit(brcmfmac_module_exit); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index f7eeee1dcdb6..2bf5dda29291 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -14,6 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/types.h> #include <linux/kernel.h> #include <linux/kthread.h> @@ -40,7 +42,7 @@ #define DCMD_RESP_TIMEOUT 2000 /* In milli second */ -#ifdef BCMDBG +#ifdef DEBUG #define BRCMF_TRAP_INFO_SIZE 80 @@ -84,7 +86,7 @@ struct rte_console { char cbuf[CBUF_LEN]; }; -#endif /* BCMDBG */ +#endif /* DEBUG */ #include <chipcommon.h> #include "dhd_bus.h" @@ -307,10 +309,10 @@ struct rte_console { /* Flags for SDH calls */ #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) -#define BRCMFMAC_FW_NAME "brcm/brcmfmac.bin" -#define BRCMFMAC_NV_NAME "brcm/brcmfmac.txt" -MODULE_FIRMWARE(BRCMFMAC_FW_NAME); -MODULE_FIRMWARE(BRCMFMAC_NV_NAME); +#define BRCMF_SDIO_FW_NAME "brcm/brcmfmac-sdio.bin" +#define BRCMF_SDIO_NV_NAME "brcm/brcmfmac-sdio.txt" +MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME); +MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME); #define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */ #define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change @@ -416,7 +418,7 @@ struct sdpcmd_regs { u16 PAD[0x80]; }; -#ifdef BCMDBG +#ifdef DEBUG /* Device console log buffer state */ struct brcmf_console { uint count; /* Poll interval msec counter */ @@ -426,7 +428,7 @@ struct brcmf_console { u8 *buf; /* Log buffer (host copy) */ uint last; /* Last buffer read index */ }; -#endif /* BCMDBG */ +#endif /* DEBUG */ struct sdpcm_shared { u32 flags; @@ -507,11 +509,11 @@ struct brcmf_sdio { uint polltick; /* Tick counter */ uint pollcnt; /* Count of active polls */ -#ifdef BCMDBG +#ifdef DEBUG uint console_interval; struct brcmf_console console; /* Console output polling support */ uint console_addr; /* Console address from shared struct */ -#endif /* BCMDBG */ +#endif /* DEBUG */ uint regfails; /* Count of R_REG failures */ @@ -587,10 +589,10 @@ struct brcmf_sdio { #define CLK_PENDING 2 /* Not used yet */ #define CLK_AVAIL 3 -#ifdef BCMDBG +#ifdef DEBUG static int qcount[NUMPRIO]; static int tx_packets[NUMPRIO]; -#endif /* BCMDBG */ +#endif /* DEBUG */ #define SDIO_DRIVE_STRENGTH 6 /* in milliamps */ @@ -764,12 +766,12 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) bus->clkstate = CLK_AVAIL; brcmf_dbg(INFO, "CLKCTL: turned ON\n"); -#if defined(BCMDBG) - if (bus->alp_only != true) { +#if defined(DEBUG) + if (!bus->alp_only) { if (SBSDIO_ALPONLY(clkctl)) brcmf_dbg(ERROR, "HT Clock should be on\n"); } -#endif /* defined (BCMDBG) */ +#endif /* defined (DEBUG) */ bus->activity = true; } else { @@ -814,9 +816,9 @@ static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on) /* Transition SD and backplane clock readiness */ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) { -#ifdef BCMDBG +#ifdef DEBUG uint oldstate = bus->clkstate; -#endif /* BCMDBG */ +#endif /* DEBUG */ brcmf_dbg(TRACE, "Enter\n"); @@ -861,9 +863,9 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) brcmf_sdbrcm_wd_timer(bus, 0); break; } -#ifdef BCMDBG +#ifdef DEBUG brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate); -#endif /* BCMDBG */ +#endif /* DEBUG */ return 0; } @@ -1279,13 +1281,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } return 0; } -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - printk(KERN_DEBUG "SUPERFRAME:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - pfirst->data, min_t(int, pfirst->len, 48)); - } -#endif + + brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), + pfirst->data, min_t(int, pfirst->len, 48), + "SUPERFRAME:\n"); /* Validate the superframe header */ dptr = (u8 *) (pfirst->data); @@ -1362,13 +1361,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) check = get_unaligned_le16(dptr + sizeof(u16)); chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - printk(KERN_DEBUG "subframe:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - dptr, 32); - } -#endif + brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), + dptr, 32, "subframe:\n"); if ((u16)~(sublen ^ check)) { brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n", @@ -1433,13 +1427,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } rxseq++; -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { - printk(KERN_DEBUG "Rx Subframe Data:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - dptr, dlen); - } -#endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), + dptr, dlen, "Rx Subframe Data:\n"); __skb_trim(pfirst, sublen); skb_pull(pfirst, doff); @@ -1457,17 +1446,13 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) continue; } -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", - bus->glom.qlen, pfirst, pfirst->data, - pfirst->len, pfirst->next, - pfirst->prev); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - pfirst->data, - min_t(int, pfirst->len, 32)); - } -#endif /* BCMDBG */ + brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), + pfirst->data, + min_t(int, pfirst->len, 32), + "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", + bus->glom.qlen, pfirst, pfirst->data, + pfirst->len, pfirst->next, + pfirst->prev); } /* sent any remaining packets up */ if (bus->glom.qlen) { @@ -1584,12 +1569,8 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) gotpkt: -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { - printk(KERN_DEBUG "RxCtrl:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len); - } -#endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), + bus->rxctl, len, "RxCtrl:\n"); /* Point to valid data and indicate its length */ bus->rxctl += doff; @@ -1818,17 +1799,13 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) } bus->tx_max = txmax; -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { - printk(KERN_DEBUG "Rx Data:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - rxbuf, len); - } else if (BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "RxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - bus->rxhdr, SDPCM_HDRLEN); - } -#endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), + rxbuf, len, "Rx Data:\n"); + brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && + BRCMF_DATA_ON()) && + BRCMF_HDRS_ON(), + bus->rxhdr, SDPCM_HDRLEN, + "RxHdr:\n"); if (chan == SDPCM_CONTROL_CHANNEL) { brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", @@ -1865,13 +1842,9 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) brcmf_sdbrcm_rxfail(bus, true, true); continue; } -#ifdef BCMDBG - if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "RxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - bus->rxhdr, SDPCM_HDRLEN); - } -#endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(), + bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); + /* Extract hardware header fields */ len = get_unaligned_le16(bus->rxhdr); @@ -2024,13 +1997,8 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) skb_push(pkt, BRCMF_FIRSTREAD); memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { - printk(KERN_DEBUG "Rx Data:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - pkt->data, len); - } -#endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), + pkt->data, len, "Rx Data:\n"); deliver: /* Save superframe descriptor and allocate packet frame */ @@ -2038,14 +2006,9 @@ deliver: if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", len); -#ifdef BCMDBG - if (BRCMF_GLOM_ON()) { - printk(KERN_DEBUG "Glom Data:\n"); - print_hex_dump_bytes("", - DUMP_PREFIX_OFFSET, - pkt->data, len); - } -#endif + brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), + pkt->data, len, + "Glom Data:\n"); __skb_trim(pkt, len); skb_pull(pkt, SDPCM_HDRLEN); bus->glomd = pkt; @@ -2078,13 +2041,11 @@ deliver: down(&bus->sdsem); } rxcount = maxframes - rxleft; -#ifdef BCMDBG /* Message if we hit the limit */ if (!rxleft) brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes); else -#endif /* BCMDBG */ brcmf_dbg(DATA, "processed %d frames\n", rxcount); /* Back off rxseq if awaiting rtx, update rx_seq */ if (bus->rxskip) @@ -2098,8 +2059,7 @@ static void brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar) { up(&bus->sdsem); - wait_event_interruptible_timeout(bus->ctrl_wait, - (*lockvar == false), HZ * 2); + wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2); down(&bus->sdsem); return; } @@ -2176,20 +2136,22 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); -#ifdef BCMDBG +#ifdef DEBUG tx_packets[pkt->priority]++; - if (BRCMF_BYTES_ON() && - (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || - (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { - printk(KERN_DEBUG "Tx Frame:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len); - } else if (BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "TxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - frame, min_t(u16, len, 16)); - } #endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && + ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || + (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)), + frame, len, "Tx Frame:\n"); + brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && + ((BRCMF_CTL_ON() && + chan == SDPCM_CONTROL_CHANNEL) || + (BRCMF_DATA_ON() && + chan != SDPCM_CONTROL_CHANNEL))) && + BRCMF_HDRS_ON(), + frame, min_t(u16, len, 16), "TxHdr:\n"); + /* Raise len to next SDIO block to eliminate tail command */ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { u16 pad = bus->blocksize - (len % bus->blocksize); @@ -2314,7 +2276,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) uint retries; int err; struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -2410,7 +2372,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) int err; u8 clkctl, devctl = 0; -#ifdef BCMDBG +#ifdef DEBUG /* Check for inconsistent device control */ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); @@ -2418,7 +2380,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; } -#endif /* BCMDBG */ +#endif /* DEBUG */ /* Read CSR, if clock on switch to AVAIL, else ignore */ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, @@ -2664,7 +2626,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) int ret = -EBADE; uint datalen, prec; struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -2684,8 +2646,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) /* Priority based enq */ spin_lock_bh(&bus->txqlock); - if (brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec) == - false) { + if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { skb_pull(pkt, SDPCM_HDRLEN); brcmf_txcomplete(bus->sdiodev->dev, pkt, false); brcmu_pkt_buf_free_skb(pkt); @@ -2701,7 +2662,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) brcmf_txflowcontrol(bus->sdiodev->dev, 0, ON); } -#ifdef BCMDBG +#ifdef DEBUG if (pktq_plen(&bus->txq, prec) > qcount[prec]) qcount[prec] = pktq_plen(&bus->txq, prec); #endif @@ -2774,7 +2735,7 @@ xfer_done: return bcmerror; } -#ifdef BCMDBG +#ifdef DEBUG #define CONSOLE_LINE_MAX 192 static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus) @@ -2845,14 +2806,14 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus) if (line[n - 1] == '\r') n--; line[n] = 0; - printk(KERN_DEBUG "CONSOLE: %s\n", line); + pr_debug("CONSOLE: %s\n", line); } } break2: return 0; } -#endif /* BCMDBG */ +#endif /* DEBUG */ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) { @@ -2906,7 +2867,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) u8 doff = 0; int ret = -1; struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -2972,7 +2933,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); - if (bus->ctrl_frame_stat == false) { + if (!bus->ctrl_frame_stat) { brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); ret = 0; } else { @@ -2982,17 +2943,11 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) } if (ret == -1) { -#ifdef BCMDBG - if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { - printk(KERN_DEBUG "Tx Frame:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - frame, len); - } else if (BRCMF_HDRS_ON()) { - printk(KERN_DEBUG "TxHdr:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - frame, min_t(u16, len, 16)); - } -#endif + brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), + frame, len, "Tx Frame:\n"); + brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && + BRCMF_HDRS_ON(), + frame, min_t(u16, len, 16), "TxHdr:\n"); do { ret = brcmf_tx_frame(bus, frame, len); @@ -3021,7 +2976,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) uint rxlen = 0; bool pending; struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; brcmf_dbg(TRACE, "Enter\n"); @@ -3040,7 +2995,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) rxlen, msglen); } else if (timeleft == 0) { brcmf_dbg(ERROR, "resumed on timeout\n"); - } else if (pending == true) { + } else if (pending) { brcmf_dbg(CTL, "cancelled\n"); return -ERESTARTSYS; } else { @@ -3096,9 +3051,9 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) u8 *vbuffer; u32 varsizew; __le32 varsizew_le; -#ifdef BCMDBG +#ifdef DEBUG char *nvram_ularray; -#endif /* BCMDBG */ +#endif /* DEBUG */ /* Even if there are no vars are to be written, we still need to set the ramsize. */ @@ -3115,7 +3070,7 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) /* Write the vars list */ bcmerror = brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); -#ifdef BCMDBG +#ifdef DEBUG /* Verify NVRAM bytes */ brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); nvram_ularray = kmalloc(varsize, GFP_ATOMIC); @@ -3142,7 +3097,7 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); kfree(nvram_ularray); -#endif /* BCMDBG */ +#endif /* DEBUG */ kfree(vbuffer); } @@ -3245,7 +3200,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus) brcmf_dbg(INFO, "Enter\n"); - ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME, + ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME, &bus->sdiodev->func[2]->dev); if (ret) { brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); @@ -3342,7 +3297,7 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) char *bufp; int ret; - ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME, + ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, &bus->sdiodev->func[2]->dev); if (ret) { brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); @@ -3432,7 +3387,7 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) static int brcmf_sdbrcm_bus_init(struct device *dev) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; unsigned long timeout; uint retries = 0; @@ -3507,16 +3462,12 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, SBSDIO_WATERMARK, 8, &err); - - /* Set bus state according to enable result */ - bus_if->state = BRCMF_BUS_DATA; - } - - else { + } else { /* Disable F2 again */ enable = SDIO_FUNC_ENABLE_1; brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, enable, NULL); + ret = -ENODEV; } /* Restore previous clock setting */ @@ -3524,7 +3475,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); /* If we didn't come up, turn off backplane clock */ - if (bus_if->state != BRCMF_BUS_DATA) + if (!ret) brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); exit: @@ -3569,9 +3520,9 @@ void brcmf_sdbrcm_isr(void *arg) static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) { -#ifdef BCMDBG +#ifdef DEBUG struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); -#endif /* BCMDBG */ +#endif /* DEBUG */ brcmf_dbg(TIMER, "Enter\n"); @@ -3616,7 +3567,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) /* Update interrupt tracking */ bus->lastintrs = bus->intrcount; } -#ifdef BCMDBG +#ifdef DEBUG /* Poll for console output periodically */ if (bus_if->state == BRCMF_BUS_DATA && bus->console_interval != 0) { @@ -3630,7 +3581,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) bus->console_interval = 0; } } -#endif /* BCMDBG */ +#endif /* DEBUG */ /* On idle timeout clear activity flag and/or turn off clock */ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { @@ -3721,11 +3672,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE)) brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n"); -#ifdef BCMDBG - printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n", - brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); - -#endif /* BCMDBG */ + pr_debug("F1 signature read @0x18000000=0x%4x\n", + brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); /* * Force PLL off until brcmf_sdio_chip_attach() @@ -3944,8 +3892,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, bus, "brcmf_watchdog"); if (IS_ERR(bus->watchdog_tsk)) { - printk(KERN_WARNING - "brcmf_watchdog thread failed to start\n"); + pr_warn("brcmf_watchdog thread failed to start\n"); bus->watchdog_tsk = NULL; } /* Initialize DPC thread */ @@ -3953,8 +3900,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, bus, "brcmf_dpc"); if (IS_ERR(bus->dpc_tsk)) { - printk(KERN_WARNING - "brcmf_dpc thread failed to start\n"); + pr_warn("brcmf_dpc thread failed to start\n"); bus->dpc_tsk = NULL; } @@ -4031,7 +3977,7 @@ void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick) { /* Totally stop the timer */ - if (!wdtick && bus->wd_timer_valid == true) { + if (!wdtick && bus->wd_timer_valid) { del_timer_sync(&bus->timer); bus->wd_timer_valid = false; bus->save_ms = wdtick; @@ -4044,7 +3990,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick) if (wdtick) { if (bus->save_ms != BRCMF_WD_POLL_MS) { - if (bus->wd_timer_valid == true) + if (bus->wd_timer_valid) /* Stop timer and restart at new value */ del_timer_sync(&bus->timer); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index 11b2d7c97ba2..1534efc21631 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -15,6 +15,8 @@ */ /* ***** SDIO interface chip backplane handle functions ***** */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/types.h> #include <linux/netdevice.h> #include <linux/mmc/card.h> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c new file mode 100644 index 000000000000..82364223e817 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -0,0 +1,1621 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#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 <net/cfg80211.h> + +#include <defs.h> +#include <brcmu_utils.h> +#include <brcmu_wifi.h> +#include <dhd_bus.h> +#include <dhd_dbg.h> + +#include "usb_rdl.h" +#include "usb.h" + +#define IOCTL_RESP_TIMEOUT 2000 + +#define BRCMF_USB_SYNC_TIMEOUT 300 /* ms */ +#define BRCMF_USB_DLIMAGE_SPINWAIT 100 /* in unit of ms */ +#define BRCMF_USB_DLIMAGE_LIMIT 500 /* spinwait limit (ms) */ + +#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 + +#define CONFIGDESC(usb) (&((usb)->actconfig)->desc) +#define IFPTR(usb, idx) ((usb)->actconfig->interface[(idx)]) +#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) +#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc +#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[(ep)]).desc + +#define CONTROL_IF 0 +#define BULK_IF 0 + +#define BRCMF_USB_CBCTL_WRITE 0 +#define BRCMF_USB_CBCTL_READ 1 +#define BRCMF_USB_MAX_PKT_SIZE 1600 + +#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.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_probe_info { + void *usbdev_info; + struct usb_device *usb; /* USB device pointer from OS */ + uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; + int intr_size; /* Size of interrupt message */ + int interval; /* Interrupt polling interval */ + int vid; + int pid; + enum usb_device_speed device_speed; + enum usbdev_suspend_state suspend_state; + struct usb_interface *intf; +}; +static struct brcmf_usb_probe_info usbdev_probe_info; + +struct brcmf_usb_image { + void *data; + u32 len; +}; +static struct brcmf_usb_image g_image = { NULL, 0 }; + +struct intr_transfer_buf { + u32 notification; + u32 reserved; +}; + +struct brcmf_usbdev_info { + struct brcmf_usbdev bus_pub; /* MUST BE FIRST */ + spinlock_t qlock; + struct list_head rx_freeq; + 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; + bool txoff; + bool rxoff; + bool txoverride; + + struct brcmf_usbreq *tx_reqs; + struct brcmf_usbreq *rx_reqs; + + u8 *image; /* buffer for combine fw and nvram */ + int image_len; + + wait_queue_head_t wait; + bool waitdone; + int sync_urb_status; + + struct usb_device *usbdev; + struct device *dev; + enum usb_device_speed device_speed; + + int ctl_in_pipe, ctl_out_pipe; + struct urb *ctl_urb; /* URB for control endpoint */ + struct usb_ctrlrequest ctl_write; + struct usb_ctrlrequest ctl_read; + u32 ctl_urb_actual_length; + int ctl_urb_status; + int ctl_completed; + wait_queue_head_t ioctl_resp_wait; + wait_queue_head_t ctrl_wait; + ulong ctl_op; + + bool rxctl_deferrespok; + + struct urb *bulk_urb; /* used for FW download */ + struct urb *intr_urb; /* URB for interrupt endpoint */ + int intr_size; /* Size of interrupt message */ + int interval; /* Interrupt polling interval */ + struct intr_transfer_buf intr; /* Data buffer for interrupt endpoint */ + + struct brcmf_usb_probe_info probe_info; + +}; + +static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, + struct brcmf_usbreq *req); + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac usb driver."); +MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac usb cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + return bus_if->bus_priv.usb; +} + +static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev) +{ + return brcmf_usb_get_buspub(dev)->devinfo; +} + +#if 0 +static void +brcmf_usb_txflowcontrol(struct brcmf_usbdev_info *devinfo, bool onoff) +{ + dhd_txflowcontrol(devinfo->bus_pub.netdev, 0, onoff); +} +#endif + +static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo, + uint *condition, bool *pending) +{ + DECLARE_WAITQUEUE(wait, current); + int timeout = IOCTL_RESP_TIMEOUT; + + /* Convert timeout in millsecond to jiffies */ + timeout = msecs_to_jiffies(timeout); + /* Wait until control frame is available */ + add_wait_queue(&devinfo->ioctl_resp_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + smp_mb(); + while (!(*condition) && (!signal_pending(current) && timeout)) { + timeout = schedule_timeout(timeout); + /* Wait until control frame is available */ + smp_mb(); + } + + if (signal_pending(current)) + *pending = true; + + set_current_state(TASK_RUNNING); + remove_wait_queue(&devinfo->ioctl_resp_wait, &wait); + + return timeout; +} + +static int brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo) +{ + if (waitqueue_active(&devinfo->ioctl_resp_wait)) + wake_up_interruptible(&devinfo->ioctl_resp_wait); + + return 0; +} + +static void +brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status) +{ + + if (unlikely(devinfo == NULL)) + return; + + if (type == BRCMF_USB_CBCTL_READ) { + if (status == 0) + devinfo->bus_pub.stats.rx_ctlpkts++; + else + devinfo->bus_pub.stats.rx_ctlerrs++; + } else if (type == BRCMF_USB_CBCTL_WRITE) { + if (status == 0) + devinfo->bus_pub.stats.tx_ctlpkts++; + else + devinfo->bus_pub.stats.tx_ctlerrs++; + } + + devinfo->ctl_urb_status = status; + devinfo->ctl_completed = true; + brcmf_usb_ioctl_resp_wake(devinfo); +} + +static void +brcmf_usb_ctlread_complete(struct urb *urb) +{ + struct brcmf_usbdev_info *devinfo = + (struct brcmf_usbdev_info *)urb->context; + + devinfo->ctl_urb_actual_length = urb->actual_length; + brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ, + urb->status); +} + +static void +brcmf_usb_ctlwrite_complete(struct urb *urb) +{ + struct brcmf_usbdev_info *devinfo = + (struct brcmf_usbdev_info *)urb->context; + + 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; + + 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; + devinfo->ctl_urb_status = 0; + devinfo->ctl_urb_actual_length = 0; + + usb_fill_control_urb(devinfo->ctl_urb, + devinfo->usbdev, + devinfo->ctl_out_pipe, + (unsigned char *) &devinfo->ctl_write, + buf, size, + (usb_complete_t)brcmf_usb_ctlwrite_complete, + devinfo); + + ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC); + if (ret < 0) + brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret); + + return ret; +} + +static int +brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) +{ + int ret; + u16 size; + + if ((devinfo == NULL) || (buf == NULL) || (len == 0) + || (devinfo->ctl_urb == NULL)) + return -EINVAL; + + size = len; + devinfo->ctl_read.wLength = cpu_to_le16p(&size); + devinfo->ctl_urb->transfer_buffer_length = size; + + if (devinfo->rxctl_deferrespok) { + /* BMAC model */ + devinfo->ctl_read.bRequestType = USB_DIR_IN + | USB_TYPE_VENDOR | USB_RECIP_INTERFACE; + devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK; + } else { + /* full dongle model */ + devinfo->ctl_read.bRequestType = USB_DIR_IN + | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + devinfo->ctl_read.bRequest = 1; + } + + usb_fill_control_urb(devinfo->ctl_urb, + devinfo->usbdev, + devinfo->ctl_in_pipe, + (unsigned char *) &devinfo->ctl_read, + buf, size, + (usb_complete_t)brcmf_usb_ctlread_complete, + devinfo); + + ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC); + if (ret < 0) + brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret); + + return ret; +} + +static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) +{ + int err = 0; + int timeout = 0; + bool pending; + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + + if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { + /* TODO: handle suspend/resume */ + return -EIO; + } + + if (test_and_set_bit(0, &devinfo->ctl_op)) + return -EIO; + + err = brcmf_usb_send_ctl(devinfo, buf, len); + if (err) { + brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); + return err; + } + + devinfo->ctl_completed = false; + timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed, + &pending); + clear_bit(0, &devinfo->ctl_op); + if (!timeout) { + brcmf_dbg(ERROR, "Txctl wait timed out\n"); + err = -EIO; + } + return err; +} + +static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) +{ + int err = 0; + int timeout = 0; + bool pending; + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + + if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { + /* TODO: handle suspend/resume */ + return -EIO; + } + if (test_and_set_bit(0, &devinfo->ctl_op)) + return -EIO; + + err = brcmf_usb_recv_ctl(devinfo, buf, len); + if (err) { + brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); + return err; + } + devinfo->ctl_completed = false; + timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed, + &pending); + err = devinfo->ctl_urb_status; + clear_bit(0, &devinfo->ctl_op); + if (!timeout) { + brcmf_dbg(ERROR, "rxctl wait timed out\n"); + err = -EIO; + } + if (!err) + return devinfo->ctl_urb_actual_length; + else + return err; +} + +static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo, + struct list_head *q) +{ + unsigned long flags; + struct brcmf_usbreq *req; + spin_lock_irqsave(&devinfo->qlock, flags); + if (list_empty(q)) { + spin_unlock_irqrestore(&devinfo->qlock, flags); + return NULL; + } + req = list_entry(q->next, struct brcmf_usbreq, list); + list_del_init(q->next); + spin_unlock_irqrestore(&devinfo->qlock, flags); + return req; + +} + +static void brcmf_usb_enq(struct brcmf_usbdev_info *devinfo, + struct list_head *q, struct brcmf_usbreq *req) +{ + unsigned long flags; + spin_lock_irqsave(&devinfo->qlock, flags); + list_add_tail(&req->list, q); + spin_unlock_irqrestore(&devinfo->qlock, flags); +} + +static struct brcmf_usbreq * +brcmf_usbdev_qinit(struct list_head *q, int qsize) +{ + int i; + struct brcmf_usbreq *req, *reqs; + + reqs = kzalloc(sizeof(struct brcmf_usbreq) * qsize, GFP_ATOMIC); + if (reqs == NULL) { + brcmf_dbg(ERROR, "fail to allocate memory!\n"); + return NULL; + } + req = reqs; + + for (i = 0; i < qsize; i++) { + req->urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!req->urb) + goto fail; + + INIT_LIST_HEAD(&req->list); + list_add_tail(&req->list, q); + req++; + } + return reqs; +fail: + brcmf_dbg(ERROR, "fail!\n"); + while (!list_empty(q)) { + req = list_entry(q->next, struct brcmf_usbreq, list); + if (req && req->urb) + usb_free_urb(req->urb); + list_del(q->next); + } + return NULL; + +} + +static void brcmf_usb_free_q(struct list_head *q, bool pending) +{ + struct brcmf_usbreq *req, *next; + int i = 0; + list_for_each_entry_safe(req, next, q, list) { + if (!req->urb) { + brcmf_dbg(ERROR, "bad req\n"); + break; + } + i++; + if (pending) { + usb_kill_urb(req->urb); + } else { + usb_free_urb(req->urb); + list_del_init(&req->list); + } + } +} + +static void brcmf_usb_del_fromq(struct brcmf_usbdev_info *devinfo, + struct brcmf_usbreq *req) +{ + unsigned long flags; + + spin_lock_irqsave(&devinfo->qlock, flags); + list_del_init(&req->list); + spin_unlock_irqrestore(&devinfo->qlock, flags); +} + + +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_usb_del_fromq(devinfo, req); + if (urb->status == 0) + devinfo->bus_pub.bus->dstats.tx_packets++; + else + devinfo->bus_pub.bus->dstats.tx_errors++; + + dev_kfree_skb(req->skb); + req->skb = NULL; + brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); + +} + +static void brcmf_usb_rx_complete(struct urb *urb) +{ + struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; + struct brcmf_usbdev_info *devinfo = req->devinfo; + struct sk_buff *skb; + int ifidx = 0; + + brcmf_usb_del_fromq(devinfo, req); + skb = req->skb; + req->skb = NULL; + + if (urb->status == 0) { + devinfo->bus_pub.bus->dstats.rx_packets++; + } else { + devinfo->bus_pub.bus->dstats.rx_errors++; + dev_kfree_skb(skb); + brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); + return; + } + + if (devinfo->bus_pub.state == BCMFMAC_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"); + brcmu_pkt_buf_free_skb(skb); + devinfo->bus_pub.bus->dstats.rx_errors++; + } else { + brcmf_rx_packet(devinfo->dev, ifidx, skb); + brcmf_usb_rx_refill(devinfo, req); + } + } else { + dev_kfree_skb(skb); + } + return; + +} + +static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, + struct brcmf_usbreq *req) +{ + struct sk_buff *skb; + int ret; + + if (!req || !devinfo) + return; + + skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu); + if (!skb) { + brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); + return; + } + req->skb = skb; + + usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe, + skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, + req); + req->urb->transfer_flags |= URB_ZERO_PACKET; + req->devinfo = devinfo; + + ret = usb_submit_urb(req->urb, GFP_ATOMIC); + if (ret == 0) { + brcmf_usb_enq(devinfo, &devinfo->rx_postq, req); + } else { + dev_kfree_skb(req->skb); + req->skb = NULL; + brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); + } + return; +} + +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"); + return; + } + while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq)) != NULL) + brcmf_usb_rx_refill(devinfo, req); +} + +static void +brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state) +{ + struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus; + int old_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); + } + + /* update state of upper layer */ + if (state == BCMFMAC_USB_STATE_DOWN) { + brcmf_dbg(INFO, "DBUS is down\n"); + bcmf_bus->state = BRCMF_BUS_DOWN; + } else { + brcmf_dbg(INFO, "DBUS current state=%d\n", state); + } +} + +static void +brcmf_usb_intr_complete(struct urb *urb) +{ + struct brcmf_usbdev_info *devinfo = + (struct brcmf_usbdev_info *)urb->context; + bool killed; + + 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 (devinfo->bus_pub.state == BCMFMAC_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); +} + +static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) +{ + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + struct brcmf_usbreq *req; + int ret; + + if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { + /* TODO: handle suspend/resume */ + return -EIO; + } + + req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq); + if (!req) { + brcmf_dbg(ERROR, "no req to send\n"); + return -ENOMEM; + } + if (!req->urb) { + brcmf_dbg(ERROR, "no urb for req %p\n", req); + return -ENOBUFS; + } + + req->skb = skb; + req->devinfo = devinfo; + usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, + skb->data, skb->len, brcmf_usb_tx_complete, req); + req->urb->transfer_flags |= URB_ZERO_PACKET; + ret = usb_submit_urb(req->urb, GFP_ATOMIC); + if (!ret) { + brcmf_usb_enq(devinfo, &devinfo->tx_postq, req); + } else { + req->skb = NULL; + brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); + } + + return ret; +} + + +static int brcmf_usb_up(struct device *dev) +{ + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + u16 ifnum; + + if (devinfo->bus_pub.state == BCMFMAC_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); + + if (devinfo->intr_urb) { + int ret; + + usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev, + devinfo->intr_pipe, + &devinfo->intr, + devinfo->intr_size, + (usb_complete_t)brcmf_usb_intr_complete, + devinfo, + devinfo->interval); + + ret = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); + if (ret) { + brcmf_dbg(ERROR, "USB_SUBMIT_URB failed with status %d\n", + ret); + return -EINVAL; + } + } + + if (devinfo->ctl_urb) { + devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0); + devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0); + + ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber; + + /* CTL Write */ + devinfo->ctl_write.bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + devinfo->ctl_write.bRequest = 0; + devinfo->ctl_write.wValue = cpu_to_le16(0); + devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum); + + /* CTL Read */ + devinfo->ctl_read.bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + devinfo->ctl_read.bRequest = 1; + devinfo->ctl_read.wValue = cpu_to_le16(0); + devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum); + } + brcmf_usb_rx_fill_all(devinfo); + return 0; +} + +static void brcmf_usb_down(struct device *dev) +{ + struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); + + if (devinfo == NULL) + return; + + brcmf_dbg(TRACE, "enter\n"); + if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) + return; + + brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN); + if (devinfo->intr_urb) + usb_kill_urb(devinfo->intr_urb); + + if (devinfo->ctl_urb) + usb_kill_urb(devinfo->ctl_urb); + + if (devinfo->bulk_urb) + usb_kill_urb(devinfo->bulk_urb); + brcmf_usb_free_q(&devinfo->tx_postq, true); + + brcmf_usb_free_q(&devinfo->rx_postq, true); +} + +static int +brcmf_usb_sync_wait(struct brcmf_usbdev_info *devinfo, u16 time) +{ + int ret; + int err = 0; + int ms = time; + + ret = wait_event_interruptible_timeout(devinfo->wait, + devinfo->waitdone == true, (ms * HZ / 1000)); + + if ((devinfo->waitdone == false) || (devinfo->sync_urb_status)) { + brcmf_dbg(ERROR, "timeout(%d) or urb err=%d\n", + ret, devinfo->sync_urb_status); + err = -EINVAL; + } + devinfo->waitdone = false; + return err; +} + +static void +brcmf_usb_sync_complete(struct urb *urb) +{ + struct brcmf_usbdev_info *devinfo = + (struct brcmf_usbdev_info *)urb->context; + + devinfo->waitdone = true; + wake_up_interruptible(&devinfo->wait); + devinfo->sync_urb_status = urb->status; +} + +static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd, + void *buffer, int buflen) +{ + int ret = 0; + char *tmpbuf; + u16 size; + + if ((!devinfo) || (devinfo->ctl_urb == NULL)) + return false; + + tmpbuf = kmalloc(buflen, GFP_ATOMIC); + if (!tmpbuf) + return false; + + size = buflen; + devinfo->ctl_urb->transfer_buffer_length = size; + + devinfo->ctl_read.wLength = cpu_to_le16p(&size); + devinfo->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_INTERFACE; + devinfo->ctl_read.bRequest = cmd; + + usb_fill_control_urb(devinfo->ctl_urb, + devinfo->usbdev, + usb_rcvctrlpipe(devinfo->usbdev, 0), + (unsigned char *) &devinfo->ctl_read, + (void *) tmpbuf, size, + (usb_complete_t)brcmf_usb_sync_complete, devinfo); + + ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC); + if (ret < 0) { + brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret); + kfree(tmpbuf); + return false; + } + + ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT); + memcpy(buffer, tmpbuf, buflen); + kfree(tmpbuf); + + return (ret == 0); +} + +static bool +brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo) +{ + struct bootrom_id_le id; + u32 chipid, chiprev; + + brcmf_dbg(TRACE, "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)); + + 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); + else + brcmf_dbg(INFO, "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)); + return false; + } else { + devinfo->bus_pub.devid = chipid; + devinfo->bus_pub.chiprev = chiprev; + } + return true; +} + +static int +brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo) +{ + struct bootrom_id_le id; + u16 wait = 0, wait_time; + + brcmf_dbg(TRACE, "enter\n"); + + if (devinfo == NULL) + return -EINVAL; + + /* Give dongle chance to boot */ + wait_time = BRCMF_USB_DLIMAGE_SPINWAIT; + while (wait < BRCMF_USB_DLIMAGE_LIMIT) { + mdelay(wait_time); + wait += wait_time; + id.chip = cpu_to_le32(0xDEAD); /* Get the ID */ + brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, + sizeof(struct bootrom_id_le)); + if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) + break; + } + + 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)); + + /* XXX this wait may not be necessary */ + mdelay(BRCMF_USB_RESETCFG_SPINWAIT); + return 0; + } else { + brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n", + wait); + return -EINVAL; + } +} + + +static int +brcmf_usb_dl_send_bulk(struct brcmf_usbdev_info *devinfo, void *buffer, int len) +{ + int ret; + + if ((devinfo == NULL) || (devinfo->bulk_urb == NULL)) + return -EINVAL; + + /* Prepare the URB */ + usb_fill_bulk_urb(devinfo->bulk_urb, devinfo->usbdev, + devinfo->tx_pipe, buffer, len, + (usb_complete_t)brcmf_usb_sync_complete, devinfo); + + devinfo->bulk_urb->transfer_flags |= URB_ZERO_PACKET; + + ret = usb_submit_urb(devinfo->bulk_urb, GFP_ATOMIC); + if (ret) { + brcmf_dbg(ERROR, "usb_submit_urb failed %d\n", ret); + return ret; + } + ret = brcmf_usb_sync_wait(devinfo, BRCMF_USB_SYNC_TIMEOUT); + return ret; +} + +static int +brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) +{ + unsigned int sendlen, sent, dllen; + char *bulkchunk = NULL, *dlpos; + struct rdl_state_le state; + u32 rdlstate, rdlbytes; + int err = 0; + brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen); + + bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC); + if (bulkchunk == NULL) { + err = -ENOMEM; + goto fail; + } + + /* 1) Prepare USB boot loader for runtime image */ + brcmf_usb_dl_cmd(devinfo, DL_START, &state, + sizeof(struct rdl_state_le)); + + rdlstate = le32_to_cpu(state.state); + rdlbytes = le32_to_cpu(state.bytes); + + /* 2) Check we are in the Waiting state */ + if (rdlstate != DL_WAITING) { + brcmf_dbg(ERROR, "Failed to DL_START\n"); + err = -EINVAL; + goto fail; + } + sent = 0; + dlpos = fw; + dllen = fwlen; + + /* Get chip id and rev */ + while (rdlbytes != dllen) { + /* Wait until the usb device reports it received all + * the bytes we sent */ + if ((rdlbytes == sent) && (rdlbytes != dllen)) { + if ((dllen-sent) < RDL_CHUNK) + sendlen = dllen-sent; + else + sendlen = RDL_CHUNK; + + /* simply avoid having to send a ZLP by ensuring we + * never have an even + * multiple of 64 + */ + if (!(sendlen % 64)) + sendlen -= 4; + + /* send data */ + memcpy(bulkchunk, dlpos, sendlen); + if (brcmf_usb_dl_send_bulk(devinfo, bulkchunk, + sendlen)) { + brcmf_dbg(ERROR, "send_bulk failed\n"); + err = -EINVAL; + goto fail; + } + + dlpos += sendlen; + sent += sendlen; + } + if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, + sizeof(struct rdl_state_le))) { + brcmf_dbg(ERROR, "DL_GETSTATE Failed xxxx\n"); + err = -EINVAL; + goto fail; + } + + rdlstate = le32_to_cpu(state.state); + rdlbytes = le32_to_cpu(state.bytes); + + /* restart if an error is reported */ + if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) { + brcmf_dbg(ERROR, "Bad Hdr or Bad CRC state %d\n", + rdlstate); + err = -EINVAL; + goto fail; + } + } + +fail: + kfree(bulkchunk); + brcmf_dbg(TRACE, "err=%d\n", err); + return err; +} + +static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len) +{ + int err; + + brcmf_dbg(TRACE, "enter\n"); + + if (devinfo == NULL) + return -EINVAL; + + if (devinfo->bus_pub.devid == 0xDEAD) + return -EINVAL; + + err = brcmf_usb_dl_writeimage(devinfo, fw, len); + if (err == 0) + devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE; + else + devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING; + brcmf_dbg(TRACE, "exit: err=%d\n", err); + + return err; +} + +static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo) +{ + struct rdl_state_le state; + + brcmf_dbg(TRACE, "enter\n"); + if (!devinfo) + return -EINVAL; + + if (devinfo->bus_pub.devid == 0xDEAD) + return -EINVAL; + + /* Check we are runnable */ + brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, + sizeof(struct rdl_state_le)); + + /* Start the image */ + if (state.state == cpu_to_le32(DL_RUNNABLE)) { + if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state, + sizeof(struct rdl_state_le))) + return -ENODEV; + if (brcmf_usb_resetcfg(devinfo)) + return -ENODEV; + /* The Dongle may go for re-enumeration. */ + } else { + brcmf_dbg(ERROR, "Dongle not runnable\n"); + return -EINVAL; + } + brcmf_dbg(TRACE, "exit\n"); + return 0; +} + +static bool brcmf_usb_chip_support(int chipid, int chiprev) +{ + switch(chipid) { + case 43235: + case 43236: + case 43238: + return (chiprev == 3); + default: + break; + } + return false; +} + +static int +brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo) +{ + int devid, chiprev; + int err; + + brcmf_dbg(TRACE, "enter\n"); + if (devinfo == NULL) + return -ENODEV; + + devid = devinfo->bus_pub.devid; + chiprev = devinfo->bus_pub.chiprev; + + if (!brcmf_usb_chip_support(devid, chiprev)) { + brcmf_dbg(ERROR, "unsupported chip %d rev %d\n", + devid, chiprev); + return -EINVAL; + } + + if (!devinfo->image) { + brcmf_dbg(ERROR, "No firmware!\n"); + return -ENOENT; + } + + err = brcmf_usb_dlstart(devinfo, + devinfo->image, devinfo->image_len); + if (err == 0) + err = brcmf_usb_dlrun(devinfo); + return err; +} + + +static void brcmf_usb_detach(const struct brcmf_usbdev *bus_pub) +{ + struct brcmf_usbdev_info *devinfo = + (struct brcmf_usbdev_info *)bus_pub; + + brcmf_dbg(TRACE, "devinfo %p\n", devinfo); + + /* store the image globally */ + g_image.data = devinfo->image; + g_image.len = devinfo->image_len; + + /* free the URBS */ + brcmf_usb_free_q(&devinfo->rx_freeq, false); + brcmf_usb_free_q(&devinfo->tx_freeq, false); + + usb_free_urb(devinfo->intr_urb); + usb_free_urb(devinfo->ctl_urb); + usb_free_urb(devinfo->bulk_urb); + + kfree(devinfo->tx_reqs); + kfree(devinfo->rx_reqs); + kfree(devinfo); +} + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +#define TRX_VERSION 1 /* Version 1 */ +#define TRX_MAX_LEN 0x3B0000 /* Max length */ +#define TRX_NO_HEADER 1 /* Do not write TRX header */ +#define TRX_MAX_OFFSET 3 /* Max number of individual files */ +#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed image */ + +struct trx_header_le { + __le32 magic; /* "HDR0" */ + __le32 len; /* Length of file including header */ + __le32 crc32; /* CRC from flag_version to end of file */ + __le32 flag_version; /* 0:15 flags, 16:31 version */ + __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of + * header */ +}; + +static int check_file(const u8 *headers) +{ + struct trx_header_le *trx; + int actual_len = -1; + + /* Extract trx header */ + trx = (struct trx_header_le *) headers; + if (trx->magic != cpu_to_le32(TRX_MAGIC)) + return -1; + + headers += sizeof(struct trx_header_le); + + if (le32_to_cpu(trx->flag_version) & TRX_UNCOMP_IMAGE) { + actual_len = le32_to_cpu(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]); + return actual_len + sizeof(struct trx_header_le); + } + return -1; +} + +static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) +{ + s8 *fwname; + const struct firmware *fw; + int err; + + devinfo->image = g_image.data; + devinfo->image_len = g_image.len; + + /* + * if we have an image we can leave here. + */ + if (devinfo->image) + return 0; + + fwname = BRCMF_USB_43236_FW_NAME; + + err = request_firmware(&fw, fwname, devinfo->dev); + if (!fw) { + brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname); + return err; + } + if (check_file(fw->data) < 0) { + brcmf_dbg(ERROR, "invalid firmware %s\n", fwname); + return -EINVAL; + } + + devinfo->image = kmalloc(fw->size, GFP_ATOMIC); /* plus nvram */ + if (!devinfo->image) + return -ENOMEM; + + memcpy(devinfo->image, fw->data, fw->size); + devinfo->image_len = fw->size; + + release_firmware(fw); + return 0; +} + + +static +struct brcmf_usbdev *brcmf_usb_attach(int nrxq, int ntxq, struct device *dev) +{ + struct brcmf_usbdev_info *devinfo; + + devinfo = kzalloc(sizeof(struct brcmf_usbdev_info), GFP_ATOMIC); + if (devinfo == NULL) + return NULL; + + devinfo->bus_pub.nrxq = nrxq; + devinfo->rx_low_watermark = nrxq / 2; + devinfo->bus_pub.devinfo = devinfo; + devinfo->bus_pub.ntxq = ntxq; + + /* flow control when too many tx urbs posted */ + devinfo->tx_low_watermark = ntxq / 4; + devinfo->tx_high_watermark = devinfo->tx_low_watermark * 3; + devinfo->dev = dev; + devinfo->usbdev = usbdev_probe_info.usb; + devinfo->tx_pipe = usbdev_probe_info.tx_pipe; + devinfo->rx_pipe = usbdev_probe_info.rx_pipe; + devinfo->rx_pipe2 = usbdev_probe_info.rx_pipe2; + devinfo->intr_pipe = usbdev_probe_info.intr_pipe; + + devinfo->interval = usbdev_probe_info.interval; + devinfo->intr_size = usbdev_probe_info.intr_size; + + memcpy(&devinfo->probe_info, &usbdev_probe_info, + sizeof(struct brcmf_usb_probe_info)); + devinfo->bus_pub.bus_mtu = BRCMF_USB_MAX_PKT_SIZE; + + /* Initialize other structure content */ + init_waitqueue_head(&devinfo->ioctl_resp_wait); + + /* Initialize the spinlocks */ + spin_lock_init(&devinfo->qlock); + + INIT_LIST_HEAD(&devinfo->rx_freeq); + INIT_LIST_HEAD(&devinfo->rx_postq); + + INIT_LIST_HEAD(&devinfo->tx_freeq); + INIT_LIST_HEAD(&devinfo->tx_postq); + + devinfo->rx_reqs = brcmf_usbdev_qinit(&devinfo->rx_freeq, nrxq); + if (!devinfo->rx_reqs) + goto error; + + devinfo->tx_reqs = brcmf_usbdev_qinit(&devinfo->tx_freeq, ntxq); + if (!devinfo->tx_reqs) + goto error; + + devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!devinfo->intr_urb) { + brcmf_dbg(ERROR, "usb_alloc_urb (intr) failed\n"); + goto error; + } + devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!devinfo->ctl_urb) { + brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n"); + goto error; + } + devinfo->rxctl_deferrespok = 0; + + devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!devinfo->bulk_urb) { + brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n"); + goto error; + } + + init_waitqueue_head(&devinfo->wait); + if (!brcmf_usb_dlneeded(devinfo)) + return &devinfo->bus_pub; + + brcmf_dbg(TRACE, "start fw downloading\n"); + if (brcmf_usb_get_fw(devinfo)) + goto error; + + if (brcmf_usb_fw_download(devinfo)) + goto error; + + return &devinfo->bus_pub; + +error: + brcmf_dbg(ERROR, "failed!\n"); + brcmf_usb_detach(&devinfo->bus_pub); + return NULL; +} + +static int brcmf_usb_probe_cb(struct device *dev, const char *desc, + u32 bustype, u32 hdrlen) +{ + struct brcmf_bus *bus = NULL; + struct brcmf_usbdev *bus_pub = NULL; + int ret; + + + bus_pub = brcmf_usb_attach(BRCMF_USB_NRXQ, BRCMF_USB_NTXQ, dev); + if (!bus_pub) { + ret = -ENODEV; + goto fail; + } + + bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); + if (!bus) { + ret = -ENOMEM; + goto fail; + } + + bus_pub->bus = bus; + bus->brcmf_bus_txdata = brcmf_usb_tx; + bus->brcmf_bus_init = brcmf_usb_up; + 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); + if (ret) { + brcmf_dbg(ERROR, "dhd_attach failed\n"); + goto fail; + } + + ret = brcmf_bus_start(dev); + if (ret == -ENOLINK) { + brcmf_dbg(ERROR, "dongle is not responding\n"); + brcmf_detach(dev); + goto fail; + } + + /* add interface and open for business */ + ret = brcmf_add_if(dev, 0, "wlan%d", NULL); + if (ret) { + brcmf_dbg(ERROR, "Add primary net device interface failed!!\n"); + brcmf_detach(dev); + goto fail; + } + + return 0; +fail: + /* Release resources in reverse order */ + if (bus_pub) + brcmf_usb_detach(bus_pub); + kfree(bus); + return ret; +} + +static void +brcmf_usb_disconnect_cb(struct brcmf_usbdev *bus_pub) +{ + if (!bus_pub) + return; + brcmf_dbg(TRACE, "enter: bus_pub %p\n", bus_pub); + + brcmf_detach(bus_pub->devinfo->dev); + kfree(bus_pub->bus); + brcmf_usb_detach(bus_pub); + +} + +static int +brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + int ep; + struct usb_endpoint_descriptor *endpoint; + int ret = 0; + struct usb_device *usb = interface_to_usbdev(intf); + int num_of_eps; + u8 endpoint_num; + + brcmf_dbg(TRACE, "enter\n"); + + usbdev_probe_info.usb = usb; + usbdev_probe_info.intf = intf; + + if (id != NULL) { + usbdev_probe_info.vid = id->idVendor; + usbdev_probe_info.pid = id->idProduct; + } + + usb_set_intfdata(intf, &usbdev_probe_info); + + /* Check that the device supports only one configuration */ + if (usb->descriptor.bNumConfigurations != 1) { + ret = -1; + goto fail; + } + + if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { + ret = -1; + goto fail; + } + + /* + * Only the BDC interface configuration is supported: + * Device class: USB_CLASS_VENDOR_SPEC + * if0 class: USB_CLASS_VENDOR_SPEC + * if0/ep0: control + * if0/ep1: bulk in + * if0/ep2: bulk out (ok if swapped with bulk in) + */ + if (CONFIGDESC(usb)->bNumInterfaces != 1) { + ret = -1; + goto fail; + } + + /* Check interface */ + if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC || + IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 || + IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) { + brcmf_dbg(ERROR, "invalid control interface: class %d, subclass %d, proto %d\n", + IFDESC(usb, CONTROL_IF).bInterfaceClass, + IFDESC(usb, CONTROL_IF).bInterfaceSubClass, + IFDESC(usb, CONTROL_IF).bInterfaceProtocol); + ret = -1; + goto fail; + } + + /* Check control endpoint */ + endpoint = &IFEPDESC(usb, CONTROL_IF, 0); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_INT) { + brcmf_dbg(ERROR, "invalid control endpoint %d\n", + endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + ret = -1; + goto fail; + } + + endpoint_num = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + usbdev_probe_info.intr_pipe = usb_rcvintpipe(usb, endpoint_num); + + usbdev_probe_info.rx_pipe = 0; + usbdev_probe_info.rx_pipe2 = 0; + usbdev_probe_info.tx_pipe = 0; + num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1; + + /* Check data endpoints and get pipes */ + for (ep = 1; ep <= num_of_eps; ep++) { + endpoint = &IFEPDESC(usb, BULK_IF, ep); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_BULK) { + brcmf_dbg(ERROR, "invalid data endpoint %d\n", ep); + ret = -1; + goto fail; + } + + endpoint_num = endpoint->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) { + if (!usbdev_probe_info.rx_pipe) { + usbdev_probe_info.rx_pipe = + usb_rcvbulkpipe(usb, endpoint_num); + } else { + usbdev_probe_info.rx_pipe2 = + usb_rcvbulkpipe(usb, endpoint_num); + } + } else { + usbdev_probe_info.tx_pipe = + usb_sndbulkpipe(usb, endpoint_num); + } + } + + /* Allocate interrupt URB and data buffer */ + /* RNDIS says 8-byte intr, our old drivers used 4-byte */ + if (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == cpu_to_le16(16)) + usbdev_probe_info.intr_size = 8; + else + usbdev_probe_info.intr_size = 4; + + usbdev_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval; + + usbdev_probe_info.device_speed = usb->speed; + if (usb->speed == USB_SPEED_HIGH) + brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n"); + else + brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n"); + + ret = brcmf_usb_probe_cb(&usb->dev, "", USB_BUS, 0); + if (ret) + goto fail; + + /* Success */ + return 0; + +fail: + brcmf_dbg(ERROR, "failed with errno %d\n", ret); + usb_set_intfdata(intf, NULL); + return ret; + +} + +static void +brcmf_usb_disconnect(struct usb_interface *intf) +{ + struct usb_device *usb = interface_to_usbdev(intf); + + brcmf_dbg(TRACE, "enter\n"); + brcmf_usb_disconnect_cb(brcmf_usb_get_buspub(&usb->dev)); + usb_set_intfdata(intf, NULL); +} + +/* + * only need to signal the bus being down and update the suspend 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; + return 0; +} + +/* + * mark suspend state active and crank up 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); + return 0; +} + +#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c +#define BRCMF_USB_DEVICE_ID_43236 0xbd17 +#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc + +static struct usb_device_id brcmf_usb_devid_table[] = { + { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) }, + /* special entry for device with firmware loaded and running */ + { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) }, + { } +}; +MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table); +MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME); + +/* TODO: suspend and resume entries */ +static struct usb_driver brcmf_usbdrvr = { + .name = KBUILD_MODNAME, + .probe = brcmf_usb_probe, + .disconnect = brcmf_usb_disconnect, + .id_table = brcmf_usb_devid_table, + .suspend = brcmf_usb_suspend, + .resume = brcmf_usb_resume, + .supports_autosuspend = 1 +}; + +void brcmf_usb_exit(void) +{ + usb_deregister(&brcmf_usbdrvr); + kfree(g_image.data); + g_image.data = NULL; + g_image.len = 0; +} + +void brcmf_usb_init(void) +{ + usb_register(&brcmf_usbdrvr); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.h b/drivers/net/wireless/brcm80211/brcmfmac/usb.h new file mode 100644 index 000000000000..acfa5e89872f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_USB_H +#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, +}; + +struct brcmf_stats { + u32 tx_ctlpkts; + u32 tx_ctlerrs; + u32 rx_ctlpkts; + u32 rx_ctlerrs; +}; + +struct brcmf_usbdev { + struct brcmf_bus *bus; + struct brcmf_usbdev_info *devinfo; + enum brcmf_usb_state state; + struct brcmf_stats stats; + int ntxq, nrxq, rxsize; + u32 bus_mtu; + int devid; + int chiprev; /* chip revsion number */ +}; + +/* IO Request Block (IRB) */ +struct brcmf_usbreq { + struct list_head list; + struct brcmf_usbdev_info *devinfo; + struct urb *urb; + struct sk_buff *skb; +}; + +#endif /* BRCMFMAC_USB_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h new file mode 100644 index 000000000000..0a35c51c3da2 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _USB_RDL_H +#define _USB_RDL_H + +/* Control messages: bRequest values */ +#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ +#define DL_CHECK_CRC 1 /* currently unused */ +#define DL_GO 2 /* execute downloaded image */ +#define DL_START 3 /* initialize dl state */ +#define DL_REBOOT 4 /* reboot the device in 2 seconds */ +#define DL_GETVER 5 /* returns the bootrom_id_t struct */ +#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset + * event to occur in 2 seconds. It is the + * responsibility of the downloaded code to + * clear this event + */ +#define DL_EXEC 7 /* jump to a supplied address */ +#define DL_RESETCFG 8 /* To support single enum on dongle + * - Not used by bootloader + */ +#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup + * if resp unavailable + */ + +/* states */ +#define DL_WAITING 0 /* waiting to rx first pkt */ +#define DL_READY 1 /* hdr was good, waiting for more of the + * compressed image */ +#define DL_BAD_HDR 2 /* hdr was corrupted */ +#define DL_BAD_CRC 3 /* compressed image was corrupted */ +#define DL_RUNNABLE 4 /* download was successful,waiting for go cmd */ +#define DL_START_FAIL 5 /* failed to initialize correctly */ +#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM + * value */ +#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START + * for rdl) */ + +struct rdl_state_le { + __le32 state; + __le32 bytes; +}; + +struct bootrom_id_le { + __le32 chip; /* Chip id */ + __le32 chiprev; /* Chip rev */ + __le32 ramsize; /* Size of RAM */ + __le32 remapbase; /* Current remap base address */ + __le32 boardtype; /* Type of board */ + __le32 boardrev; /* Board revision */ +}; + +#define RDL_CHUNK 1500 /* size of each dl transfer */ + +#define TRX_OFFSETS_DLFWLEN_IDX 0 +#define TRX_OFFSETS_JUMPTO_IDX 1 +#define TRX_OFFSETS_NVM_LEN_IDX 2 + +#define TRX_OFFSETS_DLBASE_IDX 0 + +#endif /* _USB_RDL_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index bf11850a20f1..d13ae9c299f2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -16,6 +16,8 @@ /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/if_arp.h> #include <linux/sched.h> @@ -1374,7 +1376,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, memset(&join_params, 0, sizeof(join_params)); join_params_size = sizeof(join_params.ssid_le); - ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len); + ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), (u32)sme->ssid_len); memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len); memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len); join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); @@ -2001,7 +2003,6 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, s32 err = 0; u16 channel; u32 freq; - u64 notify_timestamp; u16 notify_capability; u16 notify_interval; u8 *notify_ie; @@ -2024,7 +2025,6 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, freq = ieee80211_channel_to_frequency(channel, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); - notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ notify_capability = le16_to_cpu(bi->capability); notify_interval = le16_to_cpu(bi->beacon_period); notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); @@ -2038,10 +2038,9 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, WL_CONN("Capability: %X\n", notify_capability); WL_CONN("Beacon interval: %d\n", notify_interval); WL_CONN("Signal: %d\n", notify_signal); - WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, - notify_timestamp, notify_capability, notify_interval, notify_ie, + 0, notify_capability, notify_interval, notify_ie, notify_ielen, notify_signal, GFP_KERNEL); if (!bss) @@ -2096,7 +2095,6 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, s32 err = 0; u16 channel; u32 freq; - u64 notify_timestamp; u16 notify_capability; u16 notify_interval; u8 *notify_ie; @@ -2132,7 +2130,6 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, freq = ieee80211_channel_to_frequency(channel, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); - notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ notify_capability = le16_to_cpu(bi->capability); notify_interval = le16_to_cpu(bi->beacon_period); notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); @@ -2143,10 +2140,9 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, WL_CONN("capability: %X\n", notify_capability); WL_CONN("beacon interval: %d\n", notify_interval); WL_CONN("signal: %d\n", notify_signal); - WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, - notify_timestamp, notify_capability, notify_interval, + 0, notify_capability, notify_interval, notify_ie, notify_ielen, notify_signal, GFP_KERNEL); if (!bss) { @@ -2783,7 +2779,7 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_priv) + sizeof_iface); if (!wdev->wiphy) { - WL_ERR("Couldn not allocate wiphy device\n"); + WL_ERR("Could not allocate wiphy device\n"); err = -ENOMEM; goto wiphy_new_out; } @@ -2809,7 +2805,7 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, */ err = wiphy_register(wdev->wiphy); if (err < 0) { - WL_ERR("Couldn not register wiphy device (%d)\n", err); + WL_ERR("Could not register wiphy device (%d)\n", err); goto wiphy_register_out; } return wdev; @@ -3295,7 +3291,9 @@ static struct brcmf_cfg80211_event_q *brcmf_deq_event( } /* -** push event to tail of the queue +* push event to tail of the queue +* +* remark: this function may not sleep as it is called in atomic context. */ static s32 @@ -3304,17 +3302,18 @@ brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, { struct brcmf_cfg80211_event_q *e; s32 err = 0; + ulong flags; - e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); + e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_ATOMIC); if (!e) return -ENOMEM; e->etype = event; memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); - spin_lock_irq(&cfg_priv->evt_q_lock); + spin_lock_irqsave(&cfg_priv->evt_q_lock, flags); list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list); - spin_unlock_irq(&cfg_priv->evt_q_lock); + spin_unlock_irqrestore(&cfg_priv->evt_q_lock, flags); return err; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index a613b49cb13f..b5d9b36df3d0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -32,63 +32,63 @@ struct brcmf_cfg80211_ibss; #define WL_DBG_MASK ((WL_DBG_INFO | WL_DBG_ERR | WL_DBG_TRACE) | \ (WL_DBG_SCAN) | (WL_DBG_CONN)) -#define WL_ERR(fmt, args...) \ +#define WL_ERR(fmt, ...) \ do { \ if (brcmf_dbg_level & WL_DBG_ERR) { \ if (net_ratelimit()) { \ - printk(KERN_ERR "ERROR @%s : " fmt, \ - __func__, ##args); \ + pr_err("ERROR @%s : " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } \ } while (0) -#if (defined BCMDBG) -#define WL_INFO(fmt, args...) \ +#if (defined DEBUG) +#define WL_INFO(fmt, ...) \ do { \ if (brcmf_dbg_level & WL_DBG_INFO) { \ if (net_ratelimit()) { \ - printk(KERN_ERR "INFO @%s : " fmt, \ - __func__, ##args); \ + pr_err("INFO @%s : " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } \ } while (0) -#define WL_TRACE(fmt, args...) \ +#define WL_TRACE(fmt, ...) \ do { \ if (brcmf_dbg_level & WL_DBG_TRACE) { \ if (net_ratelimit()) { \ - printk(KERN_ERR "TRACE @%s : " fmt, \ - __func__, ##args); \ + pr_err("TRACE @%s : " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } \ } while (0) -#define WL_SCAN(fmt, args...) \ +#define WL_SCAN(fmt, ...) \ do { \ if (brcmf_dbg_level & WL_DBG_SCAN) { \ if (net_ratelimit()) { \ - printk(KERN_ERR "SCAN @%s : " fmt, \ - __func__, ##args); \ + pr_err("SCAN @%s : " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } \ } while (0) -#define WL_CONN(fmt, args...) \ +#define WL_CONN(fmt, ...) \ do { \ if (brcmf_dbg_level & WL_DBG_CONN) { \ if (net_ratelimit()) { \ - printk(KERN_ERR "CONN @%s : " fmt, \ - __func__, ##args); \ + pr_err("CONN @%s : " fmt, \ + __func__, ##__VA_ARGS__); \ } \ } \ } while (0) -#else /* (defined BCMDBG) */ +#else /* (defined DEBUG) */ #define WL_INFO(fmt, args...) #define WL_TRACE(fmt, args...) #define WL_SCAN(fmt, args...) #define WL_CONN(fmt, args...) -#endif /* (defined BCMDBG) */ +#endif /* (defined DEBUG) */ #define WL_NUM_SCAN_MAX 1 #define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index ab9bb11abfbb..c93ea35bceec 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c @@ -326,11 +326,11 @@ #define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID)) -#ifdef BCMDBG +#ifdef DEBUG #define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) #else #define SI_MSG(fmt, ...) no_printk(fmt, ##__VA_ARGS__) -#endif /* BCMDBG */ +#endif /* DEBUG */ #define GOODCOREADDR(x, b) \ (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 90911eec0cf5..95b5902bc4b3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -915,7 +915,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p); struct wiphy *wiphy = wlc->wiphy; -#ifdef BCMDBG +#ifdef DEBUG u8 hole[AMPDU_MAX_MPDU]; memset(hole, 0, sizeof(hole)); #endif @@ -959,14 +959,13 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, if (supr_status) { update_rate = false; if (supr_status == TX_STATUS_SUPR_BADCH) { - wiphy_err(wiphy, "%s: Pkt tx suppressed, " - "illegal channel possibly %d\n", + wiphy_err(wiphy, + "%s: Pkt tx suppressed, illegal channel possibly %d\n", __func__, CHSPEC_CHANNEL( wlc->default_bss->chanspec)); } else { if (supr_status != TX_STATUS_SUPR_FRAG) - wiphy_err(wiphy, "%s:" - "supr_status 0x%x\n", + wiphy_err(wiphy, "%s: supr_status 0x%x\n", __func__, supr_status); } /* no need to retry for badch; will fail again */ @@ -988,9 +987,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, } } else if (txs->phyerr) { update_rate = false; - wiphy_err(wiphy, "wl%d: ampdu tx phy " - "error (0x%x)\n", wlc->pub->unit, - txs->phyerr); + wiphy_err(wiphy, "%s: ampdu tx phy error (0x%x)\n", + __func__, txs->phyerr); if (brcm_msg_level & LOG_ERROR_VAL) { brcmu_prpkt("txpkt (AMPDU)", p); @@ -1018,10 +1016,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, ack_recd = false; if (ba_recd) { bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX); - BCMMSG(wlc->wiphy, "tid %d seq %d," - " start_seq %d, bindex %d set %d, index %d\n", - tid, seq, start_seq, bindex, - isset(bitmap, bindex), index); + BCMMSG(wiphy, + "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n", + tid, seq, start_seq, bindex, + isset(bitmap, bindex), index); /* if acked then clear bit and free packet */ if ((bindex < AMPDU_TX_BA_MAX_WSIZE) && isset(bitmap, bindex)) { @@ -1051,17 +1049,13 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, } /* either retransmit or send bar if ack not recd */ if (!ack_recd) { - struct ieee80211_tx_rate *txrate = - tx_info->status.rates; - if (retry && (txrate[0].count < (int)retry_limit)) { + if (retry && (ini->txretry[index] < (int)retry_limit)) { ini->txretry[index]++; ini->tx_in_transit--; /* * Use high prededence for retransmit to * give some punch */ - /* brcms_c_txq_enq(wlc, scb, p, - * BRCMS_PRIO_TO_PREC(tid)); */ brcms_c_txq_enq(wlc, scb, p, BRCMS_PRIO_TO_HI_PREC(tid)); } else { @@ -1074,9 +1068,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, IEEE80211_TX_STAT_AMPDU_NO_BACK; skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_TXH_LEN); - wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_" - "transit %d\n", "AMPDU status", seq, - ini->tx_in_transit); + BCMMSG(wiphy, + "BA Timeout, seq %d, in_transit %d\n", + seq, ini->tx_in_transit); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 2e90a9a16ed6..11054ae9d4f6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -177,7 +177,7 @@ #define BCMEXTRAHDROOM 172 /* debug/trace */ -#ifdef BCMDBG +#ifdef DEBUG #define DMA_ERROR(fmt, ...) \ do { \ if (*di->msg_level & 1) \ @@ -193,7 +193,7 @@ do { \ no_printk(fmt, ##__VA_ARGS__) #define DMA_TRACE(fmt, ...) \ no_printk(fmt, ##__VA_ARGS__) -#endif /* BCMDBG */ +#endif /* DEBUG */ #define DMA_NONE(fmt, ...) \ no_printk(fmt, ##__VA_ARGS__) @@ -968,7 +968,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) pktcnt++; } -#ifdef BCMDBG +#ifdef DEBUG if (resid > 0) { uint cur; cur = @@ -979,7 +979,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) DMA_ERROR("rxin %d rxout %d, hw_curr %d\n", di->rxin, di->rxout, cur); } -#endif /* BCMDBG */ +#endif /* DEBUG */ if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { DMA_ERROR("%s: bad frame length (%d)\n", diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 448ab9c4eb47..569ab8abd2a1 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -15,6 +15,7 @@ */ #define __UNDEF_NO_VERSION__ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/etherdevice.h> #include <linux/sched.h> @@ -96,10 +97,10 @@ static struct bcma_device_id brcms_coreid_table[] = { }; MODULE_DEVICE_TABLE(bcma, brcms_coreid_table); -#ifdef BCMDBG +#ifdef DEBUG static int msglevel = 0xdeadbeef; module_param(msglevel, int, 0); -#endif /* BCMDBG */ +#endif /* DEBUG */ static struct ieee80211_channel brcms_2ghz_chantable[] = { CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS), @@ -857,7 +858,7 @@ static void brcms_free(struct brcms_info *wl) /* free timers */ for (t = wl->timers; t; t = next) { next = t->next; -#ifdef BCMDBG +#ifdef DEBUG kfree(t->name); #endif kfree(t); @@ -1121,8 +1122,7 @@ static int __devinit brcms_bcma_probe(struct bcma_device *pdev) wl = brcms_attach(pdev); if (!wl) { - pr_err("%s: %s: brcms_attach failed!\n", KBUILD_MODNAME, - __func__); + pr_err("%s: brcms_attach failed!\n", __func__); return -ENODEV; } return 0; @@ -1136,8 +1136,8 @@ static int brcms_suspend(struct bcma_device *pdev) hw = bcma_get_drvdata(pdev); wl = hw->priv; if (!wl) { - wiphy_err(wl->wiphy, - "brcms_suspend: bcma_get_drvdata failed\n"); + pr_err("%s: %s: no driver private struct!\n", KBUILD_MODNAME, + __func__); return -ENODEV; } @@ -1169,25 +1169,31 @@ static struct bcma_driver brcms_bcma_driver = { /** * This is the main entry point for the brcmsmac driver. * - * This function determines if a device pointed to by pdev is a WL device, - * and if so, performs a brcms_attach() on it. - * + * This function is scheduled upon module initialization and + * does the driver registration, which result in brcms_bcma_probe() + * call resulting in the driver bringup. */ -static int __init brcms_module_init(void) +static void brcms_driver_init(struct work_struct *work) { - int error = -ENODEV; + int error; + + error = bcma_driver_register(&brcms_bcma_driver); + if (error) + pr_err("%s: register returned %d\n", __func__, error); +} -#ifdef BCMDBG +static DECLARE_WORK(brcms_driver_work, brcms_driver_init); + +static int __init brcms_module_init(void) +{ +#ifdef DEBUG if (msglevel != 0xdeadbeef) brcm_msg_level = msglevel; -#endif /* BCMDBG */ - - error = bcma_driver_register(&brcms_bcma_driver); - printk(KERN_ERR "%s: register returned %d\n", __func__, error); - if (!error) - return 0; +#endif + if (!schedule_work(&brcms_driver_work)) + return -EBUSY; - return error; + return 0; } /** @@ -1199,6 +1205,7 @@ static int __init brcms_module_init(void) */ static void __exit brcms_module_exit(void) { + cancel_work_sync(&brcms_driver_work); bcma_driver_unregister(&brcms_bcma_driver); } @@ -1367,7 +1374,7 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl, t->next = wl->timers; wl->timers = t; -#ifdef BCMDBG +#ifdef DEBUG t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); if (t->name) strcpy(t->name, name); @@ -1386,7 +1393,7 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) { struct ieee80211_hw *hw = t->wl->pub->ieee_hw; -#ifdef BCMDBG +#ifdef DEBUG if (t->set) wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n", __func__, t->name, periodic); @@ -1431,7 +1438,7 @@ void brcms_free_timer(struct brcms_timer *t) if (wl->timers == t) { wl->timers = wl->timers->next; -#ifdef BCMDBG +#ifdef DEBUG kfree(t->name); #endif kfree(t); @@ -1443,7 +1450,7 @@ void brcms_free_timer(struct brcms_timer *t) while (tmp) { if (tmp->next == t) { tmp->next = t->next; -#ifdef BCMDBG +#ifdef DEBUG kfree(t->name); #endif kfree(t); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 8f60419c37bf..9358bd5ebd35 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h @@ -40,7 +40,7 @@ struct brcms_timer { bool periodic; bool set; /* indicates if timer is active */ struct brcms_timer *next; /* for freeing on unload */ -#ifdef BCMDBG +#ifdef DEBUG char *name; /* Description of the timer */ #endif }; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index f6affc6fd12a..231ddf4a674f 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -14,6 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/pci_ids.h> #include <linux/if_ether.h> #include <net/mac80211.h> @@ -293,11 +295,11 @@ const u8 prio2fifo[NUMPRIO] = { /* debug/trace */ uint brcm_msg_level = -#if defined(BCMDBG) +#if defined(DEBUG) LOG_ERROR_VAL; #else 0; -#endif /* BCMDBG */ +#endif /* DEBUG */ /* TX FIFO number to WME/802.1E Access Category */ static const u8 wme_fifo2ac[] = { @@ -342,14 +344,14 @@ static const u16 xmtfifo_sz[][NFIFO] = { {9, 58, 22, 14, 14, 5}, }; -#ifdef BCMDBG +#ifdef DEBUG static const char * const fifo_names[] = { "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" }; #else static const char fifo_names[6][0]; #endif -#ifdef BCMDBG +#ifdef DEBUG /* pointer to most recently allocated wl/wlc */ static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL); #endif @@ -2899,7 +2901,6 @@ brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel) objoff += 2; return bcma_read16(core, objoff); -; } static void @@ -3075,30 +3076,30 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc) { int i; struct macstat macstats; -#ifdef BCMDBG +#ifdef DEBUG u16 delta; u16 rxf0ovfl; u16 txfunfl[NFIFO]; -#endif /* BCMDBG */ +#endif /* DEBUG */ /* if driver down, make no sense to update stats */ if (!wlc->pub->up) return; -#ifdef BCMDBG +#ifdef DEBUG /* save last rx fifo 0 overflow count */ rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl; /* save last tx fifo underflow count */ for (i = 0; i < NFIFO; i++) txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i]; -#endif /* BCMDBG */ +#endif /* DEBUG */ /* Read mac stats from contiguous shared memory */ brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats, sizeof(struct macstat), OBJADDR_SHM_SEL); -#ifdef BCMDBG +#ifdef DEBUG /* check for rx fifo 0 overflow */ delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl); if (delta) @@ -3114,7 +3115,7 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc) wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!" "\n", wlc->pub->unit, delta, i); } -#endif /* BCMDBG */ +#endif /* DEBUG */ /* merge counters from dma module */ for (i = 0; i < NFIFO; i++) { @@ -3246,7 +3247,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) } /* For old ucode, txfifo sizes needs to be modified(increased) */ - if (fifosz_fixup == true) + if (fifosz_fixup) brcms_b_corerev_fifofixup(wlc_hw); /* check txfifo allocations match between ucode and driver */ @@ -5425,7 +5426,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) return -EINVAL; /* update configuration value */ - if (config == true) + if (config) brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); /* Clear rateset override */ @@ -5765,62 +5766,49 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, return -ENODATA; } -#ifdef BCMDBG -static const char * const supr_reason[] = { - "None", "PMQ Entry", "Flush request", - "Previous frag failure", "Channel mismatch", - "Lifetime Expiry", "Underflow" -}; - -static void brcms_c_print_txs_status(u16 s) -{ - printk(KERN_DEBUG "[15:12] %d frame attempts\n", - (s & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT); - printk(KERN_DEBUG " [11:8] %d rts attempts\n", - (s & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT); - printk(KERN_DEBUG " [7] %d PM mode indicated\n", - ((s & TX_STATUS_PMINDCTD) ? 1 : 0)); - printk(KERN_DEBUG " [6] %d intermediate status\n", - ((s & TX_STATUS_INTERMEDIATE) ? 1 : 0)); - printk(KERN_DEBUG " [5] %d AMPDU\n", - (s & TX_STATUS_AMPDU) ? 1 : 0); - printk(KERN_DEBUG " [4:2] %d Frame Suppressed Reason (%s)\n", - ((s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT), - supr_reason[(s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT]); - printk(KERN_DEBUG " [1] %d acked\n", - ((s & TX_STATUS_ACK_RCV) ? 1 : 0)); -} -#endif /* BCMDBG */ - void brcms_c_print_txstatus(struct tx_status *txs) { -#if defined(BCMDBG) - u16 s = txs->status; - u16 ackphyrxsh = txs->ackphyrxsh; - - printk(KERN_DEBUG "\ntxpkt (MPDU) Complete\n"); - - printk(KERN_DEBUG "FrameID: %04x ", txs->frameid); - printk(KERN_DEBUG "TxStatus: %04x", s); - printk(KERN_DEBUG "\n"); - - brcms_c_print_txs_status(s); - - printk(KERN_DEBUG "LastTxTime: %04x ", txs->lasttxtime); - printk(KERN_DEBUG "Seq: %04x ", txs->sequence); - printk(KERN_DEBUG "PHYTxStatus: %04x ", txs->phyerr); - printk(KERN_DEBUG "RxAckRSSI: %04x ", - (ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT); - printk(KERN_DEBUG "RxAckSQ: %04x", - (ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); - printk(KERN_DEBUG "\n"); -#endif /* defined(BCMDBG) */ + pr_debug("\ntxpkt (MPDU) Complete\n"); + + pr_debug("FrameID: %04x TxStatus: %04x\n", txs->frameid, txs->status); + + pr_debug("[15:12] %d frame attempts\n", + (txs->status & TX_STATUS_FRM_RTX_MASK) >> + TX_STATUS_FRM_RTX_SHIFT); + pr_debug(" [11:8] %d rts attempts\n", + (txs->status & TX_STATUS_RTS_RTX_MASK) >> + TX_STATUS_RTS_RTX_SHIFT); + pr_debug(" [7] %d PM mode indicated\n", + txs->status & TX_STATUS_PMINDCTD ? 1 : 0); + pr_debug(" [6] %d intermediate status\n", + txs->status & TX_STATUS_INTERMEDIATE ? 1 : 0); + pr_debug(" [5] %d AMPDU\n", + txs->status & TX_STATUS_AMPDU ? 1 : 0); + pr_debug(" [4:2] %d Frame Suppressed Reason (%s)\n", + (txs->status & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT, + (const char *[]) { + "None", + "PMQ Entry", + "Flush request", + "Previous frag failure", + "Channel mismatch", + "Lifetime Expiry", + "Underflow" + } [(txs->status & TX_STATUS_SUPR_MASK) >> + TX_STATUS_SUPR_SHIFT]); + pr_debug(" [1] %d acked\n", + txs->status & TX_STATUS_ACK_RCV ? 1 : 0); + + pr_debug("LastTxTime: %04x Seq: %04x PHYTxStatus: %04x RxAckRSSI: %04x RxAckSQ: %04x\n", + txs->lasttxtime, txs->sequence, txs->phyerr, + (txs->ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT, + (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); } bool brcms_c_chipmatch(u16 vendor, u16 device) { if (vendor != PCI_VENDOR_ID_BROADCOM) { - pr_err("chipmatch: unknown vendor id %04x\n", vendor); + pr_err("unknown vendor id %04x\n", vendor); return false; } @@ -5833,11 +5821,11 @@ bool brcms_c_chipmatch(u16 vendor, u16 device) if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID)) return true; - pr_err("chipmatch: unknown device id %04x\n", device); + pr_err("unknown device id %04x\n", device); return false; } -#if defined(BCMDBG) +#if defined(DEBUG) void brcms_c_print_txdesc(struct d11txh *txh) { u16 mtcl = le16_to_cpu(txh->MacTxControlLow); @@ -5871,57 +5859,56 @@ void brcms_c_print_txdesc(struct d11txh *txh) struct ieee80211_rts rts = txh->rts_frame; /* add plcp header along with txh descriptor */ - printk(KERN_DEBUG "Raw TxDesc + plcp header:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - txh, sizeof(struct d11txh) + 48); - - printk(KERN_DEBUG "TxCtlLow: %04x ", mtcl); - printk(KERN_DEBUG "TxCtlHigh: %04x ", mtch); - printk(KERN_DEBUG "FC: %04x ", mfc); - printk(KERN_DEBUG "FES Time: %04x\n", tfest); - printk(KERN_DEBUG "PhyCtl: %04x%s ", ptcw, + brcmu_dbg_hex_dump(txh, sizeof(struct d11txh) + 48, + "Raw TxDesc + plcp header:\n"); + + pr_debug("TxCtlLow: %04x ", mtcl); + pr_debug("TxCtlHigh: %04x ", mtch); + pr_debug("FC: %04x ", mfc); + pr_debug("FES Time: %04x\n", tfest); + pr_debug("PhyCtl: %04x%s ", ptcw, (ptcw & PHY_TXC_SHORT_HDR) ? " short" : ""); - printk(KERN_DEBUG "PhyCtl_1: %04x ", ptcw_1); - printk(KERN_DEBUG "PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr); - printk(KERN_DEBUG "PhyCtl_1_Rts: %04x ", ptcw_1_Rts); - printk(KERN_DEBUG "PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts); - printk(KERN_DEBUG "MainRates: %04x ", mainrates); - printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft); - printk(KERN_DEBUG "\n"); + pr_debug("PhyCtl_1: %04x ", ptcw_1); + pr_debug("PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr); + pr_debug("PhyCtl_1_Rts: %04x ", ptcw_1_Rts); + pr_debug("PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts); + pr_debug("MainRates: %04x ", mainrates); + pr_debug("XtraFrameTypes: %04x ", xtraft); + pr_debug("\n"); print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV)); print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET, ra, sizeof(txh->TxFrameRA)); - printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb); + pr_debug("Fb FES Time: %04x ", tfestfb); print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET, rtspfb, sizeof(txh->RTSPLCPFallback)); - printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb); + pr_debug("RTS DUR: %04x ", rtsdfb); print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET, fragpfb, sizeof(txh->FragPLCPFallback)); - printk(KERN_DEBUG "DUR: %04x", fragdfb); - printk(KERN_DEBUG "\n"); + pr_debug("DUR: %04x", fragdfb); + pr_debug("\n"); - printk(KERN_DEBUG "MModeLen: %04x ", mmodelen); - printk(KERN_DEBUG "MModeFbrLen: %04x\n", mmodefbrlen); + pr_debug("MModeLen: %04x ", mmodelen); + pr_debug("MModeFbrLen: %04x\n", mmodefbrlen); - printk(KERN_DEBUG "FrameID: %04x\n", tfid); - printk(KERN_DEBUG "TxStatus: %04x\n", txs); + pr_debug("FrameID: %04x\n", tfid); + pr_debug("TxStatus: %04x\n", txs); - printk(KERN_DEBUG "MaxNumMpdu: %04x\n", mnmpdu); - printk(KERN_DEBUG "MaxAggbyte: %04x\n", mabyte); - printk(KERN_DEBUG "MaxAggbyte_fb: %04x\n", mabyte_f); - printk(KERN_DEBUG "MinByte: %04x\n", mmbyte); + pr_debug("MaxNumMpdu: %04x\n", mnmpdu); + pr_debug("MaxAggbyte: %04x\n", mabyte); + pr_debug("MaxAggbyte_fb: %04x\n", mabyte_f); + pr_debug("MinByte: %04x\n", mmbyte); print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET, rtsph, sizeof(txh->RTSPhyHeader)); print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET, (u8 *)&rts, sizeof(txh->rts_frame)); - printk(KERN_DEBUG "\n"); + pr_debug("\n"); } -#endif /* defined(BCMDBG) */ +#endif /* defined(DEBUG) */ -#if defined(BCMDBG) +#if defined(DEBUG) static int brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf, int len) @@ -5975,9 +5962,9 @@ brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf, return (int)(p - buf); } -#endif /* defined(BCMDBG) */ +#endif /* defined(DEBUG) */ -#if defined(BCMDBG) +#if defined(DEBUG) void brcms_c_print_rxh(struct d11rxhdr *rxh) { u16 len = rxh->RxFrameSize; @@ -5999,24 +5986,22 @@ void brcms_c_print_rxh(struct d11rxhdr *rxh) {0, NULL} }; - printk(KERN_DEBUG "Raw RxDesc:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, rxh, - sizeof(struct d11rxhdr)); + brcmu_dbg_hex_dump(rxh, sizeof(struct d11rxhdr), "Raw RxDesc:\n"); brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64); snprintf(lenbuf, sizeof(lenbuf), "0x%x", len); - printk(KERN_DEBUG "RxFrameSize: %6s (%d)%s\n", lenbuf, len, + pr_debug("RxFrameSize: %6s (%d)%s\n", lenbuf, len, (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : ""); - printk(KERN_DEBUG "RxPHYStatus: %04x %04x %04x %04x\n", + pr_debug("RxPHYStatus: %04x %04x %04x %04x\n", phystatus_0, phystatus_1, phystatus_2, phystatus_3); - printk(KERN_DEBUG "RxMACStatus: %x %s\n", macstatus1, flagstr); - printk(KERN_DEBUG "RXMACaggtype: %x\n", + pr_debug("RxMACStatus: %x %s\n", macstatus1, flagstr); + pr_debug("RXMACaggtype: %x\n", (macstatus2 & RXS_AGGTYPE_MASK)); - printk(KERN_DEBUG "RxTSFTime: %04x\n", rxh->RxTSFTime); + pr_debug("RxTSFTime: %04x\n", rxh->RxTSFTime); } -#endif /* defined(BCMDBG) */ +#endif /* defined(DEBUG) */ u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate) { @@ -8354,7 +8339,7 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit, wlc->wiphy = wl->wiphy; pub = wlc->pub; -#if defined(BCMDBG) +#if defined(DEBUG) wlc_info_dbg = wlc; #endif diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h index adb136ec1f04..8debc74c54e1 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -648,10 +648,12 @@ extern void brcms_c_print_txstatus(struct tx_status *txs); extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, uint *blocks); -#if defined(BCMDBG) +#if defined(DEBUG) extern void brcms_c_print_txdesc(struct d11txh *txh); #else -#define brcms_c_print_txdesc(a) +static inline void brcms_c_print_txdesc(struct d11txh *txh) +{ +} #endif extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index a16f1ab292fd..39095741fd05 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -14,6 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/delay.h> #include <linux/cordic.h> @@ -17822,8 +17824,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) if (pi->sh->sromrev < 4) { idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; - target_pwr_qtrdbm[0] = 13 * 4; - target_pwr_qtrdbm[1] = 13 * 4; a1[0] = -424; a1[1] = -424; b0[0] = 5612; @@ -17837,10 +17837,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) case WL_CHAN_FREQ_RANGE_2G: idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; - target_pwr_qtrdbm[0] = - pi->nphy_pwrctrl_info[0].max_pwr_2g; - target_pwr_qtrdbm[1] = - pi->nphy_pwrctrl_info[1].max_pwr_2g; a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1; a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1; b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0; @@ -17851,10 +17847,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) case WL_CHAN_FREQ_RANGE_5GL: idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; - target_pwr_qtrdbm[0] = - pi->nphy_pwrctrl_info[0].max_pwr_5gl; - target_pwr_qtrdbm[1] = - pi->nphy_pwrctrl_info[1].max_pwr_5gl; a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1; a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1; b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0; @@ -17865,10 +17857,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) case WL_CHAN_FREQ_RANGE_5GM: idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; - target_pwr_qtrdbm[0] = - pi->nphy_pwrctrl_info[0].max_pwr_5gm; - target_pwr_qtrdbm[1] = - pi->nphy_pwrctrl_info[1].max_pwr_5gm; a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1; a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1; b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0; @@ -17879,10 +17867,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) case WL_CHAN_FREQ_RANGE_5GH: idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; - target_pwr_qtrdbm[0] = - pi->nphy_pwrctrl_info[0].max_pwr_5gh; - target_pwr_qtrdbm[1] = - pi->nphy_pwrctrl_info[1].max_pwr_5gh; a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1; a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1; b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0; @@ -17893,8 +17877,6 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) default: idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; - target_pwr_qtrdbm[0] = 13 * 4; - target_pwr_qtrdbm[1] = 13 * 4; a1[0] = -424; a1[1] = -424; b0[0] = 5612; @@ -17905,6 +17887,7 @@ static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) } } + /* use the provided transmit power */ target_pwr_qtrdbm[0] = (s8) pi->tx_power_max; target_pwr_qtrdbm[1] = (s8) pi->tx_power_max; @@ -19987,12 +19970,11 @@ static void wlc_phy_radio_init_2057(struct brcms_phy *pi) switch (pi->pubpi.radiorev) { case 5: - if (pi->pubpi.radiover == 0x0) + if (NREV_IS(pi->pubpi.phy_rev, 8)) regs_2057_ptr = regs_2057_rev5; - else if (pi->pubpi.radiover == 0x1) + else if (NREV_IS(pi->pubpi.phy_rev, 9)) regs_2057_ptr = regs_2057_rev5v1; - else - break; + break; case 7: @@ -21462,7 +21444,7 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) if (NREV_GE(pi->pubpi.phy_rev, 3)) { u16 v0 = 0x211, v1 = 0x222, v2 = 0x144, v3 = 0x188; - if (lut_init == false) + if (!lut_init) return; if (pi->srom_fem2g.antswctrllut == 0) { @@ -26434,8 +26416,7 @@ cal_try: } if (bcmerror != 0) { - printk(KERN_DEBUG "%s: Failed, cnt = %d\n", __func__, - cal_retry); + pr_debug("%s: Failed, cnt = %d\n", __func__, cal_retry); if (cal_retry < CAL_RETRY_CNT) { cal_retry++; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c index 563743643038..b96f4b9d74bd 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c @@ -621,7 +621,7 @@ static inline void cpu_to_le16_buf(u16 *buf, uint nwords) /* * convert binary srom data into linked list of srom variable items. */ -static void +static int _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) { struct brcms_srom_list_head *entry; @@ -638,6 +638,9 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) /* first store the srom revision */ entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->varid = BRCMS_SROM_REV; entry->var_type = BRCMS_SROM_UNUMBER; entry->uval = sromrev; @@ -715,6 +718,8 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) entry = kzalloc(sizeof(struct brcms_srom_list_head) + extra_space, GFP_KERNEL); + if (!entry) + return -ENOMEM; entry->varid = id; entry->var_type = type; if (flags & SRFL_ETHADDR) { @@ -754,6 +759,8 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL); + if (!entry) + return -ENOMEM; entry->varid = srv->varid+p; entry->var_type = BRCMS_SROM_UNUMBER; entry->uval = val; @@ -761,6 +768,7 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) } pb += psz; } + return 0; } /* @@ -906,7 +914,9 @@ int srom_var_init(struct si_pub *sih) INIT_LIST_HEAD(&sii->var_list); /* parse SROM into name=value pairs. */ - _initvars_srom_pci(sromrev, srom, &sii->var_list); + err = _initvars_srom_pci(sromrev, srom, &sii->var_list); + if (err) + srom_free_vars(sih); } errout: diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c index b7537f70a795..b45ab34cdfdc 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c @@ -14,6 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/netdevice.h> #include <linux/module.h> @@ -240,17 +242,35 @@ struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, } EXPORT_SYMBOL(brcmu_pktq_mdeq); -#if defined(BCMDBG) +#if defined(DEBUG) /* pretty hex print a pkt buffer chain */ void brcmu_prpkt(const char *msg, struct sk_buff *p0) { struct sk_buff *p; if (msg && (msg[0] != '\0')) - printk(KERN_DEBUG "%s:\n", msg); + pr_debug("%s:\n", msg); for (p = p0; p; p = p->next) print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len); } EXPORT_SYMBOL(brcmu_prpkt); -#endif /* defined(BCMDBG) */ + +void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + pr_debug("%pV", &vaf); + + va_end(args); + + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, size); +} +EXPORT_SYMBOL(brcmu_dbg_hex_dump); +#endif /* defined(DEBUG) */ diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index ad249a0b4730..477b92ad3d62 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -176,10 +176,21 @@ struct ipv4_addr; /* externs */ /* format/print */ -#ifdef BCMDBG +#ifdef DEBUG extern void brcmu_prpkt(const char *msg, struct sk_buff *p0); #else #define brcmu_prpkt(a, b) -#endif /* BCMDBG */ +#endif /* DEBUG */ + +#ifdef DEBUG +extern __printf(3, 4) +void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...); +#else +__printf(3, 4) +static inline +void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) +{ +} +#endif #endif /* _BRCMU_UTILS_H_ */ |