diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2015-11-17 18:09:02 (GMT) |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-11-18 12:28:30 (GMT) |
commit | 560424e9a979a7b460055bda497bb4522ba5cc87 (patch) | |
tree | 53d3a3fb2beb0df84a3933934243249e71021c7c /drivers/net/wireless/cw1200 | |
parent | 05491d2ccf20b20a1375303441fbbfbd12b24a4f (diff) | |
download | linux-560424e9a979a7b460055bda497bb4522ba5cc87.tar.xz |
cw1200: move under st vendor directory
Part of reorganising wireless drivers directory and Kconfig.
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/cw1200')
27 files changed, 0 insertions, 13622 deletions
diff --git a/drivers/net/wireless/cw1200/Kconfig b/drivers/net/wireless/cw1200/Kconfig deleted file mode 100644 index 0880742..0000000 --- a/drivers/net/wireless/cw1200/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config CW1200 - tristate "CW1200 WLAN support" - depends on MAC80211 && CFG80211 - help - This is a driver for the ST-E CW1100 & CW1200 WLAN chipsets. - This option just enables the driver core, see below for - specific bus support. - -if CW1200 - -config CW1200_WLAN_SDIO - tristate "Support SDIO platforms" - depends on CW1200 && MMC - help - Enable support for the CW1200 connected via an SDIO bus. - By default this driver only supports the Sagrad SG901-1091/1098 EVK - and similar designs that utilize a hardware reset circuit. To - support different CW1200 SDIO designs you will need to override - the default platform data by calling cw1200_sdio_set_platform_data() - in your board setup file. - -config CW1200_WLAN_SPI - tristate "Support SPI platforms" - depends on CW1200 && SPI - help - Enables support for the CW1200 connected via a SPI bus. You will - need to add appropriate platform data glue in your board setup - file. - -endif diff --git a/drivers/net/wireless/cw1200/Makefile b/drivers/net/wireless/cw1200/Makefile deleted file mode 100644 index b086aac..0000000 --- a/drivers/net/wireless/cw1200/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -cw1200_core-y := \ - fwio.o \ - txrx.o \ - main.o \ - queue.o \ - hwio.o \ - bh.o \ - wsm.o \ - sta.o \ - scan.o \ - debug.o -cw1200_core-$(CONFIG_PM) += pm.o - -# CFLAGS_sta.o += -DDEBUG - -cw1200_wlan_sdio-y := cw1200_sdio.o -cw1200_wlan_spi-y := cw1200_spi.o - -obj-$(CONFIG_CW1200) += cw1200_core.o -obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o -obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o diff --git a/drivers/net/wireless/cw1200/bh.c b/drivers/net/wireless/cw1200/bh.c deleted file mode 100644 index 92d299a..0000000 --- a/drivers/net/wireless/cw1200/bh.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on: - * ST-Ericsson UMAC CW1200 driver, which is - * Copyright (c) 2010, ST-Ericsson - * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <net/mac80211.h> -#include <linux/kthread.h> -#include <linux/timer.h> - -#include "cw1200.h" -#include "bh.h" -#include "hwio.h" -#include "wsm.h" -#include "hwbus.h" -#include "debug.h" -#include "fwio.h" - -static int cw1200_bh(void *arg); - -#define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4) -/* an SPI message cannot be bigger than (2"12-1)*2 bytes - * "*2" to cvt to bytes - */ -#define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) -#define PIGGYBACK_CTRL_REG (2) -#define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) - -/* Suspend state privates */ -enum cw1200_bh_pm_state { - CW1200_BH_RESUMED = 0, - CW1200_BH_SUSPEND, - CW1200_BH_SUSPENDED, - CW1200_BH_RESUME, -}; - -typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv, - u8 *data, size_t size); - -static void cw1200_bh_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, bh_work); - cw1200_bh(priv); -} - -int cw1200_register_bh(struct cw1200_common *priv) -{ - int err = 0; - /* Realtime workqueue */ - priv->bh_workqueue = alloc_workqueue("cw1200_bh", - WQ_MEM_RECLAIM | WQ_HIGHPRI - | WQ_CPU_INTENSIVE, 1); - - if (!priv->bh_workqueue) - return -ENOMEM; - - INIT_WORK(&priv->bh_work, cw1200_bh_work); - - pr_debug("[BH] register.\n"); - - atomic_set(&priv->bh_rx, 0); - atomic_set(&priv->bh_tx, 0); - atomic_set(&priv->bh_term, 0); - atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); - priv->bh_error = 0; - priv->hw_bufs_used = 0; - priv->buf_id_tx = 0; - priv->buf_id_rx = 0; - init_waitqueue_head(&priv->bh_wq); - init_waitqueue_head(&priv->bh_evt_wq); - - err = !queue_work(priv->bh_workqueue, &priv->bh_work); - WARN_ON(err); - return err; -} - -void cw1200_unregister_bh(struct cw1200_common *priv) -{ - atomic_add(1, &priv->bh_term); - wake_up(&priv->bh_wq); - - flush_workqueue(priv->bh_workqueue); - - destroy_workqueue(priv->bh_workqueue); - priv->bh_workqueue = NULL; - - pr_debug("[BH] unregistered.\n"); -} - -void cw1200_irq_handler(struct cw1200_common *priv) -{ - pr_debug("[BH] irq.\n"); - - /* Disable Interrupts! */ - /* NOTE: hwbus_ops->lock already held */ - __cw1200_irq_enable(priv, 0); - - if (/* WARN_ON */(priv->bh_error)) - return; - - if (atomic_add_return(1, &priv->bh_rx) == 1) - wake_up(&priv->bh_wq); -} -EXPORT_SYMBOL_GPL(cw1200_irq_handler); - -void cw1200_bh_wakeup(struct cw1200_common *priv) -{ - pr_debug("[BH] wakeup.\n"); - if (priv->bh_error) { - pr_err("[BH] wakeup failed (BH error)\n"); - return; - } - - if (atomic_add_return(1, &priv->bh_tx) == 1) - wake_up(&priv->bh_wq); -} - -int cw1200_bh_suspend(struct cw1200_common *priv) -{ - pr_debug("[BH] suspend.\n"); - if (priv->bh_error) { - wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n"); - return -EINVAL; - } - - atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND); - wake_up(&priv->bh_wq); - return wait_event_timeout(priv->bh_evt_wq, priv->bh_error || - (CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)), - 1 * HZ) ? 0 : -ETIMEDOUT; -} - -int cw1200_bh_resume(struct cw1200_common *priv) -{ - pr_debug("[BH] resume.\n"); - if (priv->bh_error) { - wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n"); - return -EINVAL; - } - - atomic_set(&priv->bh_suspend, CW1200_BH_RESUME); - wake_up(&priv->bh_wq); - return wait_event_timeout(priv->bh_evt_wq, priv->bh_error || - (CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)), - 1 * HZ) ? 0 : -ETIMEDOUT; -} - -static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv) -{ - ++priv->hw_bufs_used; -} - -int wsm_release_tx_buffer(struct cw1200_common *priv, int count) -{ - int ret = 0; - int hw_bufs_used = priv->hw_bufs_used; - - priv->hw_bufs_used -= count; - if (WARN_ON(priv->hw_bufs_used < 0)) - ret = -1; - else if (hw_bufs_used >= priv->wsm_caps.input_buffers) - ret = 1; - if (!priv->hw_bufs_used) - wake_up(&priv->bh_evt_wq); - return ret; -} - -static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv, - u16 *ctrl_reg) -{ - int ret; - - ret = cw1200_reg_read_16(priv, - ST90TDS_CONTROL_REG_ID, ctrl_reg); - if (ret) { - ret = cw1200_reg_read_16(priv, - ST90TDS_CONTROL_REG_ID, ctrl_reg); - if (ret) - pr_err("[BH] Failed to read control register.\n"); - } - - return ret; -} - -static int cw1200_device_wakeup(struct cw1200_common *priv) -{ - u16 ctrl_reg; - int ret; - - pr_debug("[BH] Device wakeup.\n"); - - /* First, set the dpll register */ - ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, - cw1200_dpll_from_clk(priv->hw_refclk)); - if (WARN_ON(ret)) - return ret; - - /* To force the device to be always-on, the host sets WLAN_UP to 1 */ - ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, - ST90TDS_CONT_WUP_BIT); - if (WARN_ON(ret)) - return ret; - - ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg); - if (WARN_ON(ret)) - return ret; - - /* If the device returns WLAN_RDY as 1, the device is active and will - * remain active. - */ - if (ctrl_reg & ST90TDS_CONT_RDY_BIT) { - pr_debug("[BH] Device awake.\n"); - return 1; - } - - return 0; -} - -/* Must be called from BH thraed. */ -void cw1200_enable_powersave(struct cw1200_common *priv, - bool enable) -{ - pr_debug("[BH] Powerave is %s.\n", - enable ? "enabled" : "disabled"); - priv->powersave_enabled = enable; -} - -static int cw1200_bh_rx_helper(struct cw1200_common *priv, - uint16_t *ctrl_reg, - int *tx) -{ - size_t read_len = 0; - struct sk_buff *skb_rx = NULL; - struct wsm_hdr *wsm; - size_t wsm_len; - u16 wsm_id; - u8 wsm_seq; - int rx_resync = 1; - - size_t alloc_len; - u8 *data; - - read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2; - if (!read_len) - return 0; /* No more work */ - - if (WARN_ON((read_len < sizeof(struct wsm_hdr)) || - (read_len > EFFECTIVE_BUF_SIZE))) { - pr_debug("Invalid read len: %zu (%04x)", - read_len, *ctrl_reg); - goto err; - } - - /* Add SIZE of PIGGYBACK reg (CONTROL Reg) - * to the NEXT Message length + 2 Bytes for SKB - */ - read_len = read_len + 2; - - alloc_len = priv->hwbus_ops->align_size( - priv->hwbus_priv, read_len); - - /* Check if not exceeding CW1200 capabilities */ - if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { - pr_debug("Read aligned len: %zu\n", - alloc_len); - } - - skb_rx = dev_alloc_skb(alloc_len); - if (WARN_ON(!skb_rx)) - goto err; - - skb_trim(skb_rx, 0); - skb_put(skb_rx, read_len); - data = skb_rx->data; - if (WARN_ON(!data)) - goto err; - - if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) { - pr_err("rx blew up, len %zu\n", alloc_len); - goto err; - } - - /* Piggyback */ - *ctrl_reg = __le16_to_cpu( - ((__le16 *)data)[alloc_len / 2 - 1]); - - wsm = (struct wsm_hdr *)data; - wsm_len = __le16_to_cpu(wsm->len); - if (WARN_ON(wsm_len > read_len)) - goto err; - - if (priv->wsm_enable_wsm_dumps) - print_hex_dump_bytes("<-- ", - DUMP_PREFIX_NONE, - data, wsm_len); - - wsm_id = __le16_to_cpu(wsm->id) & 0xFFF; - wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7; - - skb_trim(skb_rx, wsm_len); - - if (wsm_id == 0x0800) { - wsm_handle_exception(priv, - &data[sizeof(*wsm)], - wsm_len - sizeof(*wsm)); - goto err; - } else if (!rx_resync) { - if (WARN_ON(wsm_seq != priv->wsm_rx_seq)) - goto err; - } - priv->wsm_rx_seq = (wsm_seq + 1) & 7; - rx_resync = 0; - - if (wsm_id & 0x0400) { - int rc = wsm_release_tx_buffer(priv, 1); - if (WARN_ON(rc < 0)) - return rc; - else if (rc > 0) - *tx = 1; - } - - /* cw1200_wsm_rx takes care on SKB livetime */ - if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx))) - goto err; - - if (skb_rx) { - dev_kfree_skb(skb_rx); - skb_rx = NULL; - } - - return 0; - -err: - if (skb_rx) { - dev_kfree_skb(skb_rx); - skb_rx = NULL; - } - return -1; -} - -static int cw1200_bh_tx_helper(struct cw1200_common *priv, - int *pending_tx, - int *tx_burst) -{ - size_t tx_len; - u8 *data; - int ret; - struct wsm_hdr *wsm; - - if (priv->device_can_sleep) { - ret = cw1200_device_wakeup(priv); - if (WARN_ON(ret < 0)) { /* Error in wakeup */ - *pending_tx = 1; - return 0; - } else if (ret) { /* Woke up */ - priv->device_can_sleep = false; - } else { /* Did not awake */ - *pending_tx = 1; - return 0; - } - } - - wsm_alloc_tx_buffer(priv); - ret = wsm_get_tx(priv, &data, &tx_len, tx_burst); - if (ret <= 0) { - wsm_release_tx_buffer(priv, 1); - if (WARN_ON(ret < 0)) - return ret; /* Error */ - return 0; /* No work */ - } - - wsm = (struct wsm_hdr *)data; - BUG_ON(tx_len < sizeof(*wsm)); - BUG_ON(__le16_to_cpu(wsm->len) != tx_len); - - atomic_add(1, &priv->bh_tx); - - tx_len = priv->hwbus_ops->align_size( - priv->hwbus_priv, tx_len); - - /* Check if not exceeding CW1200 capabilities */ - if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE)) - pr_debug("Write aligned len: %zu\n", tx_len); - - wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX)); - wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq)); - - if (WARN_ON(cw1200_data_write(priv, data, tx_len))) { - pr_err("tx blew up, len %zu\n", tx_len); - wsm_release_tx_buffer(priv, 1); - return -1; /* Error */ - } - - if (priv->wsm_enable_wsm_dumps) - print_hex_dump_bytes("--> ", - DUMP_PREFIX_NONE, - data, - __le16_to_cpu(wsm->len)); - - wsm_txed(priv, data); - priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; - - if (*tx_burst > 1) { - cw1200_debug_tx_burst(priv); - return 1; /* Work remains */ - } - - return 0; -} - -static int cw1200_bh(void *arg) -{ - struct cw1200_common *priv = arg; - int rx, tx, term, suspend; - u16 ctrl_reg = 0; - int tx_allowed; - int pending_tx = 0; - int tx_burst; - long status; - u32 dummy; - int ret; - - for (;;) { - if (!priv->hw_bufs_used && - priv->powersave_enabled && - !priv->device_can_sleep && - !atomic_read(&priv->recent_scan)) { - status = 1 * HZ; - pr_debug("[BH] Device wakedown. No data.\n"); - cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0); - priv->device_can_sleep = true; - } else if (priv->hw_bufs_used) { - /* Interrupt loss detection */ - status = 1 * HZ; - } else { - status = MAX_SCHEDULE_TIMEOUT; - } - - /* Dummy Read for SDIO retry mechanism*/ - if ((priv->hw_type != -1) && - (atomic_read(&priv->bh_rx) == 0) && - (atomic_read(&priv->bh_tx) == 0)) - cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID, - &dummy, sizeof(dummy)); - - pr_debug("[BH] waiting ...\n"); - status = wait_event_interruptible_timeout(priv->bh_wq, ({ - rx = atomic_xchg(&priv->bh_rx, 0); - tx = atomic_xchg(&priv->bh_tx, 0); - term = atomic_xchg(&priv->bh_term, 0); - suspend = pending_tx ? - 0 : atomic_read(&priv->bh_suspend); - (rx || tx || term || suspend || priv->bh_error); - }), status); - - pr_debug("[BH] - rx: %d, tx: %d, term: %d, bh_err: %d, suspend: %d, status: %ld\n", - rx, tx, term, suspend, priv->bh_error, status); - - /* Did an error occur? */ - if ((status < 0 && status != -ERESTARTSYS) || - term || priv->bh_error) { - break; - } - if (!status) { /* wait_event timed out */ - unsigned long timestamp = jiffies; - long timeout; - int pending = 0; - int i; - - /* Check to see if we have any outstanding frames */ - if (priv->hw_bufs_used && (!rx || !tx)) { - wiphy_warn(priv->hw->wiphy, - "Missed interrupt? (%d frames outstanding)\n", - priv->hw_bufs_used); - rx = 1; - - /* Get a timestamp of "oldest" frame */ - for (i = 0; i < 4; ++i) - pending += cw1200_queue_get_xmit_timestamp( - &priv->tx_queue[i], - ×tamp, - priv->pending_frame_id); - - /* Check if frame transmission is timed out. - * Add an extra second with respect to possible - * interrupt loss. - */ - timeout = timestamp + - WSM_CMD_LAST_CHANCE_TIMEOUT + - 1 * HZ - - jiffies; - - /* And terminate BH thread if the frame is "stuck" */ - if (pending && timeout < 0) { - wiphy_warn(priv->hw->wiphy, - "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n", - priv->hw_bufs_used, pending, - timestamp, jiffies); - break; - } - } else if (!priv->device_can_sleep && - !atomic_read(&priv->recent_scan)) { - pr_debug("[BH] Device wakedown. Timeout.\n"); - cw1200_reg_write_16(priv, - ST90TDS_CONTROL_REG_ID, 0); - priv->device_can_sleep = true; - } - goto done; - } else if (suspend) { - pr_debug("[BH] Device suspend.\n"); - if (priv->powersave_enabled) { - pr_debug("[BH] Device wakedown. Suspend.\n"); - cw1200_reg_write_16(priv, - ST90TDS_CONTROL_REG_ID, 0); - priv->device_can_sleep = true; - } - - atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED); - wake_up(&priv->bh_evt_wq); - status = wait_event_interruptible(priv->bh_wq, - CW1200_BH_RESUME == atomic_read(&priv->bh_suspend)); - if (status < 0) { - wiphy_err(priv->hw->wiphy, - "Failed to wait for resume: %ld.\n", - status); - break; - } - pr_debug("[BH] Device resume.\n"); - atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); - wake_up(&priv->bh_evt_wq); - atomic_add(1, &priv->bh_rx); - goto done; - } - - rx: - tx += pending_tx; - pending_tx = 0; - - if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) - break; - - /* Don't bother trying to rx unless we have data to read */ - if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) { - ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); - if (ret < 0) - break; - /* Double up here if there's more data.. */ - if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) { - ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); - if (ret < 0) - break; - } - } - - tx: - if (tx) { - tx = 0; - - BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers); - tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used; - tx_allowed = tx_burst > 0; - - if (!tx_allowed) { - /* Buffers full. Ensure we process tx - * after we handle rx.. - */ - pending_tx = tx; - goto done_rx; - } - ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst); - if (ret < 0) - break; - if (ret > 0) /* More to transmit */ - tx = ret; - - /* Re-read ctrl reg */ - if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) - break; - } - - done_rx: - if (priv->bh_error) - break; - if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) - goto rx; - if (tx) - goto tx; - - done: - /* Re-enable device interrupts */ - priv->hwbus_ops->lock(priv->hwbus_priv); - __cw1200_irq_enable(priv, 1); - priv->hwbus_ops->unlock(priv->hwbus_priv); - } - - /* Explicitly disable device interrupts */ - priv->hwbus_ops->lock(priv->hwbus_priv); - __cw1200_irq_enable(priv, 0); - priv->hwbus_ops->unlock(priv->hwbus_priv); - - if (!term) { - pr_err("[BH] Fatal error, exiting.\n"); - priv->bh_error = 1; - /* TODO: schedule_work(recovery) */ - } - return 0; -} diff --git a/drivers/net/wireless/cw1200/bh.h b/drivers/net/wireless/cw1200/bh.h deleted file mode 100644 index af6a485..0000000 --- a/drivers/net/wireless/cw1200/bh.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Device handling thread interface for mac80211 ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_BH_H -#define CW1200_BH_H - -/* extern */ struct cw1200_common; - -int cw1200_register_bh(struct cw1200_common *priv); -void cw1200_unregister_bh(struct cw1200_common *priv); -void cw1200_irq_handler(struct cw1200_common *priv); -void cw1200_bh_wakeup(struct cw1200_common *priv); -int cw1200_bh_suspend(struct cw1200_common *priv); -int cw1200_bh_resume(struct cw1200_common *priv); -/* Must be called from BH thread. */ -void cw1200_enable_powersave(struct cw1200_common *priv, - bool enable); -int wsm_release_tx_buffer(struct cw1200_common *priv, int count); - -#endif /* CW1200_BH_H */ diff --git a/drivers/net/wireless/cw1200/cw1200.h b/drivers/net/wireless/cw1200/cw1200.h deleted file mode 100644 index 1ad7d36..0000000 --- a/drivers/net/wireless/cw1200/cw1200.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Common private data for ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on the mac80211 Prism54 code, which is - * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> - * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_H -#define CW1200_H - -#include <linux/wait.h> -#include <linux/mutex.h> -#include <linux/workqueue.h> -#include <net/mac80211.h> - -#include "queue.h" -#include "wsm.h" -#include "scan.h" -#include "txrx.h" -#include "pm.h" - -/* Forward declarations */ -struct hwbus_ops; -struct task_struct; -struct cw1200_debug_priv; -struct firmware; - -#define CW1200_MAX_CTRL_FRAME_LEN (0x1000) - -#define CW1200_MAX_STA_IN_AP_MODE (5) -#define CW1200_LINK_ID_AFTER_DTIM (CW1200_MAX_STA_IN_AP_MODE + 1) -#define CW1200_LINK_ID_UAPSD (CW1200_MAX_STA_IN_AP_MODE + 2) -#define CW1200_LINK_ID_MAX (CW1200_MAX_STA_IN_AP_MODE + 3) -#define CW1200_MAX_REQUEUE_ATTEMPTS (5) - -#define CW1200_MAX_TID (8) - -#define CW1200_BLOCK_ACK_CNT (30) -#define CW1200_BLOCK_ACK_THLD (800) -#define CW1200_BLOCK_ACK_HIST (3) -#define CW1200_BLOCK_ACK_INTERVAL (1 * HZ / CW1200_BLOCK_ACK_HIST) - -#define CW1200_JOIN_TIMEOUT (1 * HZ) -#define CW1200_AUTH_TIMEOUT (5 * HZ) - -struct cw1200_ht_info { - struct ieee80211_sta_ht_cap ht_cap; - enum nl80211_channel_type channel_type; - u16 operation_mode; -}; - -/* Please keep order */ -enum cw1200_join_status { - CW1200_JOIN_STATUS_PASSIVE = 0, - CW1200_JOIN_STATUS_MONITOR, - CW1200_JOIN_STATUS_JOINING, - CW1200_JOIN_STATUS_PRE_STA, - CW1200_JOIN_STATUS_STA, - CW1200_JOIN_STATUS_IBSS, - CW1200_JOIN_STATUS_AP, -}; - -enum cw1200_link_status { - CW1200_LINK_OFF, - CW1200_LINK_RESERVE, - CW1200_LINK_SOFT, - CW1200_LINK_HARD, - CW1200_LINK_RESET, - CW1200_LINK_RESET_REMAP, -}; - -extern int cw1200_power_mode; -extern const char * const cw1200_fw_types[]; - -struct cw1200_link_entry { - unsigned long timestamp; - enum cw1200_link_status status; - enum cw1200_link_status prev_status; - u8 mac[ETH_ALEN]; - u8 buffered[CW1200_MAX_TID]; - struct sk_buff_head rx_queue; -}; - -struct cw1200_common { - /* interfaces to the rest of the stack */ - struct ieee80211_hw *hw; - struct ieee80211_vif *vif; - struct device *pdev; - - /* Statistics */ - struct ieee80211_low_level_stats stats; - - /* Our macaddr */ - u8 mac_addr[ETH_ALEN]; - - /* Hardware interface */ - const struct hwbus_ops *hwbus_ops; - struct hwbus_priv *hwbus_priv; - - /* Hardware information */ - enum { - HIF_9000_SILICON_VERSATILE = 0, - HIF_8601_VERSATILE, - HIF_8601_SILICON, - } hw_type; - enum { - CW1200_HW_REV_CUT10 = 10, - CW1200_HW_REV_CUT11 = 11, - CW1200_HW_REV_CUT20 = 20, - CW1200_HW_REV_CUT22 = 22, - CW1X60_HW_REV = 40, - } hw_revision; - int hw_refclk; - bool hw_have_5ghz; - const struct firmware *sdd; - char *sdd_path; - - struct cw1200_debug_priv *debug; - - struct workqueue_struct *workqueue; - struct mutex conf_mutex; - - struct cw1200_queue tx_queue[4]; - struct cw1200_queue_stats tx_queue_stats; - int tx_burst_idx; - - /* firmware/hardware info */ - unsigned int tx_hdr_len; - - /* Radio data */ - int output_power; - - /* BBP/MAC state */ - struct ieee80211_rate *rates; - struct ieee80211_rate *mcs_rates; - struct ieee80211_channel *channel; - struct wsm_edca_params edca; - struct wsm_tx_queue_params tx_queue_params; - struct wsm_mib_association_mode association_mode; - struct wsm_set_bss_params bss_params; - struct cw1200_ht_info ht_info; - struct wsm_set_pm powersave_mode; - struct wsm_set_pm firmware_ps_mode; - int cqm_rssi_thold; - unsigned cqm_rssi_hyst; - bool cqm_use_rssi; - int cqm_beacon_loss_count; - int channel_switch_in_progress; - wait_queue_head_t channel_switch_done; - u8 long_frame_max_tx_count; - u8 short_frame_max_tx_count; - int mode; - bool enable_beacon; - int beacon_int; - bool listening; - struct wsm_rx_filter rx_filter; - struct wsm_mib_multicast_filter multicast_filter; - bool has_multicast_subscription; - bool disable_beacon_filter; - struct work_struct update_filtering_work; - struct work_struct set_beacon_wakeup_period_work; - - u8 ba_rx_tid_mask; - u8 ba_tx_tid_mask; - - struct cw1200_pm_state pm_state; - - struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; - struct wsm_uapsd_info uapsd_info; - bool setbssparams_done; - bool bt_present; - u8 conf_listen_interval; - u32 listen_interval; - u32 erp_info; - u32 rts_threshold; - - /* BH */ - atomic_t bh_rx; - atomic_t bh_tx; - atomic_t bh_term; - atomic_t bh_suspend; - - struct workqueue_struct *bh_workqueue; - struct work_struct bh_work; - - int bh_error; - wait_queue_head_t bh_wq; - wait_queue_head_t bh_evt_wq; - u8 buf_id_tx; - u8 buf_id_rx; - u8 wsm_rx_seq; - u8 wsm_tx_seq; - int hw_bufs_used; - bool powersave_enabled; - bool device_can_sleep; - - /* Scan status */ - struct cw1200_scan scan; - /* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid - * FW issue with sleeping/waking up. - */ - atomic_t recent_scan; - struct delayed_work clear_recent_scan_work; - - /* WSM */ - struct wsm_startup_ind wsm_caps; - struct mutex wsm_cmd_mux; - struct wsm_buf wsm_cmd_buf; - struct wsm_cmd wsm_cmd; - wait_queue_head_t wsm_cmd_wq; - wait_queue_head_t wsm_startup_done; - int firmware_ready; - atomic_t tx_lock; - - /* WSM debug */ - int wsm_enable_wsm_dumps; - - /* WSM Join */ - enum cw1200_join_status join_status; - u32 pending_frame_id; - bool join_pending; - struct delayed_work join_timeout; - struct work_struct unjoin_work; - struct work_struct join_complete_work; - int join_complete_status; - int join_dtim_period; - bool delayed_unjoin; - - /* TX/RX and security */ - s8 wep_default_key_id; - struct work_struct wep_key_work; - u32 key_map; - struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; - - /* AP powersave */ - u32 link_id_map; - struct cw1200_link_entry link_id_db[CW1200_MAX_STA_IN_AP_MODE]; - struct work_struct link_id_work; - struct delayed_work link_id_gc_work; - u32 sta_asleep_mask; - u32 pspoll_mask; - bool aid0_bit_set; - spinlock_t ps_state_lock; /* Protect power save state */ - bool buffered_multicasts; - bool tx_multicast; - struct work_struct set_tim_work; - struct work_struct set_cts_work; - struct work_struct multicast_start_work; - struct work_struct multicast_stop_work; - struct timer_list mcast_timeout; - - /* WSM events and CQM implementation */ - spinlock_t event_queue_lock; /* Protect event queue */ - struct list_head event_queue; - struct work_struct event_handler; - - struct delayed_work bss_loss_work; - spinlock_t bss_loss_lock; /* Protect BSS loss state */ - int bss_loss_state; - u32 bss_loss_confirm_id; - int delayed_link_loss; - struct work_struct bss_params_work; - - /* TX rate policy cache */ - struct tx_policy_cache tx_policy_cache; - struct work_struct tx_policy_upload_work; - - /* legacy PS mode switch in suspend */ - int ps_mode_switch_in_progress; - wait_queue_head_t ps_mode_switch_done; - - /* Workaround for WFD testcase 6.1.10*/ - struct work_struct linkid_reset_work; - u8 action_frame_sa[ETH_ALEN]; - u8 action_linkid; -}; - -struct cw1200_sta_priv { - int link_id; -}; - -/* interfaces for the drivers */ -int cw1200_core_probe(const struct hwbus_ops *hwbus_ops, - struct hwbus_priv *hwbus, - struct device *pdev, - struct cw1200_common **pself, - int ref_clk, const u8 *macaddr, - const char *sdd_path, bool have_5ghz); -void cw1200_core_release(struct cw1200_common *self); - -#define FWLOAD_BLOCK_SIZE (1024) - -static inline int cw1200_is_ht(const struct cw1200_ht_info *ht_info) -{ - return ht_info->channel_type != NL80211_CHAN_NO_HT; -} - -static inline int cw1200_ht_greenfield(const struct cw1200_ht_info *ht_info) -{ - return cw1200_is_ht(ht_info) && - (ht_info->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && - !(ht_info->operation_mode & - IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); -} - -static inline int cw1200_ht_ampdu_density(const struct cw1200_ht_info *ht_info) -{ - if (!cw1200_is_ht(ht_info)) - return 0; - return ht_info->ht_cap.ampdu_density; -} - -#endif /* CW1200_H */ diff --git a/drivers/net/wireless/cw1200/cw1200_sdio.c b/drivers/net/wireless/cw1200/cw1200_sdio.c deleted file mode 100644 index d3acc85..0000000 --- a/drivers/net/wireless/cw1200/cw1200_sdio.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Mac80211 SDIO driver for ST-Ericsson CW1200 device - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/gpio.h> -#include <linux/delay.h> -#include <linux/mmc/host.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sdio.h> -#include <net/mac80211.h> - -#include "cw1200.h" -#include "hwbus.h" -#include <linux/platform_data/net-cw1200.h> -#include "hwio.h" - -MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>"); -MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SDIO driver"); -MODULE_LICENSE("GPL"); - -#define SDIO_BLOCK_SIZE (512) - -/* Default platform data for Sagrad modules */ -static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = { - .ref_clk = 38400, - .have_5ghz = false, - .sdd_file = "sdd_sagrad_1091_1098.bin", -}; - -/* Allow platform data to be overridden */ -static struct cw1200_platform_data_sdio *global_plat_data = &sagrad_109x_evk_platform_data; - -void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata) -{ - global_plat_data = pdata; -} - -struct hwbus_priv { - struct sdio_func *func; - struct cw1200_common *core; - const struct cw1200_platform_data_sdio *pdata; -}; - -#ifndef SDIO_VENDOR_ID_STE -#define SDIO_VENDOR_ID_STE 0x0020 -#endif - -#ifndef SDIO_DEVICE_ID_STE_CW1200 -#define SDIO_DEVICE_ID_STE_CW1200 0x2280 -#endif - -static const struct sdio_device_id cw1200_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) }, - { /* end: all zeroes */ }, -}; - -/* hwbus_ops implemetation */ - -static int cw1200_sdio_memcpy_fromio(struct hwbus_priv *self, - unsigned int addr, - void *dst, int count) -{ - return sdio_memcpy_fromio(self->func, dst, addr, count); -} - -static int cw1200_sdio_memcpy_toio(struct hwbus_priv *self, - unsigned int addr, - const void *src, int count) -{ - return sdio_memcpy_toio(self->func, addr, (void *)src, count); -} - -static void cw1200_sdio_lock(struct hwbus_priv *self) -{ - sdio_claim_host(self->func); -} - -static void cw1200_sdio_unlock(struct hwbus_priv *self) -{ - sdio_release_host(self->func); -} - -static void cw1200_sdio_irq_handler(struct sdio_func *func) -{ - struct hwbus_priv *self = sdio_get_drvdata(func); - - /* note: sdio_host already claimed here. */ - if (self->core) - cw1200_irq_handler(self->core); -} - -static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id) -{ - return IRQ_WAKE_THREAD; -} - -static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id) -{ - struct hwbus_priv *self = dev_id; - - if (self->core) { - cw1200_sdio_lock(self); - cw1200_irq_handler(self->core); - cw1200_sdio_unlock(self); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } -} - -static int cw1200_request_irq(struct hwbus_priv *self) -{ - int ret; - u8 cccr; - - cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret); - if (WARN_ON(ret)) - goto err; - - /* Master interrupt enable ... */ - cccr |= BIT(0); - - /* ... for our function */ - cccr |= BIT(self->func->num); - - sdio_f0_writeb(self->func, cccr, SDIO_CCCR_IENx, &ret); - if (WARN_ON(ret)) - goto err; - - ret = enable_irq_wake(self->pdata->irq); - if (WARN_ON(ret)) - goto err; - - /* Request the IRQ */ - ret = request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq, - cw1200_gpio_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "cw1200_wlan_irq", self); - if (WARN_ON(ret)) - goto err; - - return 0; - -err: - return ret; -} - -static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self) -{ - int ret = 0; - - pr_debug("SW IRQ subscribe\n"); - sdio_claim_host(self->func); - if (self->pdata->irq) - ret = cw1200_request_irq(self); - else - ret = sdio_claim_irq(self->func, cw1200_sdio_irq_handler); - - sdio_release_host(self->func); - return ret; -} - -static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self) -{ - int ret = 0; - - pr_debug("SW IRQ unsubscribe\n"); - - if (self->pdata->irq) { - disable_irq_wake(self->pdata->irq); - free_irq(self->pdata->irq, self); - } else { - sdio_claim_host(self->func); - ret = sdio_release_irq(self->func); - sdio_release_host(self->func); - } - return ret; -} - -static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata) -{ - if (pdata->reset) { - gpio_set_value(pdata->reset, 0); - msleep(30); /* Min is 2 * CLK32K cycles */ - gpio_free(pdata->reset); - } - - if (pdata->power_ctrl) - pdata->power_ctrl(pdata, false); - if (pdata->clk_ctrl) - pdata->clk_ctrl(pdata, false); - - return 0; -} - -static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata) -{ - /* Ensure I/Os are pulled low */ - if (pdata->reset) { - gpio_request(pdata->reset, "cw1200_wlan_reset"); - gpio_direction_output(pdata->reset, 0); - } - if (pdata->powerup) { - gpio_request(pdata->powerup, "cw1200_wlan_powerup"); - gpio_direction_output(pdata->powerup, 0); - } - if (pdata->reset || pdata->powerup) - msleep(10); /* Settle time? */ - - /* Enable 3v3 and 1v8 to hardware */ - if (pdata->power_ctrl) { - if (pdata->power_ctrl(pdata, true)) { - pr_err("power_ctrl() failed!\n"); - return -1; - } - } - - /* Enable CLK32K */ - if (pdata->clk_ctrl) { - if (pdata->clk_ctrl(pdata, true)) { - pr_err("clk_ctrl() failed!\n"); - return -1; - } - msleep(10); /* Delay until clock is stable for 2 cycles */ - } - - /* Enable POWERUP signal */ - if (pdata->powerup) { - gpio_set_value(pdata->powerup, 1); - msleep(250); /* or more..? */ - } - /* Enable RSTn signal */ - if (pdata->reset) { - gpio_set_value(pdata->reset, 1); - msleep(50); /* Or more..? */ - } - return 0; -} - -static size_t cw1200_sdio_align_size(struct hwbus_priv *self, size_t size) -{ - if (self->pdata->no_nptb) - size = round_up(size, SDIO_BLOCK_SIZE); - else - size = sdio_align_size(self->func, size); - - return size; -} - -static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend) -{ - int ret = 0; - - if (self->pdata->irq) - ret = irq_set_irq_wake(self->pdata->irq, suspend); - return ret; -} - -static struct hwbus_ops cw1200_sdio_hwbus_ops = { - .hwbus_memcpy_fromio = cw1200_sdio_memcpy_fromio, - .hwbus_memcpy_toio = cw1200_sdio_memcpy_toio, - .lock = cw1200_sdio_lock, - .unlock = cw1200_sdio_unlock, - .align_size = cw1200_sdio_align_size, - .power_mgmt = cw1200_sdio_pm, -}; - -/* Probe Function to be called by SDIO stack when device is discovered */ -static int cw1200_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - struct hwbus_priv *self; - int status; - - pr_info("cw1200_wlan_sdio: Probe called\n"); - - /* We are only able to handle the wlan function */ - if (func->num != 0x01) - return -ENODEV; - - self = kzalloc(sizeof(*self), GFP_KERNEL); - if (!self) { - pr_err("Can't allocate SDIO hwbus_priv.\n"); - return -ENOMEM; - } - - func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - - self->pdata = global_plat_data; /* FIXME */ - self->func = func; - sdio_set_drvdata(func, self); - sdio_claim_host(func); - sdio_enable_func(func); - sdio_release_host(func); - - status = cw1200_sdio_irq_subscribe(self); - - status = cw1200_core_probe(&cw1200_sdio_hwbus_ops, - self, &func->dev, &self->core, - self->pdata->ref_clk, - self->pdata->macaddr, - self->pdata->sdd_file, - self->pdata->have_5ghz); - if (status) { - cw1200_sdio_irq_unsubscribe(self); - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); - sdio_set_drvdata(func, NULL); - kfree(self); - } - - return status; -} - -/* Disconnect Function to be called by SDIO stack when - * device is disconnected - */ -static void cw1200_sdio_disconnect(struct sdio_func *func) -{ - struct hwbus_priv *self = sdio_get_drvdata(func); - - if (self) { - cw1200_sdio_irq_unsubscribe(self); - if (self->core) { - cw1200_core_release(self->core); - self->core = NULL; - } - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); - sdio_set_drvdata(func, NULL); - kfree(self); - } -} - -#ifdef CONFIG_PM -static int cw1200_sdio_suspend(struct device *dev) -{ - int ret; - struct sdio_func *func = dev_to_sdio_func(dev); - struct hwbus_priv *self = sdio_get_drvdata(func); - - if (!cw1200_can_suspend(self->core)) - return -EAGAIN; - - /* Notify SDIO that CW1200 will remain powered during suspend */ - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); - if (ret) - pr_err("Error setting SDIO pm flags: %i\n", ret); - - return ret; -} - -static int cw1200_sdio_resume(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops cw1200_pm_ops = { - .suspend = cw1200_sdio_suspend, - .resume = cw1200_sdio_resume, -}; -#endif - -static struct sdio_driver sdio_driver = { - .name = "cw1200_wlan_sdio", - .id_table = cw1200_sdio_ids, - .probe = cw1200_sdio_probe, - .remove = cw1200_sdio_disconnect, -#ifdef CONFIG_PM - .drv = { - .pm = &cw1200_pm_ops, - } -#endif -}; - -/* Init Module function -> Called by insmod */ -static int __init cw1200_sdio_init(void) -{ - const struct cw1200_platform_data_sdio *pdata; - int ret; - - /* FIXME -- this won't support multiple devices */ - pdata = global_plat_data; - - if (cw1200_sdio_on(pdata)) { - ret = -1; - goto err; - } - - ret = sdio_register_driver(&sdio_driver); - if (ret) - goto err; - - return 0; - -err: - cw1200_sdio_off(pdata); - return ret; -} - -/* Called at Driver Unloading */ -static void __exit cw1200_sdio_exit(void) -{ - const struct cw1200_platform_data_sdio *pdata; - - /* FIXME -- this won't support multiple devices */ - pdata = global_plat_data; - sdio_unregister_driver(&sdio_driver); - cw1200_sdio_off(pdata); -} - - -module_init(cw1200_sdio_init); -module_exit(cw1200_sdio_exit); diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c deleted file mode 100644 index a740083..0000000 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Mac80211 SPI driver for ST-Ericsson CW1200 device - * - * Copyright (c) 2011, Sagrad Inc. - * Author: Solomon Peachy <speachy@sagrad.com> - * - * Based on cw1200_sdio.c - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/gpio.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <net/mac80211.h> - -#include <linux/spi/spi.h> -#include <linux/device.h> - -#include "cw1200.h" -#include "hwbus.h" -#include <linux/platform_data/net-cw1200.h> -#include "hwio.h" - -MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>"); -MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SPI driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:cw1200_wlan_spi"); - -/* #define SPI_DEBUG */ - -struct hwbus_priv { - struct spi_device *func; - struct cw1200_common *core; - const struct cw1200_platform_data_spi *pdata; - spinlock_t lock; /* Serialize all bus operations */ - wait_queue_head_t wq; - int claimed; -}; - -#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) -#define SET_WRITE 0x7FFF /* usage: and operation */ -#define SET_READ 0x8000 /* usage: or operation */ - -/* Notes on byte ordering: - LE: B0 B1 B2 B3 - BE: B3 B2 B1 B0 - - Hardware expects 32-bit data to be written as 16-bit BE words: - - B1 B0 B3 B2 -*/ - -static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self, - unsigned int addr, - void *dst, int count) -{ - int ret, i; - u16 regaddr; - struct spi_message m; - - struct spi_transfer t_addr = { - .tx_buf = ®addr, - .len = sizeof(regaddr), - }; - struct spi_transfer t_msg = { - .rx_buf = dst, - .len = count, - }; - - regaddr = (SDIO_TO_SPI_ADDR(addr))<<12; - regaddr |= SET_READ; - regaddr |= (count>>1); - -#ifdef SPI_DEBUG - pr_info("READ : %04d from 0x%02x (%04x)\n", count, addr, regaddr); -#endif - - /* Header is LE16 */ - regaddr = cpu_to_le16(regaddr); - - /* We have to byteswap if the SPI bus is limited to 8b operation - or we are running on a Big Endian system - */ -#if defined(__LITTLE_ENDIAN) - if (self->func->bits_per_word == 8) -#endif - regaddr = swab16(regaddr); - - spi_message_init(&m); - spi_message_add_tail(&t_addr, &m); - spi_message_add_tail(&t_msg, &m); - ret = spi_sync(self->func, &m); - -#ifdef SPI_DEBUG - pr_info("READ : "); - for (i = 0; i < t_addr.len; i++) - printk("%02x ", ((u8 *)t_addr.tx_buf)[i]); - printk(" : "); - for (i = 0; i < t_msg.len; i++) - printk("%02x ", ((u8 *)t_msg.rx_buf)[i]); - printk("\n"); -#endif - - /* We have to byteswap if the SPI bus is limited to 8b operation - or we are running on a Big Endian system - */ -#if defined(__LITTLE_ENDIAN) - if (self->func->bits_per_word == 8) -#endif - { - uint16_t *buf = (uint16_t *)dst; - for (i = 0; i < ((count + 1) >> 1); i++) - buf[i] = swab16(buf[i]); - } - - return ret; -} - -static int cw1200_spi_memcpy_toio(struct hwbus_priv *self, - unsigned int addr, - const void *src, int count) -{ - int rval, i; - u16 regaddr; - struct spi_transfer t_addr = { - .tx_buf = ®addr, - .len = sizeof(regaddr), - }; - struct spi_transfer t_msg = { - .tx_buf = src, - .len = count, - }; - struct spi_message m; - - regaddr = (SDIO_TO_SPI_ADDR(addr))<<12; - regaddr &= SET_WRITE; - regaddr |= (count>>1); - -#ifdef SPI_DEBUG - pr_info("WRITE: %04d to 0x%02x (%04x)\n", count, addr, regaddr); -#endif - - /* Header is LE16 */ - regaddr = cpu_to_le16(regaddr); - - /* We have to byteswap if the SPI bus is limited to 8b operation - or we are running on a Big Endian system - */ -#if defined(__LITTLE_ENDIAN) - if (self->func->bits_per_word == 8) -#endif - { - uint16_t *buf = (uint16_t *)src; - regaddr = swab16(regaddr); - for (i = 0; i < ((count + 1) >> 1); i++) - buf[i] = swab16(buf[i]); - } - -#ifdef SPI_DEBUG - pr_info("WRITE: "); - for (i = 0; i < t_addr.len; i++) - printk("%02x ", ((u8 *)t_addr.tx_buf)[i]); - printk(" : "); - for (i = 0; i < t_msg.len; i++) - printk("%02x ", ((u8 *)t_msg.tx_buf)[i]); - printk("\n"); -#endif - - spi_message_init(&m); - spi_message_add_tail(&t_addr, &m); - spi_message_add_tail(&t_msg, &m); - rval = spi_sync(self->func, &m); - -#ifdef SPI_DEBUG - pr_info("WROTE: %d\n", m.actual_length); -#endif - -#if defined(__LITTLE_ENDIAN) - /* We have to byteswap if the SPI bus is limited to 8b operation */ - if (self->func->bits_per_word == 8) -#endif - { - uint16_t *buf = (uint16_t *)src; - for (i = 0; i < ((count + 1) >> 1); i++) - buf[i] = swab16(buf[i]); - } - return rval; -} - -static void cw1200_spi_lock(struct hwbus_priv *self) -{ - unsigned long flags; - - DECLARE_WAITQUEUE(wait, current); - - might_sleep(); - - add_wait_queue(&self->wq, &wait); - spin_lock_irqsave(&self->lock, flags); - while (1) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (!self->claimed) - break; - spin_unlock_irqrestore(&self->lock, flags); - schedule(); - spin_lock_irqsave(&self->lock, flags); - } - set_current_state(TASK_RUNNING); - self->claimed = 1; - spin_unlock_irqrestore(&self->lock, flags); - remove_wait_queue(&self->wq, &wait); - - return; -} - -static void cw1200_spi_unlock(struct hwbus_priv *self) -{ - unsigned long flags; - - spin_lock_irqsave(&self->lock, flags); - self->claimed = 0; - spin_unlock_irqrestore(&self->lock, flags); - wake_up(&self->wq); - - return; -} - -static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) -{ - struct hwbus_priv *self = dev_id; - - if (self->core) { - cw1200_spi_lock(self); - cw1200_irq_handler(self->core); - cw1200_spi_unlock(self); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } -} - -static int cw1200_spi_irq_subscribe(struct hwbus_priv *self) -{ - int ret; - - pr_debug("SW IRQ subscribe\n"); - - ret = request_threaded_irq(self->func->irq, NULL, - cw1200_spi_irq_handler, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "cw1200_wlan_irq", self); - if (WARN_ON(ret < 0)) - goto exit; - - ret = enable_irq_wake(self->func->irq); - if (WARN_ON(ret)) - goto free_irq; - - return 0; - -free_irq: - free_irq(self->func->irq, self); -exit: - return ret; -} - -static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) -{ - int ret = 0; - - pr_debug("SW IRQ unsubscribe\n"); - disable_irq_wake(self->func->irq); - free_irq(self->func->irq, self); - - return ret; -} - -static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) -{ - if (pdata->reset) { - gpio_set_value(pdata->reset, 0); - msleep(30); /* Min is 2 * CLK32K cycles */ - gpio_free(pdata->reset); - } - - if (pdata->power_ctrl) - pdata->power_ctrl(pdata, false); - if (pdata->clk_ctrl) - pdata->clk_ctrl(pdata, false); - - return 0; -} - -static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) -{ - /* Ensure I/Os are pulled low */ - if (pdata->reset) { - gpio_request(pdata->reset, "cw1200_wlan_reset"); - gpio_direction_output(pdata->reset, 0); - } - if (pdata->powerup) { - gpio_request(pdata->powerup, "cw1200_wlan_powerup"); - gpio_direction_output(pdata->powerup, 0); - } - if (pdata->reset || pdata->powerup) - msleep(10); /* Settle time? */ - - /* Enable 3v3 and 1v8 to hardware */ - if (pdata->power_ctrl) { - if (pdata->power_ctrl(pdata, true)) { - pr_err("power_ctrl() failed!\n"); - return -1; - } - } - - /* Enable CLK32K */ - if (pdata->clk_ctrl) { - if (pdata->clk_ctrl(pdata, true)) { - pr_err("clk_ctrl() failed!\n"); - return -1; - } - msleep(10); /* Delay until clock is stable for 2 cycles */ - } - - /* Enable POWERUP signal */ - if (pdata->powerup) { - gpio_set_value(pdata->powerup, 1); - msleep(250); /* or more..? */ - } - /* Enable RSTn signal */ - if (pdata->reset) { - gpio_set_value(pdata->reset, 1); - msleep(50); /* Or more..? */ - } - return 0; -} - -static size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size) -{ - return size & 1 ? size + 1 : size; -} - -static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend) -{ - return irq_set_irq_wake(self->func->irq, suspend); -} - -static struct hwbus_ops cw1200_spi_hwbus_ops = { - .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio, - .hwbus_memcpy_toio = cw1200_spi_memcpy_toio, - .lock = cw1200_spi_lock, - .unlock = cw1200_spi_unlock, - .align_size = cw1200_spi_align_size, - .power_mgmt = cw1200_spi_pm, -}; - -/* Probe Function to be called by SPI stack when device is discovered */ -static int cw1200_spi_probe(struct spi_device *func) -{ - const struct cw1200_platform_data_spi *plat_data = - dev_get_platdata(&func->dev); - struct hwbus_priv *self; - int status; - - /* Sanity check speed */ - if (func->max_speed_hz > 52000000) - func->max_speed_hz = 52000000; - if (func->max_speed_hz < 1000000) - func->max_speed_hz = 1000000; - - /* Fix up transfer size */ - if (plat_data->spi_bits_per_word) - func->bits_per_word = plat_data->spi_bits_per_word; - if (!func->bits_per_word) - func->bits_per_word = 16; - - /* And finally.. */ - func->mode = SPI_MODE_0; - - pr_info("cw1200_wlan_spi: Probe called (CS %d M %d BPW %d CLK %d)\n", - func->chip_select, func->mode, func->bits_per_word, - func->max_speed_hz); - - if (cw1200_spi_on(plat_data)) { - pr_err("spi_on() failed!\n"); - return -1; - } - - if (spi_setup(func)) { - pr_err("spi_setup() failed!\n"); - return -1; - } - - self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL); - if (!self) { - pr_err("Can't allocate SPI hwbus_priv."); - return -ENOMEM; - } - - self->pdata = plat_data; - self->func = func; - spin_lock_init(&self->lock); - - spi_set_drvdata(func, self); - - init_waitqueue_head(&self->wq); - - status = cw1200_spi_irq_subscribe(self); - - status = cw1200_core_probe(&cw1200_spi_hwbus_ops, - self, &func->dev, &self->core, - self->pdata->ref_clk, - self->pdata->macaddr, - self->pdata->sdd_file, - self->pdata->have_5ghz); - - if (status) { - cw1200_spi_irq_unsubscribe(self); - cw1200_spi_off(plat_data); - } - - return status; -} - -/* Disconnect Function to be called by SPI stack when device is disconnected */ -static int cw1200_spi_disconnect(struct spi_device *func) -{ - struct hwbus_priv *self = spi_get_drvdata(func); - - if (self) { - cw1200_spi_irq_unsubscribe(self); - if (self->core) { - cw1200_core_release(self->core); - self->core = NULL; - } - } - cw1200_spi_off(dev_get_platdata(&func->dev)); - - return 0; -} - -#ifdef CONFIG_PM -static int cw1200_spi_suspend(struct device *dev) -{ - struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); - - if (!cw1200_can_suspend(self->core)) - return -EAGAIN; - - /* XXX notify host that we have to keep CW1200 powered on? */ - return 0; -} - -static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL); - -#endif - -static struct spi_driver spi_driver = { - .probe = cw1200_spi_probe, - .remove = cw1200_spi_disconnect, - .driver = { - .name = "cw1200_wlan_spi", -#ifdef CONFIG_PM - .pm = &cw1200_pm_ops, -#endif - }, -}; - -module_spi_driver(spi_driver); diff --git a/drivers/net/wireless/cw1200/debug.c b/drivers/net/wireless/cw1200/debug.c deleted file mode 100644 index 34f97c3..0000000 --- a/drivers/net/wireless/cw1200/debug.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers - * DebugFS code - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include "cw1200.h" -#include "debug.h" -#include "fwio.h" - -/* join_status */ -static const char * const cw1200_debug_join_status[] = { - "passive", - "monitor", - "station (joining)", - "station (not authenticated yet)", - "station", - "adhoc", - "access point", -}; - -/* WSM_JOIN_PREAMBLE_... */ -static const char * const cw1200_debug_preamble[] = { - "long", - "short", - "long on 1 and 2 Mbps", -}; - - -static const char * const cw1200_debug_link_id[] = { - "OFF", - "REQ", - "SOFT", - "HARD", - "RESET", - "RESET_REMAP", -}; - -static const char *cw1200_debug_mode(int mode) -{ - switch (mode) { - case NL80211_IFTYPE_UNSPECIFIED: - return "unspecified"; - case NL80211_IFTYPE_MONITOR: - return "monitor"; - case NL80211_IFTYPE_STATION: - return "station"; - case NL80211_IFTYPE_ADHOC: - return "adhoc"; - case NL80211_IFTYPE_MESH_POINT: - return "mesh point"; - case NL80211_IFTYPE_AP: - return "access point"; - case NL80211_IFTYPE_P2P_CLIENT: - return "p2p client"; - case NL80211_IFTYPE_P2P_GO: - return "p2p go"; - default: - return "unsupported"; - } -} - -static void cw1200_queue_status_show(struct seq_file *seq, - struct cw1200_queue *q) -{ - int i; - seq_printf(seq, "Queue %d:\n", q->queue_id); - seq_printf(seq, " capacity: %zu\n", q->capacity); - seq_printf(seq, " queued: %zu\n", q->num_queued); - seq_printf(seq, " pending: %zu\n", q->num_pending); - seq_printf(seq, " sent: %zu\n", q->num_sent); - seq_printf(seq, " locked: %s\n", q->tx_locked_cnt ? "yes" : "no"); - seq_printf(seq, " overfull: %s\n", q->overfull ? "yes" : "no"); - seq_puts(seq, " link map: 0-> "); - for (i = 0; i < q->stats->map_capacity; ++i) - seq_printf(seq, "%.2d ", q->link_map_cache[i]); - seq_printf(seq, "<-%zu\n", q->stats->map_capacity); -} - -static void cw1200_debug_print_map(struct seq_file *seq, - struct cw1200_common *priv, - const char *label, - u32 map) -{ - int i; - seq_printf(seq, "%s0-> ", label); - for (i = 0; i < priv->tx_queue_stats.map_capacity; ++i) - seq_printf(seq, "%s ", (map & BIT(i)) ? "**" : ".."); - seq_printf(seq, "<-%zu\n", priv->tx_queue_stats.map_capacity - 1); -} - -static int cw1200_status_show(struct seq_file *seq, void *v) -{ - int i; - struct list_head *item; - struct cw1200_common *priv = seq->private; - struct cw1200_debug_priv *d = priv->debug; - - seq_puts(seq, "CW1200 Wireless LAN driver status\n"); - seq_printf(seq, "Hardware: %d.%d\n", - priv->wsm_caps.hw_id, - priv->wsm_caps.hw_subid); - seq_printf(seq, "Firmware: %s %d.%d\n", - cw1200_fw_types[priv->wsm_caps.fw_type], - priv->wsm_caps.fw_ver, - priv->wsm_caps.fw_build); - seq_printf(seq, "FW API: %d\n", - priv->wsm_caps.fw_api); - seq_printf(seq, "FW caps: 0x%.4X\n", - priv->wsm_caps.fw_cap); - seq_printf(seq, "FW label: '%s'\n", - priv->wsm_caps.fw_label); - seq_printf(seq, "Mode: %s%s\n", - cw1200_debug_mode(priv->mode), - priv->listening ? " (listening)" : ""); - seq_printf(seq, "Join state: %s\n", - cw1200_debug_join_status[priv->join_status]); - if (priv->channel) - seq_printf(seq, "Channel: %d%s\n", - priv->channel->hw_value, - priv->channel_switch_in_progress ? - " (switching)" : ""); - if (priv->rx_filter.promiscuous) - seq_puts(seq, "Filter: promisc\n"); - else if (priv->rx_filter.fcs) - seq_puts(seq, "Filter: fcs\n"); - if (priv->rx_filter.bssid) - seq_puts(seq, "Filter: bssid\n"); - if (!priv->disable_beacon_filter) - seq_puts(seq, "Filter: beacons\n"); - - if (priv->enable_beacon || - priv->mode == NL80211_IFTYPE_AP || - priv->mode == NL80211_IFTYPE_ADHOC || - priv->mode == NL80211_IFTYPE_MESH_POINT || - priv->mode == NL80211_IFTYPE_P2P_GO) - seq_printf(seq, "Beaconing: %s\n", - priv->enable_beacon ? - "enabled" : "disabled"); - - for (i = 0; i < 4; ++i) - seq_printf(seq, "EDCA(%d): %d, %d, %d, %d, %d\n", i, - priv->edca.params[i].cwmin, - priv->edca.params[i].cwmax, - priv->edca.params[i].aifns, - priv->edca.params[i].txop_limit, - priv->edca.params[i].max_rx_lifetime); - - if (priv->join_status == CW1200_JOIN_STATUS_STA) { - static const char *pm_mode = "unknown"; - switch (priv->powersave_mode.mode) { - case WSM_PSM_ACTIVE: - pm_mode = "off"; - break; - case WSM_PSM_PS: - pm_mode = "on"; - break; - case WSM_PSM_FAST_PS: - pm_mode = "dynamic"; - break; - } - seq_printf(seq, "Preamble: %s\n", - cw1200_debug_preamble[priv->association_mode.preamble]); - seq_printf(seq, "AMPDU spcn: %d\n", - priv->association_mode.mpdu_start_spacing); - seq_printf(seq, "Basic rate: 0x%.8X\n", - le32_to_cpu(priv->association_mode.basic_rate_set)); - seq_printf(seq, "Bss lost: %d beacons\n", - priv->bss_params.beacon_lost_count); - seq_printf(seq, "AID: %d\n", - priv->bss_params.aid); - seq_printf(seq, "Rates: 0x%.8X\n", - priv->bss_params.operational_rate_set); - seq_printf(seq, "Powersave: %s\n", pm_mode); - } - seq_printf(seq, "HT: %s\n", - cw1200_is_ht(&priv->ht_info) ? "on" : "off"); - if (cw1200_is_ht(&priv->ht_info)) { - seq_printf(seq, "Greenfield: %s\n", - cw1200_ht_greenfield(&priv->ht_info) ? "yes" : "no"); - seq_printf(seq, "AMPDU dens: %d\n", - cw1200_ht_ampdu_density(&priv->ht_info)); - } - seq_printf(seq, "RSSI thold: %d\n", - priv->cqm_rssi_thold); - seq_printf(seq, "RSSI hyst: %d\n", - priv->cqm_rssi_hyst); - seq_printf(seq, "Long retr: %d\n", - priv->long_frame_max_tx_count); - seq_printf(seq, "Short retr: %d\n", - priv->short_frame_max_tx_count); - spin_lock_bh(&priv->tx_policy_cache.lock); - i = 0; - list_for_each(item, &priv->tx_policy_cache.used) - ++i; - spin_unlock_bh(&priv->tx_policy_cache.lock); - seq_printf(seq, "RC in use: %d\n", i); - - seq_puts(seq, "\n"); - for (i = 0; i < 4; ++i) { - cw1200_queue_status_show(seq, &priv->tx_queue[i]); - seq_puts(seq, "\n"); - } - - cw1200_debug_print_map(seq, priv, "Link map: ", - priv->link_id_map); - cw1200_debug_print_map(seq, priv, "Asleep map: ", - priv->sta_asleep_mask); - cw1200_debug_print_map(seq, priv, "PSPOLL map: ", - priv->pspoll_mask); - - seq_puts(seq, "\n"); - - for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { - if (priv->link_id_db[i].status) { - seq_printf(seq, "Link %d: %s, %pM\n", - i + 1, - cw1200_debug_link_id[priv->link_id_db[i].status], - priv->link_id_db[i].mac); - } - } - - seq_puts(seq, "\n"); - - seq_printf(seq, "BH status: %s\n", - atomic_read(&priv->bh_term) ? "terminated" : "alive"); - seq_printf(seq, "Pending RX: %d\n", - atomic_read(&priv->bh_rx)); - seq_printf(seq, "Pending TX: %d\n", - atomic_read(&priv->bh_tx)); - if (priv->bh_error) - seq_printf(seq, "BH errcode: %d\n", - priv->bh_error); - seq_printf(seq, "TX bufs: %d x %d bytes\n", - priv->wsm_caps.input_buffers, - priv->wsm_caps.input_buffer_size); - seq_printf(seq, "Used bufs: %d\n", - priv->hw_bufs_used); - seq_printf(seq, "Powermgmt: %s\n", - priv->powersave_enabled ? "on" : "off"); - seq_printf(seq, "Device: %s\n", - priv->device_can_sleep ? "asleep" : "awake"); - - spin_lock(&priv->wsm_cmd.lock); - seq_printf(seq, "WSM status: %s\n", - priv->wsm_cmd.done ? "idle" : "active"); - seq_printf(seq, "WSM cmd: 0x%.4X (%td bytes)\n", - priv->wsm_cmd.cmd, priv->wsm_cmd.len); - seq_printf(seq, "WSM retval: %d\n", - priv->wsm_cmd.ret); - spin_unlock(&priv->wsm_cmd.lock); - - seq_printf(seq, "Datapath: %s\n", - atomic_read(&priv->tx_lock) ? "locked" : "unlocked"); - if (atomic_read(&priv->tx_lock)) - seq_printf(seq, "TXlock cnt: %d\n", - atomic_read(&priv->tx_lock)); - - seq_printf(seq, "TXed: %d\n", - d->tx); - seq_printf(seq, "AGG TXed: %d\n", - d->tx_agg); - seq_printf(seq, "MULTI TXed: %d (%d)\n", - d->tx_multi, d->tx_multi_frames); - seq_printf(seq, "RXed: %d\n", - d->rx); - seq_printf(seq, "AGG RXed: %d\n", - d->rx_agg); - seq_printf(seq, "TX miss: %d\n", - d->tx_cache_miss); - seq_printf(seq, "TX align: %d\n", - d->tx_align); - seq_printf(seq, "TX burst: %d\n", - d->tx_burst); - seq_printf(seq, "TX TTL: %d\n", - d->tx_ttl); - seq_printf(seq, "Scan: %s\n", - atomic_read(&priv->scan.in_progress) ? "active" : "idle"); - - return 0; -} - -static int cw1200_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, &cw1200_status_show, - inode->i_private); -} - -static const struct file_operations fops_status = { - .open = cw1200_status_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int cw1200_counters_show(struct seq_file *seq, void *v) -{ - int ret; - struct cw1200_common *priv = seq->private; - struct wsm_mib_counters_table counters; - - ret = wsm_get_counters_table(priv, &counters); - if (ret) - return ret; - -#define PUT_COUNTER(tab, name) \ - seq_printf(seq, "%s:" tab "%d\n", #name, \ - __le32_to_cpu(counters.name)) - - PUT_COUNTER("\t\t", plcp_errors); - PUT_COUNTER("\t\t", fcs_errors); - PUT_COUNTER("\t\t", tx_packets); - PUT_COUNTER("\t\t", rx_packets); - PUT_COUNTER("\t\t", rx_packet_errors); - PUT_COUNTER("\t", rx_decryption_failures); - PUT_COUNTER("\t\t", rx_mic_failures); - PUT_COUNTER("\t", rx_no_key_failures); - PUT_COUNTER("\t", tx_multicast_frames); - PUT_COUNTER("\t", tx_frames_success); - PUT_COUNTER("\t", tx_frame_failures); - PUT_COUNTER("\t", tx_frames_retried); - PUT_COUNTER("\t", tx_frames_multi_retried); - PUT_COUNTER("\t", rx_frame_duplicates); - PUT_COUNTER("\t\t", rts_success); - PUT_COUNTER("\t\t", rts_failures); - PUT_COUNTER("\t\t", ack_failures); - PUT_COUNTER("\t", rx_multicast_frames); - PUT_COUNTER("\t", rx_frames_success); - PUT_COUNTER("\t", rx_cmac_icv_errors); - PUT_COUNTER("\t\t", rx_cmac_replays); - PUT_COUNTER("\t", rx_mgmt_ccmp_replays); - -#undef PUT_COUNTER - - return 0; -} - -static int cw1200_counters_open(struct inode *inode, struct file *file) -{ - return single_open(file, &cw1200_counters_show, - inode->i_private); -} - -static const struct file_operations fops_counters = { - .open = cw1200_counters_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static ssize_t cw1200_wsm_dumps(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct cw1200_common *priv = file->private_data; - char buf[1]; - - if (!count) - return -EINVAL; - if (copy_from_user(buf, user_buf, 1)) - return -EFAULT; - - if (buf[0] == '1') - priv->wsm_enable_wsm_dumps = 1; - else - priv->wsm_enable_wsm_dumps = 0; - - return count; -} - -static const struct file_operations fops_wsm_dumps = { - .open = simple_open, - .write = cw1200_wsm_dumps, - .llseek = default_llseek, -}; - -int cw1200_debug_init(struct cw1200_common *priv) -{ - int ret = -ENOMEM; - struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv), - GFP_KERNEL); - priv->debug = d; - if (!d) - return ret; - - d->debugfs_phy = debugfs_create_dir("cw1200", - priv->hw->wiphy->debugfsdir); - if (!d->debugfs_phy) - goto err; - - if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy, - priv, &fops_status)) - goto err; - - if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy, - priv, &fops_counters)) - goto err; - - if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy, - priv, &fops_wsm_dumps)) - goto err; - - return 0; - -err: - priv->debug = NULL; - debugfs_remove_recursive(d->debugfs_phy); - kfree(d); - return ret; -} - -void cw1200_debug_release(struct cw1200_common *priv) -{ - struct cw1200_debug_priv *d = priv->debug; - if (d) { - debugfs_remove_recursive(d->debugfs_phy); - priv->debug = NULL; - kfree(d); - } -} diff --git a/drivers/net/wireless/cw1200/debug.h b/drivers/net/wireless/cw1200/debug.h deleted file mode 100644 index b525aba..0000000 --- a/drivers/net/wireless/cw1200/debug.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * DebugFS code for ST-Ericsson CW1200 mac80211 driver - * - * Copyright (c) 2011, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_DEBUG_H_INCLUDED -#define CW1200_DEBUG_H_INCLUDED - -struct cw1200_debug_priv { - struct dentry *debugfs_phy; - int tx; - int tx_agg; - int rx; - int rx_agg; - int tx_multi; - int tx_multi_frames; - int tx_cache_miss; - int tx_align; - int tx_ttl; - int tx_burst; - int ba_cnt; - int ba_acc; - int ba_cnt_rx; - int ba_acc_rx; -}; - -int cw1200_debug_init(struct cw1200_common *priv); -void cw1200_debug_release(struct cw1200_common *priv); - -static inline void cw1200_debug_txed(struct cw1200_common *priv) -{ - ++priv->debug->tx; -} - -static inline void cw1200_debug_txed_agg(struct cw1200_common *priv) -{ - ++priv->debug->tx_agg; -} - -static inline void cw1200_debug_txed_multi(struct cw1200_common *priv, - int count) -{ - ++priv->debug->tx_multi; - priv->debug->tx_multi_frames += count; -} - -static inline void cw1200_debug_rxed(struct cw1200_common *priv) -{ - ++priv->debug->rx; -} - -static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv) -{ - ++priv->debug->rx_agg; -} - -static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv) -{ - ++priv->debug->tx_cache_miss; -} - -static inline void cw1200_debug_tx_align(struct cw1200_common *priv) -{ - ++priv->debug->tx_align; -} - -static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv) -{ - ++priv->debug->tx_ttl; -} - -static inline void cw1200_debug_tx_burst(struct cw1200_common *priv) -{ - ++priv->debug->tx_burst; -} - -static inline void cw1200_debug_ba(struct cw1200_common *priv, - int ba_cnt, int ba_acc, - int ba_cnt_rx, int ba_acc_rx) -{ - priv->debug->ba_cnt = ba_cnt; - priv->debug->ba_acc = ba_acc; - priv->debug->ba_cnt_rx = ba_cnt_rx; - priv->debug->ba_acc_rx = ba_acc_rx; -} - -#endif /* CW1200_DEBUG_H_INCLUDED */ diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c deleted file mode 100644 index 30e7646..0000000 --- a/drivers/net/wireless/cw1200/fwio.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Firmware I/O code for mac80211 ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on: - * ST-Ericsson UMAC CW1200 driver which is - * Copyright (c) 2010, ST-Ericsson - * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/vmalloc.h> -#include <linux/sched.h> -#include <linux/firmware.h> - -#include "cw1200.h" -#include "fwio.h" -#include "hwio.h" -#include "hwbus.h" -#include "bh.h" - -static int cw1200_get_hw_type(u32 config_reg_val, int *major_revision) -{ - int hw_type = -1; - u32 silicon_type = (config_reg_val >> 24) & 0x7; - u32 silicon_vers = (config_reg_val >> 31) & 0x1; - - switch (silicon_type) { - case 0x00: - *major_revision = 1; - hw_type = HIF_9000_SILICON_VERSATILE; - break; - case 0x01: - case 0x02: /* CW1x00 */ - case 0x04: /* CW1x60 */ - *major_revision = silicon_type; - if (silicon_vers) - hw_type = HIF_8601_VERSATILE; - else - hw_type = HIF_8601_SILICON; - break; - default: - break; - } - - return hw_type; -} - -static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) -{ - int ret, block, num_blocks; - unsigned i; - u32 val32; - u32 put = 0, get = 0; - u8 *buf = NULL; - const char *fw_path; - const struct firmware *firmware = NULL; - - /* Macroses are local. */ -#define APB_WRITE(reg, val) \ - do { \ - ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ - if (ret < 0) \ - goto exit; \ - } while (0) -#define APB_WRITE2(reg, val) \ - do { \ - ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ - if (ret < 0) \ - goto free_buffer; \ - } while (0) -#define APB_READ(reg, val) \ - do { \ - ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \ - if (ret < 0) \ - goto free_buffer; \ - } while (0) -#define REG_WRITE(reg, val) \ - do { \ - ret = cw1200_reg_write_32(priv, (reg), (val)); \ - if (ret < 0) \ - goto exit; \ - } while (0) -#define REG_READ(reg, val) \ - do { \ - ret = cw1200_reg_read_32(priv, (reg), &(val)); \ - if (ret < 0) \ - goto exit; \ - } while (0) - - switch (priv->hw_revision) { - case CW1200_HW_REV_CUT10: - fw_path = FIRMWARE_CUT10; - if (!priv->sdd_path) - priv->sdd_path = SDD_FILE_10; - break; - case CW1200_HW_REV_CUT11: - fw_path = FIRMWARE_CUT11; - if (!priv->sdd_path) - priv->sdd_path = SDD_FILE_11; - break; - case CW1200_HW_REV_CUT20: - fw_path = FIRMWARE_CUT20; - if (!priv->sdd_path) - priv->sdd_path = SDD_FILE_20; - break; - case CW1200_HW_REV_CUT22: - fw_path = FIRMWARE_CUT22; - if (!priv->sdd_path) - priv->sdd_path = SDD_FILE_22; - break; - case CW1X60_HW_REV: - fw_path = FIRMWARE_CW1X60; - if (!priv->sdd_path) - priv->sdd_path = SDD_FILE_CW1X60; - break; - default: - pr_err("Invalid silicon revision %d.\n", priv->hw_revision); - return -EINVAL; - } - - /* Initialize common registers */ - APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, DOWNLOAD_ARE_YOU_HERE); - APB_WRITE(DOWNLOAD_PUT_REG, 0); - APB_WRITE(DOWNLOAD_GET_REG, 0); - APB_WRITE(DOWNLOAD_STATUS_REG, DOWNLOAD_PENDING); - APB_WRITE(DOWNLOAD_FLAGS_REG, 0); - - /* Write the NOP Instruction */ - REG_WRITE(ST90TDS_SRAM_BASE_ADDR_REG_ID, 0xFFF20000); - REG_WRITE(ST90TDS_AHB_DPORT_REG_ID, 0xEAFFFFFE); - - /* Release CPU from RESET */ - REG_READ(ST90TDS_CONFIG_REG_ID, val32); - val32 &= ~ST90TDS_CONFIG_CPU_RESET_BIT; - REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); - - /* Enable Clock */ - val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT; - REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); - - /* Load a firmware file */ - ret = request_firmware(&firmware, fw_path, priv->pdev); - if (ret) { - pr_err("Can't load firmware file %s.\n", fw_path); - goto exit; - } - - buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); - if (!buf) { - pr_err("Can't allocate firmware load buffer.\n"); - ret = -ENOMEM; - goto firmware_release; - } - - /* Check if the bootloader is ready */ - for (i = 0; i < 100; i += 1 + i / 2) { - APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); - if (val32 == DOWNLOAD_I_AM_HERE) - break; - mdelay(i); - } /* End of for loop */ - - if (val32 != DOWNLOAD_I_AM_HERE) { - pr_err("Bootloader is not ready.\n"); - ret = -ETIMEDOUT; - goto free_buffer; - } - - /* Calculcate number of download blocks */ - num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; - - /* Updating the length in Download Ctrl Area */ - val32 = firmware->size; /* Explicit cast from size_t to u32 */ - APB_WRITE2(DOWNLOAD_IMAGE_SIZE_REG, val32); - - /* Firmware downloading loop */ - for (block = 0; block < num_blocks; block++) { - size_t tx_size; - size_t block_size; - - /* check the download status */ - APB_READ(DOWNLOAD_STATUS_REG, val32); - if (val32 != DOWNLOAD_PENDING) { - pr_err("Bootloader reported error %d.\n", val32); - ret = -EIO; - goto free_buffer; - } - - /* loop until put - get <= 24K */ - for (i = 0; i < 100; i++) { - APB_READ(DOWNLOAD_GET_REG, get); - if ((put - get) <= - (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) - break; - mdelay(i); - } - - if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { - pr_err("Timeout waiting for FIFO.\n"); - ret = -ETIMEDOUT; - goto free_buffer; - } - - /* calculate the block size */ - tx_size = block_size = min_t(size_t, firmware->size - put, - DOWNLOAD_BLOCK_SIZE); - - memcpy(buf, &firmware->data[put], block_size); - if (block_size < DOWNLOAD_BLOCK_SIZE) { - memset(&buf[block_size], 0, - DOWNLOAD_BLOCK_SIZE - block_size); - tx_size = DOWNLOAD_BLOCK_SIZE; - } - - /* send the block to sram */ - ret = cw1200_apb_write(priv, - CW1200_APB(DOWNLOAD_FIFO_OFFSET + - (put & (DOWNLOAD_FIFO_SIZE - 1))), - buf, tx_size); - if (ret < 0) { - pr_err("Can't write firmware block @ %d!\n", - put & (DOWNLOAD_FIFO_SIZE - 1)); - goto free_buffer; - } - - /* update the put register */ - put += block_size; - APB_WRITE2(DOWNLOAD_PUT_REG, put); - } /* End of firmware download loop */ - - /* Wait for the download completion */ - for (i = 0; i < 300; i += 1 + i / 2) { - APB_READ(DOWNLOAD_STATUS_REG, val32); - if (val32 != DOWNLOAD_PENDING) - break; - mdelay(i); - } - if (val32 != DOWNLOAD_SUCCESS) { - pr_err("Wait for download completion failed: 0x%.8X\n", val32); - ret = -ETIMEDOUT; - goto free_buffer; - } else { - pr_info("Firmware download completed.\n"); - ret = 0; - } - -free_buffer: - kfree(buf); -firmware_release: - release_firmware(firmware); -exit: - return ret; - -#undef APB_WRITE -#undef APB_WRITE2 -#undef APB_READ -#undef REG_WRITE -#undef REG_READ -} - - -static int config_reg_read(struct cw1200_common *priv, u32 *val) -{ - switch (priv->hw_type) { - case HIF_9000_SILICON_VERSATILE: { - u16 val16; - int ret = cw1200_reg_read_16(priv, - ST90TDS_CONFIG_REG_ID, - &val16); - if (ret < 0) - return ret; - *val = val16; - return 0; - } - case HIF_8601_VERSATILE: - case HIF_8601_SILICON: - default: - cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, val); - break; - } - return 0; -} - -static int config_reg_write(struct cw1200_common *priv, u32 val) -{ - switch (priv->hw_type) { - case HIF_9000_SILICON_VERSATILE: - return cw1200_reg_write_16(priv, - ST90TDS_CONFIG_REG_ID, - (u16)val); - case HIF_8601_VERSATILE: - case HIF_8601_SILICON: - default: - return cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val); - } - return 0; -} - -int cw1200_load_firmware(struct cw1200_common *priv) -{ - int ret; - int i; - u32 val32; - u16 val16; - int major_revision = -1; - - /* Read CONFIG Register */ - ret = cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); - if (ret < 0) { - pr_err("Can't read config register.\n"); - goto out; - } - - if (val32 == 0 || val32 == 0xffffffff) { - pr_err("Bad config register value (0x%08x)\n", val32); - ret = -EIO; - goto out; - } - - priv->hw_type = cw1200_get_hw_type(val32, &major_revision); - if (priv->hw_type < 0) { - pr_err("Can't deduce hardware type.\n"); - ret = -ENOTSUPP; - goto out; - } - - /* Set DPLL Reg value, and read back to confirm writes work */ - ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, - cw1200_dpll_from_clk(priv->hw_refclk)); - if (ret < 0) { - pr_err("Can't write DPLL register.\n"); - goto out; - } - - msleep(20); - - ret = cw1200_reg_read_32(priv, - ST90TDS_TSET_GEN_R_W_REG_ID, &val32); - if (ret < 0) { - pr_err("Can't read DPLL register.\n"); - goto out; - } - - if (val32 != cw1200_dpll_from_clk(priv->hw_refclk)) { - pr_err("Unable to initialise DPLL register. Wrote 0x%.8X, Read 0x%.8X.\n", - cw1200_dpll_from_clk(priv->hw_refclk), val32); - ret = -EIO; - goto out; - } - - /* Set wakeup bit in device */ - ret = cw1200_reg_read_16(priv, ST90TDS_CONTROL_REG_ID, &val16); - if (ret < 0) { - pr_err("set_wakeup: can't read control register.\n"); - goto out; - } - - ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, - val16 | ST90TDS_CONT_WUP_BIT); - if (ret < 0) { - pr_err("set_wakeup: can't write control register.\n"); - goto out; - } - - /* Wait for wakeup */ - for (i = 0; i < 300; i += (1 + i / 2)) { - ret = cw1200_reg_read_16(priv, - ST90TDS_CONTROL_REG_ID, &val16); - if (ret < 0) { - pr_err("wait_for_wakeup: can't read control register.\n"); - goto out; - } - - if (val16 & ST90TDS_CONT_RDY_BIT) - break; - - msleep(i); - } - - if ((val16 & ST90TDS_CONT_RDY_BIT) == 0) { - pr_err("wait_for_wakeup: device is not responding.\n"); - ret = -ETIMEDOUT; - goto out; - } - - switch (major_revision) { - case 1: - /* CW1200 Hardware detection logic : Check for CUT1.1 */ - ret = cw1200_ahb_read_32(priv, CW1200_CUT_ID_ADDR, &val32); - if (ret) { - pr_err("HW detection: can't read CUT ID.\n"); - goto out; - } - - switch (val32) { - case CW1200_CUT_11_ID_STR: - pr_info("CW1x00 Cut 1.1 silicon detected.\n"); - priv->hw_revision = CW1200_HW_REV_CUT11; - break; - default: - pr_info("CW1x00 Cut 1.0 silicon detected.\n"); - priv->hw_revision = CW1200_HW_REV_CUT10; - break; - } - - /* According to ST-E, CUT<2.0 has busted BA TID0-3. - Just disable it entirely... - */ - priv->ba_rx_tid_mask = 0; - priv->ba_tx_tid_mask = 0; - break; - case 2: { - u32 ar1, ar2, ar3; - ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR, &ar1); - if (ret) { - pr_err("(1) HW detection: can't read CUT ID\n"); - goto out; - } - ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 4, &ar2); - if (ret) { - pr_err("(2) HW detection: can't read CUT ID.\n"); - goto out; - } - - ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 8, &ar3); - if (ret) { - pr_err("(3) HW detection: can't read CUT ID.\n"); - goto out; - } - - if (ar1 == CW1200_CUT_22_ID_STR1 && - ar2 == CW1200_CUT_22_ID_STR2 && - ar3 == CW1200_CUT_22_ID_STR3) { - pr_info("CW1x00 Cut 2.2 silicon detected.\n"); - priv->hw_revision = CW1200_HW_REV_CUT22; - } else { - pr_info("CW1x00 Cut 2.0 silicon detected.\n"); - priv->hw_revision = CW1200_HW_REV_CUT20; - } - break; - } - case 4: - pr_info("CW1x60 silicon detected.\n"); - priv->hw_revision = CW1X60_HW_REV; - break; - default: - pr_err("Unsupported silicon major revision %d.\n", - major_revision); - ret = -ENOTSUPP; - goto out; - } - - /* Checking for access mode */ - ret = config_reg_read(priv, &val32); - if (ret < 0) { - pr_err("Can't read config register.\n"); - goto out; - } - - if (!(val32 & ST90TDS_CONFIG_ACCESS_MODE_BIT)) { - pr_err("Device is already in QUEUE mode!\n"); - ret = -EINVAL; - goto out; - } - - switch (priv->hw_type) { - case HIF_8601_SILICON: - if (priv->hw_revision == CW1X60_HW_REV) { - pr_err("Can't handle CW1160/1260 firmware load yet.\n"); - ret = -ENOTSUPP; - goto out; - } - ret = cw1200_load_firmware_cw1200(priv); - break; - default: - pr_err("Can't perform firmware load for hw type %d.\n", - priv->hw_type); - ret = -ENOTSUPP; - goto out; - } - if (ret < 0) { - pr_err("Firmware load error.\n"); - goto out; - } - - /* Enable interrupt signalling */ - priv->hwbus_ops->lock(priv->hwbus_priv); - ret = __cw1200_irq_enable(priv, 1); - priv->hwbus_ops->unlock(priv->hwbus_priv); - if (ret < 0) - goto unsubscribe; - - /* Configure device for MESSSAGE MODE */ - ret = config_reg_read(priv, &val32); - if (ret < 0) { - pr_err("Can't read config register.\n"); - goto unsubscribe; - } - ret = config_reg_write(priv, val32 & ~ST90TDS_CONFIG_ACCESS_MODE_BIT); - if (ret < 0) { - pr_err("Can't write config register.\n"); - goto unsubscribe; - } - - /* Unless we read the CONFIG Register we are - * not able to get an interrupt - */ - mdelay(10); - config_reg_read(priv, &val32); - -out: - return ret; - -unsubscribe: - /* Disable interrupt signalling */ - priv->hwbus_ops->lock(priv->hwbus_priv); - ret = __cw1200_irq_enable(priv, 0); - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} diff --git a/drivers/net/wireless/cw1200/fwio.h b/drivers/net/wireless/cw1200/fwio.h deleted file mode 100644 index ea30993..0000000 --- a/drivers/net/wireless/cw1200/fwio.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Firmware API for mac80211 ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on: - * ST-Ericsson UMAC CW1200 driver which is - * Copyright (c) 2010, ST-Ericsson - * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FWIO_H_INCLUDED -#define FWIO_H_INCLUDED - -#define BOOTLOADER_CW1X60 "boot_cw1x60.bin" -#define FIRMWARE_CW1X60 "wsm_cw1x60.bin" -#define FIRMWARE_CUT22 "wsm_22.bin" -#define FIRMWARE_CUT20 "wsm_20.bin" -#define FIRMWARE_CUT11 "wsm_11.bin" -#define FIRMWARE_CUT10 "wsm_10.bin" -#define SDD_FILE_CW1X60 "sdd_cw1x60.bin" -#define SDD_FILE_22 "sdd_22.bin" -#define SDD_FILE_20 "sdd_20.bin" -#define SDD_FILE_11 "sdd_11.bin" -#define SDD_FILE_10 "sdd_10.bin" - -int cw1200_load_firmware(struct cw1200_common *priv); - -/* SDD definitions */ -#define SDD_PTA_CFG_ELT_ID 0xEB -#define SDD_REFERENCE_FREQUENCY_ELT_ID 0xc5 -u32 cw1200_dpll_from_clk(u16 clk); - -#endif diff --git a/drivers/net/wireless/cw1200/hwbus.h b/drivers/net/wireless/cw1200/hwbus.h deleted file mode 100644 index 8b2fc83..0000000 --- a/drivers/net/wireless/cw1200/hwbus.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Common hwbus abstraction layer interface for cw1200 wireless driver - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_HWBUS_H -#define CW1200_HWBUS_H - -struct hwbus_priv; - -void cw1200_irq_handler(struct cw1200_common *priv); - -/* This MUST be wrapped with hwbus_ops->lock/unlock! */ -int __cw1200_irq_enable(struct cw1200_common *priv, int enable); - -struct hwbus_ops { - int (*hwbus_memcpy_fromio)(struct hwbus_priv *self, unsigned int addr, - void *dst, int count); - int (*hwbus_memcpy_toio)(struct hwbus_priv *self, unsigned int addr, - const void *src, int count); - void (*lock)(struct hwbus_priv *self); - void (*unlock)(struct hwbus_priv *self); - size_t (*align_size)(struct hwbus_priv *self, size_t size); - int (*power_mgmt)(struct hwbus_priv *self, bool suspend); -}; - -#endif /* CW1200_HWBUS_H */ diff --git a/drivers/net/wireless/cw1200/hwio.c b/drivers/net/wireless/cw1200/hwio.c deleted file mode 100644 index ff230b7..0000000 --- a/drivers/net/wireless/cw1200/hwio.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Low-level device IO routines for ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on: - * ST-Ericsson UMAC CW1200 driver, which is - * Copyright (c) 2010, ST-Ericsson - * Author: Ajitpal Singh <ajitpal.singh@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/types.h> - -#include "cw1200.h" -#include "hwio.h" -#include "hwbus.h" - - /* Sdio addr is 4*spi_addr */ -#define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2) -#define SDIO_ADDR17BIT(buf_id, mpf, rfu, reg_id_ofs) \ - ((((buf_id) & 0x1F) << 7) \ - | (((mpf) & 1) << 6) \ - | (((rfu) & 1) << 5) \ - | (((reg_id_ofs) & 0x1F) << 0)) -#define MAX_RETRY 3 - - -static int __cw1200_reg_read(struct cw1200_common *priv, u16 addr, - void *buf, size_t buf_len, int buf_id) -{ - u16 addr_sdio; - u32 sdio_reg_addr_17bit; - - /* Check if buffer is aligned to 4 byte boundary */ - if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { - pr_err("buffer is not aligned.\n"); - return -EINVAL; - } - - /* Convert to SDIO Register Address */ - addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); - sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); - - return priv->hwbus_ops->hwbus_memcpy_fromio(priv->hwbus_priv, - sdio_reg_addr_17bit, - buf, buf_len); -} - -static int __cw1200_reg_write(struct cw1200_common *priv, u16 addr, - const void *buf, size_t buf_len, int buf_id) -{ - u16 addr_sdio; - u32 sdio_reg_addr_17bit; - - /* Convert to SDIO Register Address */ - addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); - sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); - - return priv->hwbus_ops->hwbus_memcpy_toio(priv->hwbus_priv, - sdio_reg_addr_17bit, - buf, buf_len); -} - -static inline int __cw1200_reg_read_32(struct cw1200_common *priv, - u16 addr, u32 *val) -{ - __le32 tmp; - int i = __cw1200_reg_read(priv, addr, &tmp, sizeof(tmp), 0); - *val = le32_to_cpu(tmp); - return i; -} - -static inline int __cw1200_reg_write_32(struct cw1200_common *priv, - u16 addr, u32 val) -{ - __le32 tmp = cpu_to_le32(val); - return __cw1200_reg_write(priv, addr, &tmp, sizeof(tmp), 0); -} - -static inline int __cw1200_reg_read_16(struct cw1200_common *priv, - u16 addr, u16 *val) -{ - __le16 tmp; - int i = __cw1200_reg_read(priv, addr, &tmp, sizeof(tmp), 0); - *val = le16_to_cpu(tmp); - return i; -} - -static inline int __cw1200_reg_write_16(struct cw1200_common *priv, - u16 addr, u16 val) -{ - __le16 tmp = cpu_to_le16(val); - return __cw1200_reg_write(priv, addr, &tmp, sizeof(tmp), 0); -} - -int cw1200_reg_read(struct cw1200_common *priv, u16 addr, void *buf, - size_t buf_len) -{ - int ret; - priv->hwbus_ops->lock(priv->hwbus_priv); - ret = __cw1200_reg_read(priv, addr, buf, buf_len, 0); - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} - -int cw1200_reg_write(struct cw1200_common *priv, u16 addr, const void *buf, - size_t buf_len) -{ - int ret; - priv->hwbus_ops->lock(priv->hwbus_priv); - ret = __cw1200_reg_write(priv, addr, buf, buf_len, 0); - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} - -int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len) -{ - int ret, retry = 1; - int buf_id_rx = priv->buf_id_rx; - - priv->hwbus_ops->lock(priv->hwbus_priv); - - while (retry <= MAX_RETRY) { - ret = __cw1200_reg_read(priv, - ST90TDS_IN_OUT_QUEUE_REG_ID, buf, - buf_len, buf_id_rx + 1); - if (!ret) { - buf_id_rx = (buf_id_rx + 1) & 3; - priv->buf_id_rx = buf_id_rx; - break; - } else { - retry++; - mdelay(1); - pr_err("error :[%d]\n", ret); - } - } - - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} - -int cw1200_data_write(struct cw1200_common *priv, const void *buf, - size_t buf_len) -{ - int ret, retry = 1; - int buf_id_tx = priv->buf_id_tx; - - priv->hwbus_ops->lock(priv->hwbus_priv); - - while (retry <= MAX_RETRY) { - ret = __cw1200_reg_write(priv, - ST90TDS_IN_OUT_QUEUE_REG_ID, buf, - buf_len, buf_id_tx); - if (!ret) { - buf_id_tx = (buf_id_tx + 1) & 31; - priv->buf_id_tx = buf_id_tx; - break; - } else { - retry++; - mdelay(1); - pr_err("error :[%d]\n", ret); - } - } - - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} - -int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, - size_t buf_len, u32 prefetch, u16 port_addr) -{ - u32 val32 = 0; - int i, ret; - - if ((buf_len / 2) >= 0x1000) { - pr_err("Can't read more than 0xfff words.\n"); - return -EINVAL; - } - - priv->hwbus_ops->lock(priv->hwbus_priv); - /* Write address */ - ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); - if (ret < 0) { - pr_err("Can't write address register.\n"); - goto out; - } - - /* Read CONFIG Register Value - We will read 32 bits */ - ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); - if (ret < 0) { - pr_err("Can't read config register.\n"); - goto out; - } - - /* Set PREFETCH bit */ - ret = __cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, - val32 | prefetch); - if (ret < 0) { - pr_err("Can't write prefetch bit.\n"); - goto out; - } - - /* Check for PRE-FETCH bit to be cleared */ - for (i = 0; i < 20; i++) { - ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); - if (ret < 0) { - pr_err("Can't check prefetch bit.\n"); - goto out; - } - if (!(val32 & prefetch)) - break; - - mdelay(i); - } - - if (val32 & prefetch) { - pr_err("Prefetch bit is not cleared.\n"); - goto out; - } - - /* Read data port */ - ret = __cw1200_reg_read(priv, port_addr, buf, buf_len, 0); - if (ret < 0) { - pr_err("Can't read data port.\n"); - goto out; - } - -out: - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} - -int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, - size_t buf_len) -{ - int ret; - - if ((buf_len / 2) >= 0x1000) { - pr_err("Can't write more than 0xfff words.\n"); - return -EINVAL; - } - - priv->hwbus_ops->lock(priv->hwbus_priv); - - /* Write address */ - ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); - if (ret < 0) { - pr_err("Can't write address register.\n"); - goto out; - } - - /* Write data port */ - ret = __cw1200_reg_write(priv, ST90TDS_SRAM_DPORT_REG_ID, - buf, buf_len, 0); - if (ret < 0) { - pr_err("Can't write data port.\n"); - goto out; - } - -out: - priv->hwbus_ops->unlock(priv->hwbus_priv); - return ret; -} - -int __cw1200_irq_enable(struct cw1200_common *priv, int enable) -{ - u32 val32; - u16 val16; - int ret; - - if (HIF_8601_SILICON == priv->hw_type) { - ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); - if (ret < 0) { - pr_err("Can't read config register.\n"); - return ret; - } - - if (enable) - val32 |= ST90TDS_CONF_IRQ_RDY_ENABLE; - else - val32 &= ~ST90TDS_CONF_IRQ_RDY_ENABLE; - - ret = __cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val32); - if (ret < 0) { - pr_err("Can't write config register.\n"); - return ret; - } - } else { - ret = __cw1200_reg_read_16(priv, ST90TDS_CONFIG_REG_ID, &val16); - if (ret < 0) { - pr_err("Can't read control register.\n"); - return ret; - } - - if (enable) - val16 |= ST90TDS_CONT_IRQ_RDY_ENABLE; - else - val16 &= ~ST90TDS_CONT_IRQ_RDY_ENABLE; - - ret = __cw1200_reg_write_16(priv, ST90TDS_CONFIG_REG_ID, val16); - if (ret < 0) { - pr_err("Can't write control register.\n"); - return ret; - } - } - return 0; -} diff --git a/drivers/net/wireless/cw1200/hwio.h b/drivers/net/wireless/cw1200/hwio.h deleted file mode 100644 index ddf5266..0000000 --- a/drivers/net/wireless/cw1200/hwio.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Low-level API for mac80211 ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on: - * ST-Ericsson UMAC CW1200 driver which is - * Copyright (c) 2010, ST-Ericsson - * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_HWIO_H_INCLUDED -#define CW1200_HWIO_H_INCLUDED - -/* extern */ struct cw1200_common; - -#define CW1200_CUT_11_ID_STR (0x302E3830) -#define CW1200_CUT_22_ID_STR1 (0x302e3132) -#define CW1200_CUT_22_ID_STR2 (0x32302e30) -#define CW1200_CUT_22_ID_STR3 (0x3335) -#define CW1200_CUT_ID_ADDR (0xFFF17F90) -#define CW1200_CUT2_ID_ADDR (0xFFF1FF90) - -/* Download control area */ -/* boot loader start address in SRAM */ -#define DOWNLOAD_BOOT_LOADER_OFFSET (0x00000000) -/* 32K, 0x4000 to 0xDFFF */ -#define DOWNLOAD_FIFO_OFFSET (0x00004000) -/* 32K */ -#define DOWNLOAD_FIFO_SIZE (0x00008000) -/* 128 bytes, 0xFF80 to 0xFFFF */ -#define DOWNLOAD_CTRL_OFFSET (0x0000FF80) -#define DOWNLOAD_CTRL_DATA_DWORDS (32-6) - -struct download_cntl_t { - /* size of whole firmware file (including Cheksum), host init */ - u32 image_size; - /* downloading flags */ - u32 flags; - /* No. of bytes put into the download, init & updated by host */ - u32 put; - /* last traced program counter, last ARM reg_pc */ - u32 trace_pc; - /* No. of bytes read from the download, host init, device updates */ - u32 get; - /* r0, boot losader status, host init to pending, device updates */ - u32 status; - /* Extra debug info, r1 to r14 if status=r0=DOWNLOAD_EXCEPTION */ - u32 debug_data[DOWNLOAD_CTRL_DATA_DWORDS]; -}; - -#define DOWNLOAD_IMAGE_SIZE_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, image_size)) -#define DOWNLOAD_FLAGS_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, flags)) -#define DOWNLOAD_PUT_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, put)) -#define DOWNLOAD_TRACE_PC_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, trace_pc)) -#define DOWNLOAD_GET_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, get)) -#define DOWNLOAD_STATUS_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, status)) -#define DOWNLOAD_DEBUG_DATA_REG \ - (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, debug_data)) -#define DOWNLOAD_DEBUG_DATA_LEN (108) - -#define DOWNLOAD_BLOCK_SIZE (1024) - -/* For boot loader detection */ -#define DOWNLOAD_ARE_YOU_HERE (0x87654321) -#define DOWNLOAD_I_AM_HERE (0x12345678) - -/* Download error code */ -#define DOWNLOAD_PENDING (0xFFFFFFFF) -#define DOWNLOAD_SUCCESS (0) -#define DOWNLOAD_EXCEPTION (1) -#define DOWNLOAD_ERR_MEM_1 (2) -#define DOWNLOAD_ERR_MEM_2 (3) -#define DOWNLOAD_ERR_SOFTWARE (4) -#define DOWNLOAD_ERR_FILE_SIZE (5) -#define DOWNLOAD_ERR_CHECKSUM (6) -#define DOWNLOAD_ERR_OVERFLOW (7) -#define DOWNLOAD_ERR_IMAGE (8) -#define DOWNLOAD_ERR_HOST (9) -#define DOWNLOAD_ERR_ABORT (10) - - -#define SYS_BASE_ADDR_SILICON (0) -#define PAC_BASE_ADDRESS_SILICON (SYS_BASE_ADDR_SILICON + 0x09000000) -#define PAC_SHARED_MEMORY_SILICON (PAC_BASE_ADDRESS_SILICON) - -#define CW1200_APB(addr) (PAC_SHARED_MEMORY_SILICON + (addr)) - -/* Device register definitions */ - -/* WBF - SPI Register Addresses */ -#define ST90TDS_ADDR_ID_BASE (0x0000) -/* 16/32 bits */ -#define ST90TDS_CONFIG_REG_ID (0x0000) -/* 16/32 bits */ -#define ST90TDS_CONTROL_REG_ID (0x0001) -/* 16 bits, Q mode W/R */ -#define ST90TDS_IN_OUT_QUEUE_REG_ID (0x0002) -/* 32 bits, AHB bus R/W */ -#define ST90TDS_AHB_DPORT_REG_ID (0x0003) -/* 16/32 bits */ -#define ST90TDS_SRAM_BASE_ADDR_REG_ID (0x0004) -/* 32 bits, APB bus R/W */ -#define ST90TDS_SRAM_DPORT_REG_ID (0x0005) -/* 32 bits, t_settle/general */ -#define ST90TDS_TSET_GEN_R_W_REG_ID (0x0006) -/* 16 bits, Q mode read, no length */ -#define ST90TDS_FRAME_OUT_REG_ID (0x0007) -#define ST90TDS_ADDR_ID_MAX (ST90TDS_FRAME_OUT_REG_ID) - -/* WBF - Control register bit set */ -/* next o/p length, bit 11 to 0 */ -#define ST90TDS_CONT_NEXT_LEN_MASK (0x0FFF) -#define ST90TDS_CONT_WUP_BIT (BIT(12)) -#define ST90TDS_CONT_RDY_BIT (BIT(13)) -#define ST90TDS_CONT_IRQ_ENABLE (BIT(14)) -#define ST90TDS_CONT_RDY_ENABLE (BIT(15)) -#define ST90TDS_CONT_IRQ_RDY_ENABLE (BIT(14)|BIT(15)) - -/* SPI Config register bit set */ -#define ST90TDS_CONFIG_FRAME_BIT (BIT(2)) -#define ST90TDS_CONFIG_WORD_MODE_BITS (BIT(3)|BIT(4)) -#define ST90TDS_CONFIG_WORD_MODE_1 (BIT(3)) -#define ST90TDS_CONFIG_WORD_MODE_2 (BIT(4)) -#define ST90TDS_CONFIG_ERROR_0_BIT (BIT(5)) -#define ST90TDS_CONFIG_ERROR_1_BIT (BIT(6)) -#define ST90TDS_CONFIG_ERROR_2_BIT (BIT(7)) -/* TBD: Sure??? */ -#define ST90TDS_CONFIG_CSN_FRAME_BIT (BIT(7)) -#define ST90TDS_CONFIG_ERROR_3_BIT (BIT(8)) -#define ST90TDS_CONFIG_ERROR_4_BIT (BIT(9)) -/* QueueM */ -#define ST90TDS_CONFIG_ACCESS_MODE_BIT (BIT(10)) -/* AHB bus */ -#define ST90TDS_CONFIG_AHB_PRFETCH_BIT (BIT(11)) -#define ST90TDS_CONFIG_CPU_CLK_DIS_BIT (BIT(12)) -/* APB bus */ -#define ST90TDS_CONFIG_PRFETCH_BIT (BIT(13)) -/* cpu reset */ -#define ST90TDS_CONFIG_CPU_RESET_BIT (BIT(14)) -#define ST90TDS_CONFIG_CLEAR_INT_BIT (BIT(15)) - -/* For CW1200 the IRQ Enable and Ready Bits are in CONFIG register */ -#define ST90TDS_CONF_IRQ_ENABLE (BIT(16)) -#define ST90TDS_CONF_RDY_ENABLE (BIT(17)) -#define ST90TDS_CONF_IRQ_RDY_ENABLE (BIT(16)|BIT(17)) - -int cw1200_data_read(struct cw1200_common *priv, - void *buf, size_t buf_len); -int cw1200_data_write(struct cw1200_common *priv, - const void *buf, size_t buf_len); - -int cw1200_reg_read(struct cw1200_common *priv, u16 addr, - void *buf, size_t buf_len); -int cw1200_reg_write(struct cw1200_common *priv, u16 addr, - const void *buf, size_t buf_len); - -static inline int cw1200_reg_read_16(struct cw1200_common *priv, - u16 addr, u16 *val) -{ - __le32 tmp; - int i; - i = cw1200_reg_read(priv, addr, &tmp, sizeof(tmp)); - *val = le32_to_cpu(tmp) & 0xfffff; - return i; -} - -static inline int cw1200_reg_write_16(struct cw1200_common *priv, - u16 addr, u16 val) -{ - __le32 tmp = cpu_to_le32((u32)val); - return cw1200_reg_write(priv, addr, &tmp, sizeof(tmp)); -} - -static inline int cw1200_reg_read_32(struct cw1200_common *priv, - u16 addr, u32 *val) -{ - __le32 tmp; - int i = cw1200_reg_read(priv, addr, &tmp, sizeof(tmp)); - *val = le32_to_cpu(tmp); - return i; -} - -static inline int cw1200_reg_write_32(struct cw1200_common *priv, - u16 addr, u32 val) -{ - __le32 tmp = cpu_to_le32(val); - return cw1200_reg_write(priv, addr, &tmp, sizeof(val)); -} - -int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, - size_t buf_len, u32 prefetch, u16 port_addr); -int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, - size_t buf_len); - -static inline int cw1200_apb_read(struct cw1200_common *priv, u32 addr, - void *buf, size_t buf_len) -{ - return cw1200_indirect_read(priv, addr, buf, buf_len, - ST90TDS_CONFIG_PRFETCH_BIT, - ST90TDS_SRAM_DPORT_REG_ID); -} - -static inline int cw1200_ahb_read(struct cw1200_common *priv, u32 addr, - void *buf, size_t buf_len) -{ - return cw1200_indirect_read(priv, addr, buf, buf_len, - ST90TDS_CONFIG_AHB_PRFETCH_BIT, - ST90TDS_AHB_DPORT_REG_ID); -} - -static inline int cw1200_apb_read_32(struct cw1200_common *priv, - u32 addr, u32 *val) -{ - __le32 tmp; - int i = cw1200_apb_read(priv, addr, &tmp, sizeof(tmp)); - *val = le32_to_cpu(tmp); - return i; -} - -static inline int cw1200_apb_write_32(struct cw1200_common *priv, - u32 addr, u32 val) -{ - __le32 tmp = cpu_to_le32(val); - return cw1200_apb_write(priv, addr, &tmp, sizeof(val)); -} -static inline int cw1200_ahb_read_32(struct cw1200_common *priv, - u32 addr, u32 *val) -{ - __le32 tmp; - int i = cw1200_ahb_read(priv, addr, &tmp, sizeof(tmp)); - *val = le32_to_cpu(tmp); - return i; -} - -#endif /* CW1200_HWIO_H_INCLUDED */ diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c deleted file mode 100644 index 0e51e27..0000000 --- a/drivers/net/wireless/cw1200/main.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on: - * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> - * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de> - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * Based on: - * - the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. - * - stlc45xx driver - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/firmware.h> -#include <linux/etherdevice.h> -#include <linux/vmalloc.h> -#include <linux/random.h> -#include <linux/sched.h> -#include <net/mac80211.h> - -#include "cw1200.h" -#include "txrx.h" -#include "hwbus.h" -#include "fwio.h" -#include "hwio.h" -#include "bh.h" -#include "sta.h" -#include "scan.h" -#include "debug.h" -#include "pm.h" - -MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>"); -MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("cw1200_core"); - -/* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */ -static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00}; -module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, S_IRUGO); -MODULE_PARM_DESC(macaddr, "Override platform_data MAC address"); - -static char *cw1200_sdd_path; -module_param(cw1200_sdd_path, charp, 0644); -MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file"); -static int cw1200_refclk; -module_param(cw1200_refclk, int, 0644); -MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock"); - -int cw1200_power_mode = wsm_power_mode_quiescent; -module_param(cw1200_power_mode, int, 0644); -MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode. 0 == active, 1 == doze, 2 == quiescent (default)"); - -#define RATETAB_ENT(_rate, _rateid, _flags) \ - { \ - .bitrate = (_rate), \ - .hw_value = (_rateid), \ - .flags = (_flags), \ - } - -static struct ieee80211_rate cw1200_rates[] = { - RATETAB_ENT(10, 0, 0), - RATETAB_ENT(20, 1, 0), - RATETAB_ENT(55, 2, 0), - RATETAB_ENT(110, 3, 0), - RATETAB_ENT(60, 6, 0), - RATETAB_ENT(90, 7, 0), - RATETAB_ENT(120, 8, 0), - RATETAB_ENT(180, 9, 0), - RATETAB_ENT(240, 10, 0), - RATETAB_ENT(360, 11, 0), - RATETAB_ENT(480, 12, 0), - RATETAB_ENT(540, 13, 0), -}; - -static struct ieee80211_rate cw1200_mcs_rates[] = { - RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), - RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), - RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), - RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), - RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), - RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), - RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), - RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), -}; - -#define cw1200_a_rates (cw1200_rates + 4) -#define cw1200_a_rates_size (ARRAY_SIZE(cw1200_rates) - 4) -#define cw1200_g_rates (cw1200_rates + 0) -#define cw1200_g_rates_size (ARRAY_SIZE(cw1200_rates)) -#define cw1200_n_rates (cw1200_mcs_rates) -#define cw1200_n_rates_size (ARRAY_SIZE(cw1200_mcs_rates)) - - -#define CHAN2G(_channel, _freq, _flags) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -#define CHAN5G(_channel, _flags) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = 5000 + (5 * (_channel)), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -static struct ieee80211_channel cw1200_2ghz_chantable[] = { - CHAN2G(1, 2412, 0), - CHAN2G(2, 2417, 0), - CHAN2G(3, 2422, 0), - CHAN2G(4, 2427, 0), - CHAN2G(5, 2432, 0), - CHAN2G(6, 2437, 0), - CHAN2G(7, 2442, 0), - CHAN2G(8, 2447, 0), - CHAN2G(9, 2452, 0), - CHAN2G(10, 2457, 0), - CHAN2G(11, 2462, 0), - CHAN2G(12, 2467, 0), - CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), -}; - -static struct ieee80211_channel cw1200_5ghz_chantable[] = { - CHAN5G(34, 0), CHAN5G(36, 0), - CHAN5G(38, 0), CHAN5G(40, 0), - CHAN5G(42, 0), CHAN5G(44, 0), - CHAN5G(46, 0), CHAN5G(48, 0), - CHAN5G(52, 0), CHAN5G(56, 0), - CHAN5G(60, 0), CHAN5G(64, 0), - CHAN5G(100, 0), CHAN5G(104, 0), - CHAN5G(108, 0), CHAN5G(112, 0), - CHAN5G(116, 0), CHAN5G(120, 0), - CHAN5G(124, 0), CHAN5G(128, 0), - CHAN5G(132, 0), CHAN5G(136, 0), - CHAN5G(140, 0), CHAN5G(149, 0), - CHAN5G(153, 0), CHAN5G(157, 0), - CHAN5G(161, 0), CHAN5G(165, 0), - CHAN5G(184, 0), CHAN5G(188, 0), - CHAN5G(192, 0), CHAN5G(196, 0), - CHAN5G(200, 0), CHAN5G(204, 0), - CHAN5G(208, 0), CHAN5G(212, 0), - CHAN5G(216, 0), -}; - -static struct ieee80211_supported_band cw1200_band_2ghz = { - .channels = cw1200_2ghz_chantable, - .n_channels = ARRAY_SIZE(cw1200_2ghz_chantable), - .bitrates = cw1200_g_rates, - .n_bitrates = cw1200_g_rates_size, - .ht_cap = { - .cap = IEEE80211_HT_CAP_GRN_FLD | - (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | - IEEE80211_HT_CAP_MAX_AMSDU, - .ht_supported = 1, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, - .mcs = { - .rx_mask[0] = 0xFF, - .rx_highest = __cpu_to_le16(0x41), - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, - }, - }, -}; - -static struct ieee80211_supported_band cw1200_band_5ghz = { - .channels = cw1200_5ghz_chantable, - .n_channels = ARRAY_SIZE(cw1200_5ghz_chantable), - .bitrates = cw1200_a_rates, - .n_bitrates = cw1200_a_rates_size, - .ht_cap = { - .cap = IEEE80211_HT_CAP_GRN_FLD | - (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | - IEEE80211_HT_CAP_MAX_AMSDU, - .ht_supported = 1, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, - .mcs = { - .rx_mask[0] = 0xFF, - .rx_highest = __cpu_to_le16(0x41), - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, - }, - }, -}; - -static const unsigned long cw1200_ttl[] = { - 1 * HZ, /* VO */ - 2 * HZ, /* VI */ - 5 * HZ, /* BE */ - 10 * HZ /* BK */ -}; - -static const struct ieee80211_ops cw1200_ops = { - .start = cw1200_start, - .stop = cw1200_stop, - .add_interface = cw1200_add_interface, - .remove_interface = cw1200_remove_interface, - .change_interface = cw1200_change_interface, - .tx = cw1200_tx, - .hw_scan = cw1200_hw_scan, - .set_tim = cw1200_set_tim, - .sta_notify = cw1200_sta_notify, - .sta_add = cw1200_sta_add, - .sta_remove = cw1200_sta_remove, - .set_key = cw1200_set_key, - .set_rts_threshold = cw1200_set_rts_threshold, - .config = cw1200_config, - .bss_info_changed = cw1200_bss_info_changed, - .prepare_multicast = cw1200_prepare_multicast, - .configure_filter = cw1200_configure_filter, - .conf_tx = cw1200_conf_tx, - .get_stats = cw1200_get_stats, - .ampdu_action = cw1200_ampdu_action, - .flush = cw1200_flush, -#ifdef CONFIG_PM - .suspend = cw1200_wow_suspend, - .resume = cw1200_wow_resume, -#endif - /* Intentionally not offloaded: */ - /*.channel_switch = cw1200_channel_switch, */ - /*.remain_on_channel = cw1200_remain_on_channel, */ - /*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel, */ -}; - -static int cw1200_ba_rx_tids = -1; -static int cw1200_ba_tx_tids = -1; -module_param(cw1200_ba_rx_tids, int, 0644); -module_param(cw1200_ba_tx_tids, int, 0644); -MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs"); -MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs"); - -#ifdef CONFIG_PM -static const struct wiphy_wowlan_support cw1200_wowlan_support = { - /* Support only for limited wowlan functionalities */ - .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT, -}; -#endif - - -static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, - const bool have_5ghz) -{ - int i, band; - struct ieee80211_hw *hw; - struct cw1200_common *priv; - - hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops); - if (!hw) - return NULL; - - priv = hw->priv; - priv->hw = hw; - priv->hw_type = -1; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->rates = cw1200_rates; /* TODO: fetch from FW */ - priv->mcs_rates = cw1200_n_rates; - if (cw1200_ba_rx_tids != -1) - priv->ba_rx_tid_mask = cw1200_ba_rx_tids; - else - priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */ - if (cw1200_ba_tx_tids != -1) - priv->ba_tx_tid_mask = cw1200_ba_tx_tids; - else - priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */ - - ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); - ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); - ieee80211_hw_set(hw, AMPDU_AGGREGATION); - ieee80211_hw_set(hw, CONNECTION_MONITOR); - ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); - ieee80211_hw_set(hw, SIGNAL_DBM); - ieee80211_hw_set(hw, SUPPORTS_PS); - - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); - -#ifdef CONFIG_PM - hw->wiphy->wowlan = &cw1200_wowlan_support; -#endif - - hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - - hw->queues = 4; - - priv->rts_threshold = -1; - - hw->max_rates = 8; - hw->max_rate_tries = 15; - hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + - 8; /* TKIP IV */ - - hw->sta_data_size = sizeof(struct cw1200_sta_priv); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz; - if (have_5ghz) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz; - - /* Channel params have to be cleared before registering wiphy again */ - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; - if (!sband) - continue; - for (i = 0; i < sband->n_channels; i++) { - sband->channels[i].flags = 0; - sband->channels[i].max_antenna_gain = 0; - sband->channels[i].max_power = 30; - } - } - - hw->wiphy->max_scan_ssids = 2; - hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - - if (macaddr) - SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr); - else - SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template); - - /* Fix up mac address if necessary */ - if (hw->wiphy->perm_addr[3] == 0 && - hw->wiphy->perm_addr[4] == 0 && - hw->wiphy->perm_addr[5] == 0) { - get_random_bytes(&hw->wiphy->perm_addr[3], 3); - } - - mutex_init(&priv->wsm_cmd_mux); - mutex_init(&priv->conf_mutex); - priv->workqueue = create_singlethread_workqueue("cw1200_wq"); - sema_init(&priv->scan.lock, 1); - INIT_WORK(&priv->scan.work, cw1200_scan_work); - INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); - INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout); - INIT_DELAYED_WORK(&priv->clear_recent_scan_work, - cw1200_clear_recent_scan_work); - INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout); - INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work); - INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work); - INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work); - INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work); - spin_lock_init(&priv->event_queue_lock); - INIT_LIST_HEAD(&priv->event_queue); - INIT_WORK(&priv->event_handler, cw1200_event_handler); - INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work); - INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work); - spin_lock_init(&priv->bss_loss_lock); - spin_lock_init(&priv->ps_state_lock); - INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work); - INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work); - INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work); - INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work); - INIT_WORK(&priv->link_id_work, cw1200_link_id_work); - INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work); - INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset); - INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); - INIT_WORK(&priv->set_beacon_wakeup_period_work, - cw1200_set_beacon_wakeup_period_work); - setup_timer(&priv->mcast_timeout, cw1200_mcast_timeout, - (unsigned long)priv); - - if (cw1200_queue_stats_init(&priv->tx_queue_stats, - CW1200_LINK_ID_MAX, - cw1200_skb_dtor, - priv)) { - ieee80211_free_hw(hw); - return NULL; - } - - for (i = 0; i < 4; ++i) { - if (cw1200_queue_init(&priv->tx_queue[i], - &priv->tx_queue_stats, i, 16, - cw1200_ttl[i])) { - for (; i > 0; i--) - cw1200_queue_deinit(&priv->tx_queue[i - 1]); - cw1200_queue_stats_deinit(&priv->tx_queue_stats); - ieee80211_free_hw(hw); - return NULL; - } - } - - init_waitqueue_head(&priv->channel_switch_done); - init_waitqueue_head(&priv->wsm_cmd_wq); - init_waitqueue_head(&priv->wsm_startup_done); - init_waitqueue_head(&priv->ps_mode_switch_done); - wsm_buf_init(&priv->wsm_cmd_buf); - spin_lock_init(&priv->wsm_cmd.lock); - priv->wsm_cmd.done = 1; - tx_policy_init(priv); - - return hw; -} - -static int cw1200_register_common(struct ieee80211_hw *dev) -{ - struct cw1200_common *priv = dev->priv; - int err; - -#ifdef CONFIG_PM - err = cw1200_pm_init(&priv->pm_state, priv); - if (err) { - pr_err("Cannot init PM. (%d).\n", - err); - return err; - } -#endif - - err = ieee80211_register_hw(dev); - if (err) { - pr_err("Cannot register device (%d).\n", - err); -#ifdef CONFIG_PM - cw1200_pm_deinit(&priv->pm_state); -#endif - return err; - } - - cw1200_debug_init(priv); - - pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy)); - return 0; -} - -static void cw1200_free_common(struct ieee80211_hw *dev) -{ - ieee80211_free_hw(dev); -} - -static void cw1200_unregister_common(struct ieee80211_hw *dev) -{ - struct cw1200_common *priv = dev->priv; - int i; - - ieee80211_unregister_hw(dev); - - del_timer_sync(&priv->mcast_timeout); - cw1200_unregister_bh(priv); - - cw1200_debug_release(priv); - - mutex_destroy(&priv->conf_mutex); - - wsm_buf_deinit(&priv->wsm_cmd_buf); - - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - - if (priv->sdd) { - release_firmware(priv->sdd); - priv->sdd = NULL; - } - - for (i = 0; i < 4; ++i) - cw1200_queue_deinit(&priv->tx_queue[i]); - - cw1200_queue_stats_deinit(&priv->tx_queue_stats); -#ifdef CONFIG_PM - cw1200_pm_deinit(&priv->pm_state); -#endif -} - -/* Clock is in KHz */ -u32 cw1200_dpll_from_clk(u16 clk_khz) -{ - switch (clk_khz) { - case 0x32C8: /* 13000 KHz */ - return 0x1D89D241; - case 0x3E80: /* 16000 KHz */ - return 0x000001E1; - case 0x41A0: /* 16800 KHz */ - return 0x124931C1; - case 0x4B00: /* 19200 KHz */ - return 0x00000191; - case 0x5DC0: /* 24000 KHz */ - return 0x00000141; - case 0x6590: /* 26000 KHz */ - return 0x0EC4F121; - case 0x8340: /* 33600 KHz */ - return 0x092490E1; - case 0x9600: /* 38400 KHz */ - return 0x100010C1; - case 0x9C40: /* 40000 KHz */ - return 0x000000C1; - case 0xBB80: /* 48000 KHz */ - return 0x000000A1; - case 0xCB20: /* 52000 KHz */ - return 0x07627091; - default: - pr_err("Unknown Refclk freq (0x%04x), using 26000KHz\n", - clk_khz); - return 0x0EC4F121; - } -} - -int cw1200_core_probe(const struct hwbus_ops *hwbus_ops, - struct hwbus_priv *hwbus, - struct device *pdev, - struct cw1200_common **core, - int ref_clk, const u8 *macaddr, - const char *sdd_path, bool have_5ghz) -{ - int err = -EINVAL; - struct ieee80211_hw *dev; - struct cw1200_common *priv; - struct wsm_operational_mode mode = { - .power_mode = cw1200_power_mode, - .disable_more_flag_usage = true, - }; - - dev = cw1200_init_common(macaddr, have_5ghz); - if (!dev) - goto err; - - priv = dev->priv; - priv->hw_refclk = ref_clk; - if (cw1200_refclk) - priv->hw_refclk = cw1200_refclk; - - priv->sdd_path = (char *)sdd_path; - if (cw1200_sdd_path) - priv->sdd_path = cw1200_sdd_path; - - priv->hwbus_ops = hwbus_ops; - priv->hwbus_priv = hwbus; - priv->pdev = pdev; - SET_IEEE80211_DEV(priv->hw, pdev); - - /* Pass struct cw1200_common back up */ - *core = priv; - - err = cw1200_register_bh(priv); - if (err) - goto err1; - - err = cw1200_load_firmware(priv); - if (err) - goto err2; - - if (wait_event_interruptible_timeout(priv->wsm_startup_done, - priv->firmware_ready, - 3*HZ) <= 0) { - /* TODO: Need to find how to reset device - in QUEUE mode properly. - */ - pr_err("Timeout waiting on device startup\n"); - err = -ETIMEDOUT; - goto err2; - } - - /* Set low-power mode. */ - wsm_set_operational_mode(priv, &mode); - - /* Enable multi-TX confirmation */ - wsm_use_multi_tx_conf(priv, true); - - err = cw1200_register_common(dev); - if (err) - goto err2; - - return err; - -err2: - cw1200_unregister_bh(priv); -err1: - cw1200_free_common(dev); -err: - *core = NULL; - return err; -} -EXPORT_SYMBOL_GPL(cw1200_core_probe); - -void cw1200_core_release(struct cw1200_common *self) -{ - /* Disable device interrupts */ - self->hwbus_ops->lock(self->hwbus_priv); - __cw1200_irq_enable(self, 0); - self->hwbus_ops->unlock(self->hwbus_priv); - - /* And then clean up */ - cw1200_unregister_common(self->hw); - cw1200_free_common(self->hw); - return; -} -EXPORT_SYMBOL_GPL(cw1200_core_release); diff --git a/drivers/net/wireless/cw1200/pm.c b/drivers/net/wireless/cw1200/pm.c deleted file mode 100644 index d2202ae..0000000 --- a/drivers/net/wireless/cw1200/pm.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Mac80211 power management API for ST-Ericsson CW1200 drivers - * - * Copyright (c) 2011, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/if_ether.h> -#include "cw1200.h" -#include "pm.h" -#include "sta.h" -#include "bh.h" -#include "hwbus.h" - -#define CW1200_BEACON_SKIPPING_MULTIPLIER 3 - -struct cw1200_udp_port_filter { - struct wsm_udp_port_filter_hdr hdr; - /* Up to 4 filters are allowed. */ - struct wsm_udp_port_filter filters[WSM_MAX_FILTER_ELEMENTS]; -} __packed; - -struct cw1200_ether_type_filter { - struct wsm_ether_type_filter_hdr hdr; - /* Up to 4 filters are allowed. */ - struct wsm_ether_type_filter filters[WSM_MAX_FILTER_ELEMENTS]; -} __packed; - -static struct cw1200_udp_port_filter cw1200_udp_port_filter_on = { - .hdr.num = 2, - .filters = { - [0] = { - .action = WSM_FILTER_ACTION_FILTER_OUT, - .type = WSM_FILTER_PORT_TYPE_DST, - .port = __cpu_to_le16(67), /* DHCP Bootps */ - }, - [1] = { - .action = WSM_FILTER_ACTION_FILTER_OUT, - .type = WSM_FILTER_PORT_TYPE_DST, - .port = __cpu_to_le16(68), /* DHCP Bootpc */ - }, - } -}; - -static struct wsm_udp_port_filter_hdr cw1200_udp_port_filter_off = { - .num = 0, -}; - -#ifndef ETH_P_WAPI -#define ETH_P_WAPI 0x88B4 -#endif - -static struct cw1200_ether_type_filter cw1200_ether_type_filter_on = { - .hdr.num = 4, - .filters = { - [0] = { - .action = WSM_FILTER_ACTION_FILTER_IN, - .type = __cpu_to_le16(ETH_P_IP), - }, - [1] = { - .action = WSM_FILTER_ACTION_FILTER_IN, - .type = __cpu_to_le16(ETH_P_PAE), - }, - [2] = { - .action = WSM_FILTER_ACTION_FILTER_IN, - .type = __cpu_to_le16(ETH_P_WAPI), - }, - [3] = { - .action = WSM_FILTER_ACTION_FILTER_IN, - .type = __cpu_to_le16(ETH_P_ARP), - }, - }, -}; - -static struct wsm_ether_type_filter_hdr cw1200_ether_type_filter_off = { - .num = 0, -}; - -/* private */ -struct cw1200_suspend_state { - unsigned long bss_loss_tmo; - unsigned long join_tmo; - unsigned long direct_probe; - unsigned long link_id_gc; - bool beacon_skipping; - u8 prev_ps_mode; -}; - -static void cw1200_pm_stay_awake_tmo(unsigned long arg) -{ - /* XXX what's the point of this ? */ -} - -int cw1200_pm_init(struct cw1200_pm_state *pm, - struct cw1200_common *priv) -{ - spin_lock_init(&pm->lock); - - setup_timer(&pm->stay_awake, cw1200_pm_stay_awake_tmo, - (unsigned long)pm); - - return 0; -} - -void cw1200_pm_deinit(struct cw1200_pm_state *pm) -{ - del_timer_sync(&pm->stay_awake); -} - -void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, - unsigned long tmo) -{ - long cur_tmo; - spin_lock_bh(&pm->lock); - cur_tmo = pm->stay_awake.expires - jiffies; - if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) - mod_timer(&pm->stay_awake, jiffies + tmo); - spin_unlock_bh(&pm->lock); -} - -static long cw1200_suspend_work(struct delayed_work *work) -{ - int ret = cancel_delayed_work(work); - long tmo; - if (ret > 0) { - /* Timer is pending */ - tmo = work->timer.expires - jiffies; - if (tmo < 0) - tmo = 0; - } else { - tmo = -1; - } - return tmo; -} - -static int cw1200_resume_work(struct cw1200_common *priv, - struct delayed_work *work, - unsigned long tmo) -{ - if ((long)tmo < 0) - return 1; - - return queue_delayed_work(priv->workqueue, work, tmo); -} - -int cw1200_can_suspend(struct cw1200_common *priv) -{ - if (atomic_read(&priv->bh_rx)) { - wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n"); - return 0; - } - return 1; -} -EXPORT_SYMBOL_GPL(cw1200_can_suspend); - -int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) -{ - struct cw1200_common *priv = hw->priv; - struct cw1200_pm_state *pm_state = &priv->pm_state; - struct cw1200_suspend_state *state; - int ret; - - spin_lock_bh(&pm_state->lock); - ret = timer_pending(&pm_state->stay_awake); - spin_unlock_bh(&pm_state->lock); - if (ret) - return -EAGAIN; - - /* Do not suspend when datapath is not idle */ - if (priv->tx_queue_stats.num_queued) - return -EBUSY; - - /* Make sure there is no configuration requests in progress. */ - if (!mutex_trylock(&priv->conf_mutex)) - return -EBUSY; - - /* Ensure pending operations are done. - * Note also that wow_suspend must return in ~2.5sec, before - * watchdog is triggered. - */ - if (priv->channel_switch_in_progress) - goto revert1; - - /* Do not suspend when join is pending */ - if (priv->join_pending) - goto revert1; - - /* Do not suspend when scanning */ - if (down_trylock(&priv->scan.lock)) - goto revert1; - - /* Lock TX. */ - wsm_lock_tx_async(priv); - - /* Wait to avoid possible race with bh code. - * But do not wait too long... - */ - if (wait_event_timeout(priv->bh_evt_wq, - !priv->hw_bufs_used, HZ / 10) <= 0) - goto revert2; - - /* Set UDP filter */ - wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr); - - /* Set ethernet frame type filter */ - wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr); - - /* Allocate state */ - state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL); - if (!state) - goto revert3; - - /* Change to legacy PS while going to suspend */ - if (!priv->vif->p2p && - priv->join_status == CW1200_JOIN_STATUS_STA && - priv->powersave_mode.mode != WSM_PSM_PS) { - state->prev_ps_mode = priv->powersave_mode.mode; - priv->powersave_mode.mode = WSM_PSM_PS; - cw1200_set_pm(priv, &priv->powersave_mode); - if (wait_event_interruptible_timeout(priv->ps_mode_switch_done, - !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) { - goto revert4; - } - } - - /* Store delayed work states. */ - state->bss_loss_tmo = - cw1200_suspend_work(&priv->bss_loss_work); - state->join_tmo = - cw1200_suspend_work(&priv->join_timeout); - state->direct_probe = - cw1200_suspend_work(&priv->scan.probe_work); - state->link_id_gc = - cw1200_suspend_work(&priv->link_id_gc_work); - - cancel_delayed_work_sync(&priv->clear_recent_scan_work); - atomic_set(&priv->recent_scan, 0); - - /* Enable beacon skipping */ - if (priv->join_status == CW1200_JOIN_STATUS_STA && - priv->join_dtim_period && - !priv->has_multicast_subscription) { - state->beacon_skipping = true; - wsm_set_beacon_wakeup_period(priv, - priv->join_dtim_period, - CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period); - } - - /* Stop serving thread */ - if (cw1200_bh_suspend(priv)) - goto revert5; - - ret = timer_pending(&priv->mcast_timeout); - if (ret) - goto revert6; - - /* Store suspend state */ - pm_state->suspend_state = state; - - /* Enable IRQ wake */ - ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true); - if (ret) { - wiphy_err(priv->hw->wiphy, - "PM request failed: %d. WoW is disabled.\n", ret); - cw1200_wow_resume(hw); - return -EBUSY; - } - - /* Force resume if event is coming from the device. */ - if (atomic_read(&priv->bh_rx)) { - cw1200_wow_resume(hw); - return -EAGAIN; - } - - return 0; - -revert6: - WARN_ON(cw1200_bh_resume(priv)); -revert5: - cw1200_resume_work(priv, &priv->bss_loss_work, - state->bss_loss_tmo); - cw1200_resume_work(priv, &priv->join_timeout, - state->join_tmo); - cw1200_resume_work(priv, &priv->scan.probe_work, - state->direct_probe); - cw1200_resume_work(priv, &priv->link_id_gc_work, - state->link_id_gc); -revert4: - kfree(state); -revert3: - wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); - wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); -revert2: - wsm_unlock_tx(priv); - up(&priv->scan.lock); -revert1: - mutex_unlock(&priv->conf_mutex); - return -EBUSY; -} - -int cw1200_wow_resume(struct ieee80211_hw *hw) -{ - struct cw1200_common *priv = hw->priv; - struct cw1200_pm_state *pm_state = &priv->pm_state; - struct cw1200_suspend_state *state; - - state = pm_state->suspend_state; - pm_state->suspend_state = NULL; - - /* Disable IRQ wake */ - priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false); - - /* Scan.lock must be released before BH is resumed other way - * in case when BSS_LOST command arrived the processing of the - * command will be delayed. - */ - up(&priv->scan.lock); - - /* Resume BH thread */ - WARN_ON(cw1200_bh_resume(priv)); - - /* Restores previous PS mode */ - if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) { - priv->powersave_mode.mode = state->prev_ps_mode; - cw1200_set_pm(priv, &priv->powersave_mode); - } - - if (state->beacon_skipping) { - wsm_set_beacon_wakeup_period(priv, priv->beacon_int * - priv->join_dtim_period > - MAX_BEACON_SKIP_TIME_MS ? 1 : - priv->join_dtim_period, 0); - state->beacon_skipping = false; - } - - /* Resume delayed work */ - cw1200_resume_work(priv, &priv->bss_loss_work, - state->bss_loss_tmo); - cw1200_resume_work(priv, &priv->join_timeout, - state->join_tmo); - cw1200_resume_work(priv, &priv->scan.probe_work, - state->direct_probe); - cw1200_resume_work(priv, &priv->link_id_gc_work, - state->link_id_gc); - - /* Remove UDP port filter */ - wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); - - /* Remove ethernet frame type filter */ - wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); - - /* Unlock datapath */ - wsm_unlock_tx(priv); - - /* Unlock configuration mutex */ - mutex_unlock(&priv->conf_mutex); - - /* Free memory */ - kfree(state); - - return 0; -} diff --git a/drivers/net/wireless/cw1200/pm.h b/drivers/net/wireless/cw1200/pm.h deleted file mode 100644 index 3ed90ff..0000000 --- a/drivers/net/wireless/cw1200/pm.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Mac80211 power management interface for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2011, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef PM_H_INCLUDED -#define PM_H_INCLUDED - -/* ******************************************************************** */ -/* mac80211 API */ - -/* extern */ struct cw1200_common; -/* private */ struct cw1200_suspend_state; - -struct cw1200_pm_state { - struct cw1200_suspend_state *suspend_state; - struct timer_list stay_awake; - struct platform_device *pm_dev; - spinlock_t lock; /* Protect access */ -}; - -#ifdef CONFIG_PM -int cw1200_pm_init(struct cw1200_pm_state *pm, - struct cw1200_common *priv); -void cw1200_pm_deinit(struct cw1200_pm_state *pm); -int cw1200_wow_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan); -int cw1200_wow_resume(struct ieee80211_hw *hw); -int cw1200_can_suspend(struct cw1200_common *priv); -void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, - unsigned long tmo); -#else -static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, - unsigned long tmo) { -} -#endif -#endif diff --git a/drivers/net/wireless/cw1200/queue.c b/drivers/net/wireless/cw1200/queue.c deleted file mode 100644 index 0ba5ef9..0000000 --- a/drivers/net/wireless/cw1200/queue.c +++ /dev/null @@ -1,581 +0,0 @@ -/* - * O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <net/mac80211.h> -#include <linux/sched.h> -#include "queue.h" -#include "cw1200.h" -#include "debug.h" - -/* private */ struct cw1200_queue_item -{ - struct list_head head; - struct sk_buff *skb; - u32 packet_id; - unsigned long queue_timestamp; - unsigned long xmit_timestamp; - struct cw1200_txpriv txpriv; - u8 generation; -}; - -static inline void __cw1200_queue_lock(struct cw1200_queue *queue) -{ - struct cw1200_queue_stats *stats = queue->stats; - if (queue->tx_locked_cnt++ == 0) { - pr_debug("[TX] Queue %d is locked.\n", - queue->queue_id); - ieee80211_stop_queue(stats->priv->hw, queue->queue_id); - } -} - -static inline void __cw1200_queue_unlock(struct cw1200_queue *queue) -{ - struct cw1200_queue_stats *stats = queue->stats; - BUG_ON(!queue->tx_locked_cnt); - if (--queue->tx_locked_cnt == 0) { - pr_debug("[TX] Queue %d is unlocked.\n", - queue->queue_id); - ieee80211_wake_queue(stats->priv->hw, queue->queue_id); - } -} - -static inline void cw1200_queue_parse_id(u32 packet_id, u8 *queue_generation, - u8 *queue_id, u8 *item_generation, - u8 *item_id) -{ - *item_id = (packet_id >> 0) & 0xFF; - *item_generation = (packet_id >> 8) & 0xFF; - *queue_id = (packet_id >> 16) & 0xFF; - *queue_generation = (packet_id >> 24) & 0xFF; -} - -static inline u32 cw1200_queue_mk_packet_id(u8 queue_generation, u8 queue_id, - u8 item_generation, u8 item_id) -{ - return ((u32)item_id << 0) | - ((u32)item_generation << 8) | - ((u32)queue_id << 16) | - ((u32)queue_generation << 24); -} - -static void cw1200_queue_post_gc(struct cw1200_queue_stats *stats, - struct list_head *gc_list) -{ - struct cw1200_queue_item *item, *tmp; - - list_for_each_entry_safe(item, tmp, gc_list, head) { - list_del(&item->head); - stats->skb_dtor(stats->priv, item->skb, &item->txpriv); - kfree(item); - } -} - -static void cw1200_queue_register_post_gc(struct list_head *gc_list, - struct cw1200_queue_item *item) -{ - struct cw1200_queue_item *gc_item; - gc_item = kmalloc(sizeof(struct cw1200_queue_item), - GFP_ATOMIC); - BUG_ON(!gc_item); - memcpy(gc_item, item, sizeof(struct cw1200_queue_item)); - list_add_tail(&gc_item->head, gc_list); -} - -static void __cw1200_queue_gc(struct cw1200_queue *queue, - struct list_head *head, - bool unlock) -{ - struct cw1200_queue_stats *stats = queue->stats; - struct cw1200_queue_item *item = NULL, *tmp; - bool wakeup_stats = false; - - list_for_each_entry_safe(item, tmp, &queue->queue, head) { - if (jiffies - item->queue_timestamp < queue->ttl) - break; - --queue->num_queued; - --queue->link_map_cache[item->txpriv.link_id]; - spin_lock_bh(&stats->lock); - --stats->num_queued; - if (!--stats->link_map_cache[item->txpriv.link_id]) - wakeup_stats = true; - spin_unlock_bh(&stats->lock); - cw1200_debug_tx_ttl(stats->priv); - cw1200_queue_register_post_gc(head, item); - item->skb = NULL; - list_move_tail(&item->head, &queue->free_pool); - } - - if (wakeup_stats) - wake_up(&stats->wait_link_id_empty); - - if (queue->overfull) { - if (queue->num_queued <= (queue->capacity >> 1)) { - queue->overfull = false; - if (unlock) - __cw1200_queue_unlock(queue); - } else if (item) { - unsigned long tmo = item->queue_timestamp + queue->ttl; - mod_timer(&queue->gc, tmo); - cw1200_pm_stay_awake(&stats->priv->pm_state, - tmo - jiffies); - } - } -} - -static void cw1200_queue_gc(unsigned long arg) -{ - LIST_HEAD(list); - struct cw1200_queue *queue = - (struct cw1200_queue *)arg; - - spin_lock_bh(&queue->lock); - __cw1200_queue_gc(queue, &list, true); - spin_unlock_bh(&queue->lock); - cw1200_queue_post_gc(queue->stats, &list); -} - -int cw1200_queue_stats_init(struct cw1200_queue_stats *stats, - size_t map_capacity, - cw1200_queue_skb_dtor_t skb_dtor, - struct cw1200_common *priv) -{ - memset(stats, 0, sizeof(*stats)); - stats->map_capacity = map_capacity; - stats->skb_dtor = skb_dtor; - stats->priv = priv; - spin_lock_init(&stats->lock); - init_waitqueue_head(&stats->wait_link_id_empty); - - stats->link_map_cache = kzalloc(sizeof(int) * map_capacity, - GFP_KERNEL); - if (!stats->link_map_cache) - return -ENOMEM; - - return 0; -} - -int cw1200_queue_init(struct cw1200_queue *queue, - struct cw1200_queue_stats *stats, - u8 queue_id, - size_t capacity, - unsigned long ttl) -{ - size_t i; - - memset(queue, 0, sizeof(*queue)); - queue->stats = stats; - queue->capacity = capacity; - queue->queue_id = queue_id; - queue->ttl = ttl; - INIT_LIST_HEAD(&queue->queue); - INIT_LIST_HEAD(&queue->pending); - INIT_LIST_HEAD(&queue->free_pool); - spin_lock_init(&queue->lock); - setup_timer(&queue->gc, cw1200_queue_gc, (unsigned long)queue); - - queue->pool = kzalloc(sizeof(struct cw1200_queue_item) * capacity, - GFP_KERNEL); - if (!queue->pool) - return -ENOMEM; - - queue->link_map_cache = kzalloc(sizeof(int) * stats->map_capacity, - GFP_KERNEL); - if (!queue->link_map_cache) { - kfree(queue->pool); - queue->pool = NULL; - return -ENOMEM; - } - - for (i = 0; i < capacity; ++i) - list_add_tail(&queue->pool[i].head, &queue->free_pool); - - return 0; -} - -int cw1200_queue_clear(struct cw1200_queue *queue) -{ - int i; - LIST_HEAD(gc_list); - struct cw1200_queue_stats *stats = queue->stats; - struct cw1200_queue_item *item, *tmp; - - spin_lock_bh(&queue->lock); - queue->generation++; - list_splice_tail_init(&queue->queue, &queue->pending); - list_for_each_entry_safe(item, tmp, &queue->pending, head) { - WARN_ON(!item->skb); - cw1200_queue_register_post_gc(&gc_list, item); - item->skb = NULL; - list_move_tail(&item->head, &queue->free_pool); - } - queue->num_queued = 0; - queue->num_pending = 0; - - spin_lock_bh(&stats->lock); - for (i = 0; i < stats->map_capacity; ++i) { - stats->num_queued -= queue->link_map_cache[i]; - stats->link_map_cache[i] -= queue->link_map_cache[i]; - queue->link_map_cache[i] = 0; - } - spin_unlock_bh(&stats->lock); - if (queue->overfull) { - queue->overfull = false; - __cw1200_queue_unlock(queue); - } - spin_unlock_bh(&queue->lock); - wake_up(&stats->wait_link_id_empty); - cw1200_queue_post_gc(stats, &gc_list); - return 0; -} - -void cw1200_queue_stats_deinit(struct cw1200_queue_stats *stats) -{ - kfree(stats->link_map_cache); - stats->link_map_cache = NULL; -} - -void cw1200_queue_deinit(struct cw1200_queue *queue) -{ - cw1200_queue_clear(queue); - del_timer_sync(&queue->gc); - INIT_LIST_HEAD(&queue->free_pool); - kfree(queue->pool); - kfree(queue->link_map_cache); - queue->pool = NULL; - queue->link_map_cache = NULL; - queue->capacity = 0; -} - -size_t cw1200_queue_get_num_queued(struct cw1200_queue *queue, - u32 link_id_map) -{ - size_t ret; - int i, bit; - size_t map_capacity = queue->stats->map_capacity; - - if (!link_id_map) - return 0; - - spin_lock_bh(&queue->lock); - if (link_id_map == (u32)-1) { - ret = queue->num_queued - queue->num_pending; - } else { - ret = 0; - for (i = 0, bit = 1; i < map_capacity; ++i, bit <<= 1) { - if (link_id_map & bit) - ret += queue->link_map_cache[i]; - } - } - spin_unlock_bh(&queue->lock); - return ret; -} - -int cw1200_queue_put(struct cw1200_queue *queue, - struct sk_buff *skb, - struct cw1200_txpriv *txpriv) -{ - int ret = 0; - LIST_HEAD(gc_list); - struct cw1200_queue_stats *stats = queue->stats; - - if (txpriv->link_id >= queue->stats->map_capacity) - return -EINVAL; - - spin_lock_bh(&queue->lock); - if (!WARN_ON(list_empty(&queue->free_pool))) { - struct cw1200_queue_item *item = list_first_entry( - &queue->free_pool, struct cw1200_queue_item, head); - BUG_ON(item->skb); - - list_move_tail(&item->head, &queue->queue); - item->skb = skb; - item->txpriv = *txpriv; - item->generation = 0; - item->packet_id = cw1200_queue_mk_packet_id(queue->generation, - queue->queue_id, - item->generation, - item - queue->pool); - item->queue_timestamp = jiffies; - - ++queue->num_queued; - ++queue->link_map_cache[txpriv->link_id]; - - spin_lock_bh(&stats->lock); - ++stats->num_queued; - ++stats->link_map_cache[txpriv->link_id]; - spin_unlock_bh(&stats->lock); - - /* TX may happen in parallel sometimes. - * Leave extra queue slots so we don't overflow. - */ - if (queue->overfull == false && - queue->num_queued >= - (queue->capacity - (num_present_cpus() - 1))) { - queue->overfull = true; - __cw1200_queue_lock(queue); - mod_timer(&queue->gc, jiffies); - } - } else { - ret = -ENOENT; - } - spin_unlock_bh(&queue->lock); - return ret; -} - -int cw1200_queue_get(struct cw1200_queue *queue, - u32 link_id_map, - struct wsm_tx **tx, - struct ieee80211_tx_info **tx_info, - const struct cw1200_txpriv **txpriv) -{ - int ret = -ENOENT; - struct cw1200_queue_item *item; - struct cw1200_queue_stats *stats = queue->stats; - bool wakeup_stats = false; - - spin_lock_bh(&queue->lock); - list_for_each_entry(item, &queue->queue, head) { - if (link_id_map & BIT(item->txpriv.link_id)) { - ret = 0; - break; - } - } - - if (!WARN_ON(ret)) { - *tx = (struct wsm_tx *)item->skb->data; - *tx_info = IEEE80211_SKB_CB(item->skb); - *txpriv = &item->txpriv; - (*tx)->packet_id = item->packet_id; - list_move_tail(&item->head, &queue->pending); - ++queue->num_pending; - --queue->link_map_cache[item->txpriv.link_id]; - item->xmit_timestamp = jiffies; - - spin_lock_bh(&stats->lock); - --stats->num_queued; - if (!--stats->link_map_cache[item->txpriv.link_id]) - wakeup_stats = true; - spin_unlock_bh(&stats->lock); - } - spin_unlock_bh(&queue->lock); - if (wakeup_stats) - wake_up(&stats->wait_link_id_empty); - return ret; -} - -int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id) -{ - int ret = 0; - u8 queue_generation, queue_id, item_generation, item_id; - struct cw1200_queue_item *item; - struct cw1200_queue_stats *stats = queue->stats; - - cw1200_queue_parse_id(packet_id, &queue_generation, &queue_id, - &item_generation, &item_id); - - item = &queue->pool[item_id]; - - spin_lock_bh(&queue->lock); - BUG_ON(queue_id != queue->queue_id); - if (queue_generation != queue->generation) { - ret = -ENOENT; - } else if (item_id >= (unsigned) queue->capacity) { - WARN_ON(1); - ret = -EINVAL; - } else if (item->generation != item_generation) { - WARN_ON(1); - ret = -ENOENT; - } else { - --queue->num_pending; - ++queue->link_map_cache[item->txpriv.link_id]; - - spin_lock_bh(&stats->lock); - ++stats->num_queued; - ++stats->link_map_cache[item->txpriv.link_id]; - spin_unlock_bh(&stats->lock); - - item->generation = ++item_generation; - item->packet_id = cw1200_queue_mk_packet_id(queue_generation, - queue_id, - item_generation, - item_id); - list_move(&item->head, &queue->queue); - } - spin_unlock_bh(&queue->lock); - return ret; -} - -int cw1200_queue_requeue_all(struct cw1200_queue *queue) -{ - struct cw1200_queue_item *item, *tmp; - struct cw1200_queue_stats *stats = queue->stats; - spin_lock_bh(&queue->lock); - - list_for_each_entry_safe_reverse(item, tmp, &queue->pending, head) { - --queue->num_pending; - ++queue->link_map_cache[item->txpriv.link_id]; - - spin_lock_bh(&stats->lock); - ++stats->num_queued; - ++stats->link_map_cache[item->txpriv.link_id]; - spin_unlock_bh(&stats->lock); - - ++item->generation; - item->packet_id = cw1200_queue_mk_packet_id(queue->generation, - queue->queue_id, - item->generation, - item - queue->pool); - list_move(&item->head, &queue->queue); - } - spin_unlock_bh(&queue->lock); - - return 0; -} - -int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id) -{ - int ret = 0; - u8 queue_generation, queue_id, item_generation, item_id; - struct cw1200_queue_item *item; - struct cw1200_queue_stats *stats = queue->stats; - struct sk_buff *gc_skb = NULL; - struct cw1200_txpriv gc_txpriv; - - cw1200_queue_parse_id(packet_id, &queue_generation, &queue_id, - &item_generation, &item_id); - - item = &queue->pool[item_id]; - - spin_lock_bh(&queue->lock); - BUG_ON(queue_id != queue->queue_id); - if (queue_generation != queue->generation) { - ret = -ENOENT; - } else if (item_id >= (unsigned) queue->capacity) { - WARN_ON(1); - ret = -EINVAL; - } else if (item->generation != item_generation) { - WARN_ON(1); - ret = -ENOENT; - } else { - gc_txpriv = item->txpriv; - gc_skb = item->skb; - item->skb = NULL; - --queue->num_pending; - --queue->num_queued; - ++queue->num_sent; - ++item->generation; - /* Do not use list_move_tail here, but list_move: - * try to utilize cache row. - */ - list_move(&item->head, &queue->free_pool); - - if (queue->overfull && - (queue->num_queued <= (queue->capacity >> 1))) { - queue->overfull = false; - __cw1200_queue_unlock(queue); - } - } - spin_unlock_bh(&queue->lock); - - if (gc_skb) - stats->skb_dtor(stats->priv, gc_skb, &gc_txpriv); - - return ret; -} - -int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id, - struct sk_buff **skb, - const struct cw1200_txpriv **txpriv) -{ - int ret = 0; - u8 queue_generation, queue_id, item_generation, item_id; - struct cw1200_queue_item *item; - cw1200_queue_parse_id(packet_id, &queue_generation, &queue_id, - &item_generation, &item_id); - - item = &queue->pool[item_id]; - - spin_lock_bh(&queue->lock); - BUG_ON(queue_id != queue->queue_id); - if (queue_generation != queue->generation) { - ret = -ENOENT; - } else if (item_id >= (unsigned) queue->capacity) { - WARN_ON(1); - ret = -EINVAL; - } else if (item->generation != item_generation) { - WARN_ON(1); - ret = -ENOENT; - } else { - *skb = item->skb; - *txpriv = &item->txpriv; - } - spin_unlock_bh(&queue->lock); - return ret; -} - -void cw1200_queue_lock(struct cw1200_queue *queue) -{ - spin_lock_bh(&queue->lock); - __cw1200_queue_lock(queue); - spin_unlock_bh(&queue->lock); -} - -void cw1200_queue_unlock(struct cw1200_queue *queue) -{ - spin_lock_bh(&queue->lock); - __cw1200_queue_unlock(queue); - spin_unlock_bh(&queue->lock); -} - -bool cw1200_queue_get_xmit_timestamp(struct cw1200_queue *queue, - unsigned long *timestamp, - u32 pending_frame_id) -{ - struct cw1200_queue_item *item; - bool ret; - - spin_lock_bh(&queue->lock); - ret = !list_empty(&queue->pending); - if (ret) { - list_for_each_entry(item, &queue->pending, head) { - if (item->packet_id != pending_frame_id) - if (time_before(item->xmit_timestamp, - *timestamp)) - *timestamp = item->xmit_timestamp; - } - } - spin_unlock_bh(&queue->lock); - return ret; -} - -bool cw1200_queue_stats_is_empty(struct cw1200_queue_stats *stats, - u32 link_id_map) -{ - bool empty = true; - - spin_lock_bh(&stats->lock); - if (link_id_map == (u32)-1) { - empty = stats->num_queued == 0; - } else { - int i; - for (i = 0; i < stats->map_capacity; ++i) { - if (link_id_map & BIT(i)) { - if (stats->link_map_cache[i]) { - empty = false; - break; - } - } - } - } - spin_unlock_bh(&stats->lock); - - return empty; -} diff --git a/drivers/net/wireless/cw1200/queue.h b/drivers/net/wireless/cw1200/queue.h deleted file mode 100644 index 119f9c7..0000000 --- a/drivers/net/wireless/cw1200/queue.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_QUEUE_H_INCLUDED -#define CW1200_QUEUE_H_INCLUDED - -/* private */ struct cw1200_queue_item; - -/* extern */ struct sk_buff; -/* extern */ struct wsm_tx; -/* extern */ struct cw1200_common; -/* extern */ struct ieee80211_tx_queue_stats; -/* extern */ struct cw1200_txpriv; - -/* forward */ struct cw1200_queue_stats; - -typedef void (*cw1200_queue_skb_dtor_t)(struct cw1200_common *priv, - struct sk_buff *skb, - const struct cw1200_txpriv *txpriv); - -struct cw1200_queue { - struct cw1200_queue_stats *stats; - size_t capacity; - size_t num_queued; - size_t num_pending; - size_t num_sent; - struct cw1200_queue_item *pool; - struct list_head queue; - struct list_head free_pool; - struct list_head pending; - int tx_locked_cnt; - int *link_map_cache; - bool overfull; - spinlock_t lock; /* Protect queue entry */ - u8 queue_id; - u8 generation; - struct timer_list gc; - unsigned long ttl; -}; - -struct cw1200_queue_stats { - spinlock_t lock; /* Protect stats entry */ - int *link_map_cache; - int num_queued; - size_t map_capacity; - wait_queue_head_t wait_link_id_empty; - cw1200_queue_skb_dtor_t skb_dtor; - struct cw1200_common *priv; -}; - -struct cw1200_txpriv { - u8 link_id; - u8 raw_link_id; - u8 tid; - u8 rate_id; - u8 offset; -}; - -int cw1200_queue_stats_init(struct cw1200_queue_stats *stats, - size_t map_capacity, - cw1200_queue_skb_dtor_t skb_dtor, - struct cw1200_common *priv); -int cw1200_queue_init(struct cw1200_queue *queue, - struct cw1200_queue_stats *stats, - u8 queue_id, - size_t capacity, - unsigned long ttl); -int cw1200_queue_clear(struct cw1200_queue *queue); -void cw1200_queue_stats_deinit(struct cw1200_queue_stats *stats); -void cw1200_queue_deinit(struct cw1200_queue *queue); - -size_t cw1200_queue_get_num_queued(struct cw1200_queue *queue, - u32 link_id_map); -int cw1200_queue_put(struct cw1200_queue *queue, - struct sk_buff *skb, - struct cw1200_txpriv *txpriv); -int cw1200_queue_get(struct cw1200_queue *queue, - u32 link_id_map, - struct wsm_tx **tx, - struct ieee80211_tx_info **tx_info, - const struct cw1200_txpriv **txpriv); -int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id); -int cw1200_queue_requeue_all(struct cw1200_queue *queue); -int cw1200_queue_remove(struct cw1200_queue *queue, - u32 packet_id); -int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id, - struct sk_buff **skb, - const struct cw1200_txpriv **txpriv); -void cw1200_queue_lock(struct cw1200_queue *queue); -void cw1200_queue_unlock(struct cw1200_queue *queue); -bool cw1200_queue_get_xmit_timestamp(struct cw1200_queue *queue, - unsigned long *timestamp, - u32 pending_frame_id); - -bool cw1200_queue_stats_is_empty(struct cw1200_queue_stats *stats, - u32 link_id_map); - -static inline u8 cw1200_queue_get_queue_id(u32 packet_id) -{ - return (packet_id >> 16) & 0xFF; -} - -static inline u8 cw1200_queue_get_generation(u32 packet_id) -{ - return (packet_id >> 8) & 0xFF; -} - -#endif /* CW1200_QUEUE_H_INCLUDED */ diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c deleted file mode 100644 index bff81b8..0000000 --- a/drivers/net/wireless/cw1200/scan.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Scan implementation for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/sched.h> -#include "cw1200.h" -#include "scan.h" -#include "sta.h" -#include "pm.h" - -static void cw1200_scan_restart_delayed(struct cw1200_common *priv); - -static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) -{ - int ret, i; - int tmo = 2000; - - switch (priv->join_status) { - case CW1200_JOIN_STATUS_PRE_STA: - case CW1200_JOIN_STATUS_JOINING: - return -EBUSY; - default: - break; - } - - wiphy_dbg(priv->hw->wiphy, "[SCAN] hw req, type %d, %d channels, flags: 0x%x.\n", - scan->type, scan->num_channels, scan->flags); - - for (i = 0; i < scan->num_channels; ++i) - tmo += scan->ch[i].max_chan_time + 10; - - cancel_delayed_work_sync(&priv->clear_recent_scan_work); - atomic_set(&priv->scan.in_progress, 1); - atomic_set(&priv->recent_scan, 1); - cw1200_pm_stay_awake(&priv->pm_state, msecs_to_jiffies(tmo)); - queue_delayed_work(priv->workqueue, &priv->scan.timeout, - msecs_to_jiffies(tmo)); - ret = wsm_scan(priv, scan); - if (ret) { - atomic_set(&priv->scan.in_progress, 0); - cancel_delayed_work_sync(&priv->scan.timeout); - cw1200_scan_restart_delayed(priv); - } - return ret; -} - -int cw1200_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_scan_request *hw_req) -{ - struct cw1200_common *priv = hw->priv; - struct cfg80211_scan_request *req = &hw_req->req; - struct wsm_template_frame frame = { - .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, - }; - int i, ret; - - if (!priv->vif) - return -EINVAL; - - /* Scan when P2P_GO corrupt firmware MiniAP mode */ - if (priv->join_status == CW1200_JOIN_STATUS_AP) - return -EOPNOTSUPP; - - if (req->n_ssids == 1 && !req->ssids[0].ssid_len) - req->n_ssids = 0; - - wiphy_dbg(hw->wiphy, "[SCAN] Scan request for %d SSIDs.\n", - req->n_ssids); - - if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) - return -EINVAL; - - frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, - req->ie_len); - if (!frame.skb) - return -ENOMEM; - - if (req->ie_len) - memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len); - - /* will be unlocked in cw1200_scan_work() */ - down(&priv->scan.lock); - mutex_lock(&priv->conf_mutex); - - ret = wsm_set_template_frame(priv, &frame); - if (!ret) { - /* Host want to be the probe responder. */ - ret = wsm_set_probe_responder(priv, true); - } - if (ret) { - mutex_unlock(&priv->conf_mutex); - up(&priv->scan.lock); - dev_kfree_skb(frame.skb); - return ret; - } - - wsm_lock_tx(priv); - - BUG_ON(priv->scan.req); - priv->scan.req = req; - priv->scan.n_ssids = 0; - priv->scan.status = 0; - priv->scan.begin = &req->channels[0]; - priv->scan.curr = priv->scan.begin; - priv->scan.end = &req->channels[req->n_channels]; - priv->scan.output_power = priv->output_power; - - for (i = 0; i < req->n_ssids; ++i) { - struct wsm_ssid *dst = &priv->scan.ssids[priv->scan.n_ssids]; - memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); - dst->length = req->ssids[i].ssid_len; - ++priv->scan.n_ssids; - } - - mutex_unlock(&priv->conf_mutex); - - if (frame.skb) - dev_kfree_skb(frame.skb); - queue_work(priv->workqueue, &priv->scan.work); - return 0; -} - -void cw1200_scan_work(struct work_struct *work) -{ - struct cw1200_common *priv = container_of(work, struct cw1200_common, - scan.work); - struct ieee80211_channel **it; - struct wsm_scan scan = { - .type = WSM_SCAN_TYPE_FOREGROUND, - .flags = WSM_SCAN_FLAG_SPLIT_METHOD, - }; - bool first_run = (priv->scan.begin == priv->scan.curr && - priv->scan.begin != priv->scan.end); - int i; - - if (first_run) { - /* Firmware gets crazy if scan request is sent - * when STA is joined but not yet associated. - * Force unjoin in this case. - */ - if (cancel_delayed_work_sync(&priv->join_timeout) > 0) - cw1200_join_timeout(&priv->join_timeout.work); - } - - mutex_lock(&priv->conf_mutex); - - if (first_run) { - if (priv->join_status == CW1200_JOIN_STATUS_STA && - !(priv->powersave_mode.mode & WSM_PSM_PS)) { - struct wsm_set_pm pm = priv->powersave_mode; - pm.mode = WSM_PSM_PS; - cw1200_set_pm(priv, &pm); - } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { - /* FW bug: driver has to restart p2p-dev mode - * after scan - */ - cw1200_disable_listening(priv); - } - } - - if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { - if (priv->scan.output_power != priv->output_power) - wsm_set_output_power(priv, priv->output_power * 10); - if (priv->join_status == CW1200_JOIN_STATUS_STA && - !(priv->powersave_mode.mode & WSM_PSM_PS)) - cw1200_set_pm(priv, &priv->powersave_mode); - - if (priv->scan.status < 0) - wiphy_warn(priv->hw->wiphy, - "[SCAN] Scan failed (%d).\n", - priv->scan.status); - else if (priv->scan.req) - wiphy_dbg(priv->hw->wiphy, - "[SCAN] Scan completed.\n"); - else - wiphy_dbg(priv->hw->wiphy, - "[SCAN] Scan canceled.\n"); - - priv->scan.req = NULL; - cw1200_scan_restart_delayed(priv); - wsm_unlock_tx(priv); - mutex_unlock(&priv->conf_mutex); - ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0); - up(&priv->scan.lock); - return; - } else { - struct ieee80211_channel *first = *priv->scan.curr; - for (it = priv->scan.curr + 1, i = 1; - it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; - ++it, ++i) { - if ((*it)->band != first->band) - break; - if (((*it)->flags ^ first->flags) & - IEEE80211_CHAN_NO_IR) - break; - if (!(first->flags & IEEE80211_CHAN_NO_IR) && - (*it)->max_power != first->max_power) - break; - } - scan.band = first->band; - - if (priv->scan.req->no_cck) - scan.max_tx_rate = WSM_TRANSMIT_RATE_6; - else - scan.max_tx_rate = WSM_TRANSMIT_RATE_1; - scan.num_probes = - (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; - scan.num_ssids = priv->scan.n_ssids; - scan.ssids = &priv->scan.ssids[0]; - scan.num_channels = it - priv->scan.curr; - /* TODO: Is it optimal? */ - scan.probe_delay = 100; - /* It is not stated in WSM specification, however - * FW team says that driver may not use FG scan - * when joined. - */ - if (priv->join_status == CW1200_JOIN_STATUS_STA) { - scan.type = WSM_SCAN_TYPE_BACKGROUND; - scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; - } - scan.ch = kzalloc( - sizeof(struct wsm_scan_ch) * (it - priv->scan.curr), - GFP_KERNEL); - if (!scan.ch) { - priv->scan.status = -ENOMEM; - goto fail; - } - for (i = 0; i < scan.num_channels; ++i) { - scan.ch[i].number = priv->scan.curr[i]->hw_value; - if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { - scan.ch[i].min_chan_time = 50; - scan.ch[i].max_chan_time = 100; - } else { - scan.ch[i].min_chan_time = 10; - scan.ch[i].max_chan_time = 25; - } - } - if (!(first->flags & IEEE80211_CHAN_NO_IR) && - priv->scan.output_power != first->max_power) { - priv->scan.output_power = first->max_power; - wsm_set_output_power(priv, - priv->scan.output_power * 10); - } - priv->scan.status = cw1200_scan_start(priv, &scan); - kfree(scan.ch); - if (priv->scan.status) - goto fail; - priv->scan.curr = it; - } - mutex_unlock(&priv->conf_mutex); - return; - -fail: - priv->scan.curr = priv->scan.end; - mutex_unlock(&priv->conf_mutex); - queue_work(priv->workqueue, &priv->scan.work); - return; -} - -static void cw1200_scan_restart_delayed(struct cw1200_common *priv) -{ - /* FW bug: driver has to restart p2p-dev mode after scan. */ - if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { - cw1200_enable_listening(priv); - cw1200_update_filtering(priv); - } - - if (priv->delayed_unjoin) { - priv->delayed_unjoin = false; - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - } else if (priv->delayed_link_loss) { - wiphy_dbg(priv->hw->wiphy, "[CQM] Requeue BSS loss.\n"); - priv->delayed_link_loss = 0; - cw1200_cqm_bssloss_sm(priv, 1, 0, 0); - } -} - -static void cw1200_scan_complete(struct cw1200_common *priv) -{ - queue_delayed_work(priv->workqueue, &priv->clear_recent_scan_work, HZ); - if (priv->scan.direct_probe) { - wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe complete.\n"); - cw1200_scan_restart_delayed(priv); - priv->scan.direct_probe = 0; - up(&priv->scan.lock); - wsm_unlock_tx(priv); - } else { - cw1200_scan_work(&priv->scan.work); - } -} - -void cw1200_scan_failed_cb(struct cw1200_common *priv) -{ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - /* STA is stopped. */ - return; - - if (cancel_delayed_work_sync(&priv->scan.timeout) > 0) { - priv->scan.status = -EIO; - queue_delayed_work(priv->workqueue, &priv->scan.timeout, 0); - } -} - - -void cw1200_scan_complete_cb(struct cw1200_common *priv, - struct wsm_scan_complete *arg) -{ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - /* STA is stopped. */ - return; - - if (cancel_delayed_work_sync(&priv->scan.timeout) > 0) { - priv->scan.status = 1; - queue_delayed_work(priv->workqueue, &priv->scan.timeout, 0); - } -} - -void cw1200_clear_recent_scan_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, - clear_recent_scan_work.work); - atomic_xchg(&priv->recent_scan, 0); -} - -void cw1200_scan_timeout(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, scan.timeout.work); - if (atomic_xchg(&priv->scan.in_progress, 0)) { - if (priv->scan.status > 0) { - priv->scan.status = 0; - } else if (!priv->scan.status) { - wiphy_warn(priv->hw->wiphy, - "Timeout waiting for scan complete notification.\n"); - priv->scan.status = -ETIMEDOUT; - priv->scan.curr = priv->scan.end; - wsm_stop_scan(priv); - } - cw1200_scan_complete(priv); - } -} - -void cw1200_probe_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, scan.probe_work.work); - u8 queue_id = cw1200_queue_get_queue_id(priv->pending_frame_id); - struct cw1200_queue *queue = &priv->tx_queue[queue_id]; - const struct cw1200_txpriv *txpriv; - struct wsm_tx *wsm; - struct wsm_template_frame frame = { - .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, - }; - struct wsm_ssid ssids[1] = {{ - .length = 0, - } }; - struct wsm_scan_ch ch[1] = {{ - .min_chan_time = 0, - .max_chan_time = 10, - } }; - struct wsm_scan scan = { - .type = WSM_SCAN_TYPE_FOREGROUND, - .num_probes = 1, - .probe_delay = 0, - .num_channels = 1, - .ssids = ssids, - .ch = ch, - }; - u8 *ies; - size_t ies_len; - int ret; - - wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe work.\n"); - - mutex_lock(&priv->conf_mutex); - if (down_trylock(&priv->scan.lock)) { - /* Scan is already in progress. Requeue self. */ - schedule(); - queue_delayed_work(priv->workqueue, &priv->scan.probe_work, - msecs_to_jiffies(100)); - mutex_unlock(&priv->conf_mutex); - return; - } - - /* Make sure we still have a pending probe req */ - if (cw1200_queue_get_skb(queue, priv->pending_frame_id, - &frame.skb, &txpriv)) { - up(&priv->scan.lock); - mutex_unlock(&priv->conf_mutex); - wsm_unlock_tx(priv); - return; - } - wsm = (struct wsm_tx *)frame.skb->data; - scan.max_tx_rate = wsm->max_tx_rate; - scan.band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? - WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; - if (priv->join_status == CW1200_JOIN_STATUS_STA || - priv->join_status == CW1200_JOIN_STATUS_IBSS) { - scan.type = WSM_SCAN_TYPE_BACKGROUND; - scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; - } - ch[0].number = priv->channel->hw_value; - - skb_pull(frame.skb, txpriv->offset); - - ies = &frame.skb->data[sizeof(struct ieee80211_hdr_3addr)]; - ies_len = frame.skb->len - sizeof(struct ieee80211_hdr_3addr); - - if (ies_len) { - u8 *ssidie = - (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); - if (ssidie && ssidie[1] && ssidie[1] <= sizeof(ssids[0].ssid)) { - u8 *nextie = &ssidie[2 + ssidie[1]]; - /* Remove SSID from the IE list. It has to be provided - * as a separate argument in cw1200_scan_start call - */ - - /* Store SSID localy */ - ssids[0].length = ssidie[1]; - memcpy(ssids[0].ssid, &ssidie[2], ssids[0].length); - scan.num_ssids = 1; - - /* Remove SSID from IE list */ - ssidie[1] = 0; - memmove(&ssidie[2], nextie, &ies[ies_len] - nextie); - skb_trim(frame.skb, frame.skb->len - ssids[0].length); - } - } - - /* FW bug: driver has to restart p2p-dev mode after scan */ - if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) - cw1200_disable_listening(priv); - ret = wsm_set_template_frame(priv, &frame); - priv->scan.direct_probe = 1; - if (!ret) { - wsm_flush_tx(priv); - ret = cw1200_scan_start(priv, &scan); - } - mutex_unlock(&priv->conf_mutex); - - skb_push(frame.skb, txpriv->offset); - if (!ret) - IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK; - BUG_ON(cw1200_queue_remove(queue, priv->pending_frame_id)); - - if (ret) { - priv->scan.direct_probe = 0; - up(&priv->scan.lock); - wsm_unlock_tx(priv); - } - - return; -} diff --git a/drivers/net/wireless/cw1200/scan.h b/drivers/net/wireless/cw1200/scan.h deleted file mode 100644 index cc75459..0000000 --- a/drivers/net/wireless/cw1200/scan.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Scan interface for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SCAN_H_INCLUDED -#define SCAN_H_INCLUDED - -#include <linux/semaphore.h> -#include "wsm.h" - -/* external */ struct sk_buff; -/* external */ struct cfg80211_scan_request; -/* external */ struct ieee80211_channel; -/* external */ struct ieee80211_hw; -/* external */ struct work_struct; - -struct cw1200_scan { - struct semaphore lock; - struct work_struct work; - struct delayed_work timeout; - struct cfg80211_scan_request *req; - struct ieee80211_channel **begin; - struct ieee80211_channel **curr; - struct ieee80211_channel **end; - struct wsm_ssid ssids[WSM_SCAN_MAX_NUM_OF_SSIDS]; - int output_power; - int n_ssids; - int status; - atomic_t in_progress; - /* Direct probe requests workaround */ - struct delayed_work probe_work; - int direct_probe; -}; - -int cw1200_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_scan_request *hw_req); -void cw1200_scan_work(struct work_struct *work); -void cw1200_scan_timeout(struct work_struct *work); -void cw1200_clear_recent_scan_work(struct work_struct *work); -void cw1200_scan_complete_cb(struct cw1200_common *priv, - struct wsm_scan_complete *arg); -void cw1200_scan_failed_cb(struct cw1200_common *priv); - -/* ******************************************************************** */ -/* Raw probe requests TX workaround */ -void cw1200_probe_work(struct work_struct *work); - -#endif diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c deleted file mode 100644 index 95a7fdb..0000000 --- a/drivers/net/wireless/cw1200/sta.c +++ /dev/null @@ -1,2399 +0,0 @@ -/* - * Mac80211 STA API for ST-Ericsson CW1200 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/vmalloc.h> -#include <linux/sched.h> -#include <linux/firmware.h> -#include <linux/module.h> -#include <linux/etherdevice.h> - -#include "cw1200.h" -#include "sta.h" -#include "fwio.h" -#include "bh.h" -#include "debug.h" - -#ifndef ERP_INFO_BYTE_OFFSET -#define ERP_INFO_BYTE_OFFSET 2 -#endif - -static void cw1200_do_join(struct cw1200_common *priv); -static void cw1200_do_unjoin(struct cw1200_common *priv); - -static int cw1200_upload_beacon(struct cw1200_common *priv); -static int cw1200_upload_pspoll(struct cw1200_common *priv); -static int cw1200_upload_null(struct cw1200_common *priv); -static int cw1200_upload_qosnull(struct cw1200_common *priv); -static int cw1200_start_ap(struct cw1200_common *priv); -static int cw1200_update_beaconing(struct cw1200_common *priv); -static int cw1200_enable_beaconing(struct cw1200_common *priv, - bool enable); -static void __cw1200_sta_notify(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, - int link_id); -static int __cw1200_flush(struct cw1200_common *priv, bool drop); - -static inline void __cw1200_free_event_queue(struct list_head *list) -{ - struct cw1200_wsm_event *event, *tmp; - list_for_each_entry_safe(event, tmp, list, link) { - list_del(&event->link); - kfree(event); - } -} - -/* ******************************************************************** */ -/* STA API */ - -int cw1200_start(struct ieee80211_hw *dev) -{ - struct cw1200_common *priv = dev->priv; - int ret = 0; - - cw1200_pm_stay_awake(&priv->pm_state, HZ); - - mutex_lock(&priv->conf_mutex); - - /* default EDCA */ - WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007, 47, 0xc8, false); - WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f, 94, 0xc8, false); - WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff, 0, 0xc8, false); - WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff, 0, 0xc8, false); - ret = wsm_set_edca_params(priv, &priv->edca); - if (ret) - goto out; - - ret = cw1200_set_uapsd_param(priv, &priv->edca); - if (ret) - goto out; - - priv->setbssparams_done = false; - - memcpy(priv->mac_addr, dev->wiphy->perm_addr, ETH_ALEN); - priv->mode = NL80211_IFTYPE_MONITOR; - priv->wep_default_key_id = -1; - - priv->cqm_beacon_loss_count = 10; - - ret = cw1200_setup_mac(priv); - if (ret) - goto out; - -out: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -void cw1200_stop(struct ieee80211_hw *dev) -{ - struct cw1200_common *priv = dev->priv; - LIST_HEAD(list); - int i; - - wsm_lock_tx(priv); - - while (down_trylock(&priv->scan.lock)) { - /* Scan is in progress. Force it to stop. */ - priv->scan.req = NULL; - schedule(); - } - up(&priv->scan.lock); - - cancel_delayed_work_sync(&priv->scan.probe_work); - cancel_delayed_work_sync(&priv->scan.timeout); - cancel_delayed_work_sync(&priv->clear_recent_scan_work); - cancel_delayed_work_sync(&priv->join_timeout); - cw1200_cqm_bssloss_sm(priv, 0, 0, 0); - cancel_work_sync(&priv->unjoin_work); - cancel_delayed_work_sync(&priv->link_id_gc_work); - flush_workqueue(priv->workqueue); - del_timer_sync(&priv->mcast_timeout); - mutex_lock(&priv->conf_mutex); - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->listening = false; - - spin_lock(&priv->event_queue_lock); - list_splice_init(&priv->event_queue, &list); - spin_unlock(&priv->event_queue_lock); - __cw1200_free_event_queue(&list); - - - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - priv->join_pending = false; - - for (i = 0; i < 4; i++) - cw1200_queue_clear(&priv->tx_queue[i]); - mutex_unlock(&priv->conf_mutex); - tx_policy_clean(priv); - - /* HACK! */ - if (atomic_xchg(&priv->tx_lock, 1) != 1) - pr_debug("[STA] TX is force-unlocked due to stop request.\n"); - - wsm_unlock_tx(priv); - atomic_xchg(&priv->tx_lock, 0); /* for recovery to work */ -} - -static int cw1200_bssloss_mitigation = 1; -module_param(cw1200_bssloss_mitigation, int, 0644); -MODULE_PARM_DESC(cw1200_bssloss_mitigation, "BSS Loss mitigation. 0 == disabled, 1 == enabled (default)"); - - -void __cw1200_cqm_bssloss_sm(struct cw1200_common *priv, - int init, int good, int bad) -{ - int tx = 0; - - priv->delayed_link_loss = 0; - cancel_work_sync(&priv->bss_params_work); - - pr_debug("[STA] CQM BSSLOSS_SM: state: %d init %d good %d bad: %d txlock: %d uj: %d\n", - priv->bss_loss_state, - init, good, bad, - atomic_read(&priv->tx_lock), - priv->delayed_unjoin); - - /* If we have a pending unjoin */ - if (priv->delayed_unjoin) - return; - - if (init) { - queue_delayed_work(priv->workqueue, - &priv->bss_loss_work, - HZ); - priv->bss_loss_state = 0; - - /* Skip the confimration procedure in P2P case */ - if (!priv->vif->p2p && !atomic_read(&priv->tx_lock)) - tx = 1; - } else if (good) { - cancel_delayed_work_sync(&priv->bss_loss_work); - priv->bss_loss_state = 0; - queue_work(priv->workqueue, &priv->bss_params_work); - } else if (bad) { - /* XXX Should we just keep going until we time out? */ - if (priv->bss_loss_state < 3) - tx = 1; - } else { - cancel_delayed_work_sync(&priv->bss_loss_work); - priv->bss_loss_state = 0; - } - - /* Bypass mitigation if it's disabled */ - if (!cw1200_bssloss_mitigation) - tx = 0; - - /* Spit out a NULL packet to our AP if necessary */ - if (tx) { - struct sk_buff *skb; - - priv->bss_loss_state++; - - skb = ieee80211_nullfunc_get(priv->hw, priv->vif); - WARN_ON(!skb); - if (skb) - cw1200_tx(priv->hw, NULL, skb); - } -} - -int cw1200_add_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) -{ - int ret; - struct cw1200_common *priv = dev->priv; - /* __le32 auto_calibration_mode = __cpu_to_le32(1); */ - - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | - IEEE80211_VIF_SUPPORTS_UAPSD | - IEEE80211_VIF_SUPPORTS_CQM_RSSI; - - mutex_lock(&priv->conf_mutex); - - if (priv->mode != NL80211_IFTYPE_MONITOR) { - mutex_unlock(&priv->conf_mutex); - return -EOPNOTSUPP; - } - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_AP: - priv->mode = vif->type; - break; - default: - mutex_unlock(&priv->conf_mutex); - return -EOPNOTSUPP; - } - - priv->vif = vif; - memcpy(priv->mac_addr, vif->addr, ETH_ALEN); - ret = cw1200_setup_mac(priv); - /* Enable auto-calibration */ - /* Exception in subsequent channel switch; disabled. - * wsm_write_mib(priv, WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE, - * &auto_calibration_mode, sizeof(auto_calibration_mode)); - */ - - mutex_unlock(&priv->conf_mutex); - return ret; -} - -void cw1200_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) -{ - struct cw1200_common *priv = dev->priv; - struct wsm_reset reset = { - .reset_statistics = true, - }; - int i; - - mutex_lock(&priv->conf_mutex); - switch (priv->join_status) { - case CW1200_JOIN_STATUS_JOINING: - case CW1200_JOIN_STATUS_PRE_STA: - case CW1200_JOIN_STATUS_STA: - case CW1200_JOIN_STATUS_IBSS: - wsm_lock_tx(priv); - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - break; - case CW1200_JOIN_STATUS_AP: - for (i = 0; priv->link_id_map; ++i) { - if (priv->link_id_map & BIT(i)) { - reset.link_id = i; - wsm_reset(priv, &reset); - priv->link_id_map &= ~BIT(i); - } - } - memset(priv->link_id_db, 0, sizeof(priv->link_id_db)); - priv->sta_asleep_mask = 0; - priv->enable_beacon = false; - priv->tx_multicast = false; - priv->aid0_bit_set = false; - priv->buffered_multicasts = false; - priv->pspoll_mask = 0; - reset.link_id = 0; - wsm_reset(priv, &reset); - break; - case CW1200_JOIN_STATUS_MONITOR: - cw1200_update_listening(priv, false); - break; - default: - break; - } - priv->vif = NULL; - priv->mode = NL80211_IFTYPE_MONITOR; - eth_zero_addr(priv->mac_addr); - memset(&priv->p2p_ps_modeinfo, 0, sizeof(priv->p2p_ps_modeinfo)); - cw1200_free_keys(priv); - cw1200_setup_mac(priv); - priv->listening = false; - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - if (!__cw1200_flush(priv, true)) - wsm_unlock_tx(priv); - - mutex_unlock(&priv->conf_mutex); -} - -int cw1200_change_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - enum nl80211_iftype new_type, - bool p2p) -{ - int ret = 0; - pr_debug("change_interface new: %d (%d), old: %d (%d)\n", new_type, - p2p, vif->type, vif->p2p); - - if (new_type != vif->type || vif->p2p != p2p) { - cw1200_remove_interface(dev, vif); - vif->type = new_type; - vif->p2p = p2p; - ret = cw1200_add_interface(dev, vif); - } - - return ret; -} - -int cw1200_config(struct ieee80211_hw *dev, u32 changed) -{ - int ret = 0; - struct cw1200_common *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - - pr_debug("CONFIG CHANGED: %08x\n", changed); - - down(&priv->scan.lock); - mutex_lock(&priv->conf_mutex); - /* TODO: IEEE80211_CONF_CHANGE_QOS */ - /* TODO: IEEE80211_CONF_CHANGE_LISTEN_INTERVAL */ - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - priv->output_power = conf->power_level; - pr_debug("[STA] TX power: %d\n", priv->output_power); - wsm_set_output_power(priv, priv->output_power * 10); - } - - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) && - (priv->channel != conf->chandef.chan)) { - struct ieee80211_channel *ch = conf->chandef.chan; - struct wsm_switch_channel channel = { - .channel_number = ch->hw_value, - }; - pr_debug("[STA] Freq %d (wsm ch: %d).\n", - ch->center_freq, ch->hw_value); - - /* __cw1200_flush() implicitly locks tx, if successful */ - if (!__cw1200_flush(priv, false)) { - if (!wsm_switch_channel(priv, &channel)) { - ret = wait_event_timeout(priv->channel_switch_done, - !priv->channel_switch_in_progress, - 3 * HZ); - if (ret) { - /* Already unlocks if successful */ - priv->channel = ch; - ret = 0; - } else { - ret = -ETIMEDOUT; - } - } else { - /* Unlock if switch channel fails */ - wsm_unlock_tx(priv); - } - } - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - if (!(conf->flags & IEEE80211_CONF_PS)) - priv->powersave_mode.mode = WSM_PSM_ACTIVE; - else if (conf->dynamic_ps_timeout <= 0) - priv->powersave_mode.mode = WSM_PSM_PS; - else - priv->powersave_mode.mode = WSM_PSM_FAST_PS; - - /* Firmware requires that value for this 1-byte field must - * be specified in units of 500us. Values above the 128ms - * threshold are not supported. - */ - if (conf->dynamic_ps_timeout >= 0x80) - priv->powersave_mode.fast_psm_idle_period = 0xFF; - else - priv->powersave_mode.fast_psm_idle_period = - conf->dynamic_ps_timeout << 1; - - if (priv->join_status == CW1200_JOIN_STATUS_STA && - priv->bss_params.aid) - cw1200_set_pm(priv, &priv->powersave_mode); - } - - if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - /* TBD: It looks like it's transparent - * there's a monitor interface present -- use this - * to determine for example whether to calculate - * timestamps for packets or not, do not use instead - * of filter flags! - */ - } - - if (changed & IEEE80211_CONF_CHANGE_IDLE) { - struct wsm_operational_mode mode = { - .power_mode = cw1200_power_mode, - .disable_more_flag_usage = true, - }; - - wsm_lock_tx(priv); - /* Disable p2p-dev mode forced by TX request */ - if ((priv->join_status == CW1200_JOIN_STATUS_MONITOR) && - (conf->flags & IEEE80211_CONF_IDLE) && - !priv->listening) { - cw1200_disable_listening(priv); - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - } - wsm_set_operational_mode(priv, &mode); - wsm_unlock_tx(priv); - } - - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - pr_debug("[STA] Retry limits: %d (long), %d (short).\n", - conf->long_frame_max_tx_count, - conf->short_frame_max_tx_count); - spin_lock_bh(&priv->tx_policy_cache.lock); - priv->long_frame_max_tx_count = conf->long_frame_max_tx_count; - priv->short_frame_max_tx_count = - (conf->short_frame_max_tx_count < 0x0F) ? - conf->short_frame_max_tx_count : 0x0F; - priv->hw->max_rate_tries = priv->short_frame_max_tx_count; - spin_unlock_bh(&priv->tx_policy_cache.lock); - } - mutex_unlock(&priv->conf_mutex); - up(&priv->scan.lock); - return ret; -} - -void cw1200_update_filtering(struct cw1200_common *priv) -{ - int ret; - bool bssid_filtering = !priv->rx_filter.bssid; - bool is_p2p = priv->vif && priv->vif->p2p; - bool is_sta = priv->vif && NL80211_IFTYPE_STATION == priv->vif->type; - - static struct wsm_beacon_filter_control bf_ctrl; - static struct wsm_mib_beacon_filter_table bf_tbl = { - .entry[0].ie_id = WLAN_EID_VENDOR_SPECIFIC, - .entry[0].flags = WSM_BEACON_FILTER_IE_HAS_CHANGED | - WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | - WSM_BEACON_FILTER_IE_HAS_APPEARED, - .entry[0].oui[0] = 0x50, - .entry[0].oui[1] = 0x6F, - .entry[0].oui[2] = 0x9A, - .entry[1].ie_id = WLAN_EID_HT_OPERATION, - .entry[1].flags = WSM_BEACON_FILTER_IE_HAS_CHANGED | - WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | - WSM_BEACON_FILTER_IE_HAS_APPEARED, - .entry[2].ie_id = WLAN_EID_ERP_INFO, - .entry[2].flags = WSM_BEACON_FILTER_IE_HAS_CHANGED | - WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | - WSM_BEACON_FILTER_IE_HAS_APPEARED, - }; - - if (priv->join_status == CW1200_JOIN_STATUS_PASSIVE) - return; - else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) - bssid_filtering = false; - - if (priv->disable_beacon_filter) { - bf_ctrl.enabled = 0; - bf_ctrl.bcn_count = 1; - bf_tbl.num = __cpu_to_le32(0); - } else if (is_p2p || !is_sta) { - bf_ctrl.enabled = WSM_BEACON_FILTER_ENABLE | - WSM_BEACON_FILTER_AUTO_ERP; - bf_ctrl.bcn_count = 0; - bf_tbl.num = __cpu_to_le32(2); - } else { - bf_ctrl.enabled = WSM_BEACON_FILTER_ENABLE; - bf_ctrl.bcn_count = 0; - bf_tbl.num = __cpu_to_le32(3); - } - - /* When acting as p2p client being connected to p2p GO, in order to - * receive frames from a different p2p device, turn off bssid filter. - * - * WARNING: FW dependency! - * This can only be used with FW WSM371 and its successors. - * In that FW version even with bssid filter turned off, - * device will block most of the unwanted frames. - */ - if (is_p2p) - bssid_filtering = false; - - ret = wsm_set_rx_filter(priv, &priv->rx_filter); - if (!ret) - ret = wsm_set_beacon_filter_table(priv, &bf_tbl); - if (!ret) - ret = wsm_beacon_filter_control(priv, &bf_ctrl); - if (!ret) - ret = wsm_set_bssid_filtering(priv, bssid_filtering); - if (!ret) - ret = wsm_set_multicast_filter(priv, &priv->multicast_filter); - if (ret) - wiphy_err(priv->hw->wiphy, - "Update filtering failed: %d.\n", ret); - return; -} - -void cw1200_update_filtering_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, - update_filtering_work); - - cw1200_update_filtering(priv); -} - -void cw1200_set_beacon_wakeup_period_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, - set_beacon_wakeup_period_work); - - wsm_set_beacon_wakeup_period(priv, - priv->beacon_int * priv->join_dtim_period > - MAX_BEACON_SKIP_TIME_MS ? 1 : - priv->join_dtim_period, 0); -} - -u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - static u8 broadcast_ipv6[ETH_ALEN] = { - 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 - }; - static u8 broadcast_ipv4[ETH_ALEN] = { - 0x01, 0x00, 0x5e, 0x00, 0x00, 0x01 - }; - struct cw1200_common *priv = hw->priv; - struct netdev_hw_addr *ha; - int count = 0; - - /* Disable multicast filtering */ - priv->has_multicast_subscription = false; - memset(&priv->multicast_filter, 0x00, sizeof(priv->multicast_filter)); - - if (netdev_hw_addr_list_count(mc_list) > WSM_MAX_GRP_ADDRTABLE_ENTRIES) - return 0; - - /* Enable if requested */ - netdev_hw_addr_list_for_each(ha, mc_list) { - pr_debug("[STA] multicast: %pM\n", ha->addr); - memcpy(&priv->multicast_filter.macaddrs[count], - ha->addr, ETH_ALEN); - if (!ether_addr_equal(ha->addr, broadcast_ipv4) && - !ether_addr_equal(ha->addr, broadcast_ipv6)) - priv->has_multicast_subscription = true; - count++; - } - - if (count) { - priv->multicast_filter.enable = __cpu_to_le32(1); - priv->multicast_filter.num_addrs = __cpu_to_le32(count); - } - - return netdev_hw_addr_list_count(mc_list); -} - -void cw1200_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct cw1200_common *priv = dev->priv; - bool listening = !!(*total_flags & - (FIF_OTHER_BSS | - FIF_BCN_PRBRESP_PROMISC | - FIF_PROBE_REQ)); - - *total_flags &= FIF_OTHER_BSS | - FIF_FCSFAIL | - FIF_BCN_PRBRESP_PROMISC | - FIF_PROBE_REQ; - - down(&priv->scan.lock); - mutex_lock(&priv->conf_mutex); - - priv->rx_filter.promiscuous = 0; - priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS | - FIF_PROBE_REQ)) ? 1 : 0; - priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0; - priv->disable_beacon_filter = !(*total_flags & - (FIF_BCN_PRBRESP_PROMISC | - FIF_PROBE_REQ)); - if (priv->listening != listening) { - priv->listening = listening; - wsm_lock_tx(priv); - cw1200_update_listening(priv, listening); - wsm_unlock_tx(priv); - } - cw1200_update_filtering(priv); - mutex_unlock(&priv->conf_mutex); - up(&priv->scan.lock); -} - -int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) -{ - struct cw1200_common *priv = dev->priv; - int ret = 0; - /* To prevent re-applying PM request OID again and again*/ - bool old_uapsd_flags; - - mutex_lock(&priv->conf_mutex); - - if (queue < dev->queues) { - old_uapsd_flags = le16_to_cpu(priv->uapsd_info.uapsd_flags); - - WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0); - ret = wsm_set_tx_queue_params(priv, - &priv->tx_queue_params.params[queue], queue); - if (ret) { - ret = -EINVAL; - goto out; - } - - WSM_EDCA_SET(&priv->edca, queue, params->aifs, - params->cw_min, params->cw_max, - params->txop, 0xc8, - params->uapsd); - ret = wsm_set_edca_params(priv, &priv->edca); - if (ret) { - ret = -EINVAL; - goto out; - } - - if (priv->mode == NL80211_IFTYPE_STATION) { - ret = cw1200_set_uapsd_param(priv, &priv->edca); - if (!ret && priv->setbssparams_done && - (priv->join_status == CW1200_JOIN_STATUS_STA) && - (old_uapsd_flags != le16_to_cpu(priv->uapsd_info.uapsd_flags))) - ret = cw1200_set_pm(priv, &priv->powersave_mode); - } - } else { - ret = -EINVAL; - } - -out: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -int cw1200_get_stats(struct ieee80211_hw *dev, - struct ieee80211_low_level_stats *stats) -{ - struct cw1200_common *priv = dev->priv; - - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; -} - -int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) -{ - struct wsm_set_pm pm = *arg; - - if (priv->uapsd_info.uapsd_flags != 0) - pm.mode &= ~WSM_PSM_FAST_PS_FLAG; - - if (memcmp(&pm, &priv->firmware_ps_mode, - sizeof(struct wsm_set_pm))) { - priv->firmware_ps_mode = pm; - return wsm_set_pm(priv, &pm); - } else { - return 0; - } -} - -int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - int ret = -EOPNOTSUPP; - struct cw1200_common *priv = dev->priv; - struct ieee80211_key_seq seq; - - mutex_lock(&priv->conf_mutex); - - if (cmd == SET_KEY) { - u8 *peer_addr = NULL; - int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ? - 1 : 0; - int idx = cw1200_alloc_key(priv); - struct wsm_add_key *wsm_key = &priv->keys[idx]; - - if (idx < 0) { - ret = -EINVAL; - goto finally; - } - - if (sta) - peer_addr = sta->addr; - - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | - IEEE80211_KEY_FLAG_RESERVE_TAILROOM; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - if (key->keylen > 16) { - cw1200_free_key(priv, idx); - ret = -EINVAL; - goto finally; - } - - if (pairwise) { - wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; - memcpy(wsm_key->wep_pairwise.peer, - peer_addr, ETH_ALEN); - memcpy(wsm_key->wep_pairwise.keydata, - &key->key[0], key->keylen); - wsm_key->wep_pairwise.keylen = key->keylen; - } else { - wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; - memcpy(wsm_key->wep_group.keydata, - &key->key[0], key->keylen); - wsm_key->wep_group.keylen = key->keylen; - wsm_key->wep_group.keyid = key->keyidx; - } - break; - case WLAN_CIPHER_SUITE_TKIP: - ieee80211_get_key_rx_seq(key, 0, &seq); - if (pairwise) { - wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; - memcpy(wsm_key->tkip_pairwise.peer, - peer_addr, ETH_ALEN); - memcpy(wsm_key->tkip_pairwise.keydata, - &key->key[0], 16); - memcpy(wsm_key->tkip_pairwise.tx_mic_key, - &key->key[16], 8); - memcpy(wsm_key->tkip_pairwise.rx_mic_key, - &key->key[24], 8); - } else { - size_t mic_offset = - (priv->mode == NL80211_IFTYPE_AP) ? - 16 : 24; - wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; - memcpy(wsm_key->tkip_group.keydata, - &key->key[0], 16); - memcpy(wsm_key->tkip_group.rx_mic_key, - &key->key[mic_offset], 8); - - wsm_key->tkip_group.rx_seqnum[0] = seq.tkip.iv16 & 0xff; - wsm_key->tkip_group.rx_seqnum[1] = (seq.tkip.iv16 >> 8) & 0xff; - wsm_key->tkip_group.rx_seqnum[2] = seq.tkip.iv32 & 0xff; - wsm_key->tkip_group.rx_seqnum[3] = (seq.tkip.iv32 >> 8) & 0xff; - wsm_key->tkip_group.rx_seqnum[4] = (seq.tkip.iv32 >> 16) & 0xff; - wsm_key->tkip_group.rx_seqnum[5] = (seq.tkip.iv32 >> 24) & 0xff; - wsm_key->tkip_group.rx_seqnum[6] = 0; - wsm_key->tkip_group.rx_seqnum[7] = 0; - - wsm_key->tkip_group.keyid = key->keyidx; - } - break; - case WLAN_CIPHER_SUITE_CCMP: - ieee80211_get_key_rx_seq(key, 0, &seq); - if (pairwise) { - wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; - memcpy(wsm_key->aes_pairwise.peer, - peer_addr, ETH_ALEN); - memcpy(wsm_key->aes_pairwise.keydata, - &key->key[0], 16); - } else { - wsm_key->type = WSM_KEY_TYPE_AES_GROUP; - memcpy(wsm_key->aes_group.keydata, - &key->key[0], 16); - - wsm_key->aes_group.rx_seqnum[0] = seq.ccmp.pn[5]; - wsm_key->aes_group.rx_seqnum[1] = seq.ccmp.pn[4]; - wsm_key->aes_group.rx_seqnum[2] = seq.ccmp.pn[3]; - wsm_key->aes_group.rx_seqnum[3] = seq.ccmp.pn[2]; - wsm_key->aes_group.rx_seqnum[4] = seq.ccmp.pn[1]; - wsm_key->aes_group.rx_seqnum[5] = seq.ccmp.pn[0]; - wsm_key->aes_group.rx_seqnum[6] = 0; - wsm_key->aes_group.rx_seqnum[7] = 0; - wsm_key->aes_group.keyid = key->keyidx; - } - break; - case WLAN_CIPHER_SUITE_SMS4: - if (pairwise) { - wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; - memcpy(wsm_key->wapi_pairwise.peer, - peer_addr, ETH_ALEN); - memcpy(wsm_key->wapi_pairwise.keydata, - &key->key[0], 16); - memcpy(wsm_key->wapi_pairwise.mic_key, - &key->key[16], 16); - wsm_key->wapi_pairwise.keyid = key->keyidx; - } else { - wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; - memcpy(wsm_key->wapi_group.keydata, - &key->key[0], 16); - memcpy(wsm_key->wapi_group.mic_key, - &key->key[16], 16); - wsm_key->wapi_group.keyid = key->keyidx; - } - break; - default: - pr_warn("Unhandled key type %d\n", key->cipher); - cw1200_free_key(priv, idx); - ret = -EOPNOTSUPP; - goto finally; - } - ret = wsm_add_key(priv, wsm_key); - if (!ret) - key->hw_key_idx = idx; - else - cw1200_free_key(priv, idx); - } else if (cmd == DISABLE_KEY) { - struct wsm_remove_key wsm_key = { - .index = key->hw_key_idx, - }; - - if (wsm_key.index > WSM_KEY_MAX_INDEX) { - ret = -EINVAL; - goto finally; - } - - cw1200_free_key(priv, wsm_key.index); - ret = wsm_remove_key(priv, &wsm_key); - } else { - pr_warn("Unhandled key command %d\n", cmd); - } - -finally: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -void cw1200_wep_key_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, wep_key_work); - u8 queue_id = cw1200_queue_get_queue_id(priv->pending_frame_id); - struct cw1200_queue *queue = &priv->tx_queue[queue_id]; - __le32 wep_default_key_id = __cpu_to_le32( - priv->wep_default_key_id); - - pr_debug("[STA] Setting default WEP key: %d\n", - priv->wep_default_key_id); - wsm_flush_tx(priv); - wsm_write_mib(priv, WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, - &wep_default_key_id, sizeof(wep_default_key_id)); - cw1200_queue_requeue(queue, priv->pending_frame_id); - wsm_unlock_tx(priv); -} - -int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - int ret = 0; - __le32 val32; - struct cw1200_common *priv = hw->priv; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return 0; - - if (value != (u32) -1) - val32 = __cpu_to_le32(value); - else - val32 = 0; /* disabled */ - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { - /* device is down, can _not_ set threshold */ - ret = -ENODEV; - goto out; - } - - if (priv->rts_threshold == value) - goto out; - - pr_debug("[STA] Setting RTS threshold: %d\n", - priv->rts_threshold); - - /* mutex_lock(&priv->conf_mutex); */ - ret = wsm_write_mib(priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD, - &val32, sizeof(val32)); - if (!ret) - priv->rts_threshold = value; - /* mutex_unlock(&priv->conf_mutex); */ - -out: - return ret; -} - -/* If successful, LOCKS the TX queue! */ -static int __cw1200_flush(struct cw1200_common *priv, bool drop) -{ - int i, ret; - - for (;;) { - /* TODO: correct flush handling is required when dev_stop. - * Temporary workaround: 2s - */ - if (drop) { - for (i = 0; i < 4; ++i) - cw1200_queue_clear(&priv->tx_queue[i]); - } else { - ret = wait_event_timeout( - priv->tx_queue_stats.wait_link_id_empty, - cw1200_queue_stats_is_empty( - &priv->tx_queue_stats, -1), - 2 * HZ); - } - - if (!drop && ret <= 0) { - ret = -ETIMEDOUT; - break; - } else { - ret = 0; - } - - wsm_lock_tx(priv); - if (!cw1200_queue_stats_is_empty(&priv->tx_queue_stats, -1)) { - /* Highly unlikely: WSM requeued frames. */ - wsm_unlock_tx(priv); - continue; - } - break; - } - return ret; -} - -void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) -{ - struct cw1200_common *priv = hw->priv; - - switch (priv->mode) { - case NL80211_IFTYPE_MONITOR: - drop = true; - break; - case NL80211_IFTYPE_AP: - if (!priv->enable_beacon) - drop = true; - break; - } - - if (!__cw1200_flush(priv, drop)) - wsm_unlock_tx(priv); - - return; -} - -/* ******************************************************************** */ -/* WSM callbacks */ - -void cw1200_free_event_queue(struct cw1200_common *priv) -{ - LIST_HEAD(list); - - spin_lock(&priv->event_queue_lock); - list_splice_init(&priv->event_queue, &list); - spin_unlock(&priv->event_queue_lock); - - __cw1200_free_event_queue(&list); -} - -void cw1200_event_handler(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, event_handler); - struct cw1200_wsm_event *event; - LIST_HEAD(list); - - spin_lock(&priv->event_queue_lock); - list_splice_init(&priv->event_queue, &list); - spin_unlock(&priv->event_queue_lock); - - list_for_each_entry(event, &list, link) { - switch (event->evt.id) { - case WSM_EVENT_ERROR: - pr_err("Unhandled WSM Error from LMAC\n"); - break; - case WSM_EVENT_BSS_LOST: - pr_debug("[CQM] BSS lost.\n"); - cancel_work_sync(&priv->unjoin_work); - if (!down_trylock(&priv->scan.lock)) { - cw1200_cqm_bssloss_sm(priv, 1, 0, 0); - up(&priv->scan.lock); - } else { - /* Scan is in progress. Delay reporting. - * Scan complete will trigger bss_loss_work - */ - priv->delayed_link_loss = 1; - /* Also start a watchdog. */ - queue_delayed_work(priv->workqueue, - &priv->bss_loss_work, 5*HZ); - } - break; - case WSM_EVENT_BSS_REGAINED: - pr_debug("[CQM] BSS regained.\n"); - cw1200_cqm_bssloss_sm(priv, 0, 0, 0); - cancel_work_sync(&priv->unjoin_work); - break; - case WSM_EVENT_RADAR_DETECTED: - wiphy_info(priv->hw->wiphy, "radar pulse detected\n"); - break; - case WSM_EVENT_RCPI_RSSI: - { - /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 - * RSSI = RCPI / 2 - 110 - */ - int rcpi_rssi = (int)(event->evt.data & 0xFF); - int cqm_evt; - if (priv->cqm_use_rssi) - rcpi_rssi = (s8)rcpi_rssi; - else - rcpi_rssi = rcpi_rssi / 2 - 110; - - cqm_evt = (rcpi_rssi <= priv->cqm_rssi_thold) ? - NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : - NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - pr_debug("[CQM] RSSI event: %d.\n", rcpi_rssi); - ieee80211_cqm_rssi_notify(priv->vif, cqm_evt, - GFP_KERNEL); - break; - } - case WSM_EVENT_BT_INACTIVE: - pr_warn("Unhandled BT INACTIVE from LMAC\n"); - break; - case WSM_EVENT_BT_ACTIVE: - pr_warn("Unhandled BT ACTIVE from LMAC\n"); - break; - } - } - __cw1200_free_event_queue(&list); -} - -void cw1200_bss_loss_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, bss_loss_work.work); - - pr_debug("[CQM] Reporting connection loss.\n"); - wsm_lock_tx(priv); - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); -} - -void cw1200_bss_params_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, bss_params_work); - mutex_lock(&priv->conf_mutex); - - priv->bss_params.reset_beacon_loss = 1; - wsm_set_bss_params(priv, &priv->bss_params); - priv->bss_params.reset_beacon_loss = 0; - - mutex_unlock(&priv->conf_mutex); -} - -/* ******************************************************************** */ -/* Internal API */ - -/* This function is called to Parse the SDD file - * to extract listen_interval and PTA related information - * sdd is a TLV: u8 id, u8 len, u8 data[] - */ -static int cw1200_parse_sdd_file(struct cw1200_common *priv) -{ - const u8 *p = priv->sdd->data; - int ret = 0; - - while (p + 2 <= priv->sdd->data + priv->sdd->size) { - if (p + p[1] + 2 > priv->sdd->data + priv->sdd->size) { - pr_warn("Malformed sdd structure\n"); - return -1; - } - switch (p[0]) { - case SDD_PTA_CFG_ELT_ID: { - u16 v; - if (p[1] < 4) { - pr_warn("SDD_PTA_CFG_ELT_ID malformed\n"); - ret = -1; - break; - } - v = le16_to_cpu(*((__le16 *)(p + 2))); - if (!v) /* non-zero means this is enabled */ - break; - - v = le16_to_cpu(*((__le16 *)(p + 4))); - priv->conf_listen_interval = (v >> 7) & 0x1F; - pr_debug("PTA found; Listen Interval %d\n", - priv->conf_listen_interval); - break; - } - case SDD_REFERENCE_FREQUENCY_ELT_ID: { - u16 clk = le16_to_cpu(*((__le16 *)(p + 2))); - if (clk != priv->hw_refclk) - pr_warn("SDD file doesn't match configured refclk (%d vs %d)\n", - clk, priv->hw_refclk); - break; - } - default: - break; - } - p += p[1] + 2; - } - - if (!priv->bt_present) { - pr_debug("PTA element NOT found.\n"); - priv->conf_listen_interval = 0; - } - return ret; -} - -int cw1200_setup_mac(struct cw1200_common *priv) -{ - int ret = 0; - - /* NOTE: There is a bug in FW: it reports signal - * as RSSI if RSSI subscription is enabled. - * It's not enough to set WSM_RCPI_RSSI_USE_RSSI. - * - * NOTE2: RSSI based reports have been switched to RCPI, since - * FW has a bug and RSSI reported values are not stable, - * what can leads to signal level oscilations in user-end applications - */ - struct wsm_rcpi_rssi_threshold threshold = { - .rssiRcpiMode = WSM_RCPI_RSSI_THRESHOLD_ENABLE | - WSM_RCPI_RSSI_DONT_USE_UPPER | - WSM_RCPI_RSSI_DONT_USE_LOWER, - .rollingAverageCount = 16, - }; - - struct wsm_configuration cfg = { - .dot11StationId = &priv->mac_addr[0], - }; - - /* Remember the decission here to make sure, we will handle - * the RCPI/RSSI value correctly on WSM_EVENT_RCPI_RSS - */ - if (threshold.rssiRcpiMode & WSM_RCPI_RSSI_USE_RSSI) - priv->cqm_use_rssi = true; - - if (!priv->sdd) { - ret = request_firmware(&priv->sdd, priv->sdd_path, priv->pdev); - if (ret) { - pr_err("Can't load sdd file %s.\n", priv->sdd_path); - return ret; - } - cw1200_parse_sdd_file(priv); - } - - cfg.dpdData = priv->sdd->data; - cfg.dpdData_size = priv->sdd->size; - ret = wsm_configuration(priv, &cfg); - if (ret) - return ret; - - /* Configure RSSI/SCPI reporting as RSSI. */ - wsm_set_rcpi_rssi_threshold(priv, &threshold); - - return 0; -} - -static void cw1200_join_complete(struct cw1200_common *priv) -{ - pr_debug("[STA] Join complete (%d)\n", priv->join_complete_status); - - priv->join_pending = false; - if (priv->join_complete_status) { - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - cw1200_update_listening(priv, priv->listening); - cw1200_do_unjoin(priv); - ieee80211_connection_loss(priv->vif); - } else { - if (priv->mode == NL80211_IFTYPE_ADHOC) - priv->join_status = CW1200_JOIN_STATUS_IBSS; - else - priv->join_status = CW1200_JOIN_STATUS_PRE_STA; - } - wsm_unlock_tx(priv); /* Clearing the lock held before do_join() */ -} - -void cw1200_join_complete_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, join_complete_work); - mutex_lock(&priv->conf_mutex); - cw1200_join_complete(priv); - mutex_unlock(&priv->conf_mutex); -} - -void cw1200_join_complete_cb(struct cw1200_common *priv, - struct wsm_join_complete *arg) -{ - pr_debug("[STA] cw1200_join_complete_cb called, status=%d.\n", - arg->status); - - if (cancel_delayed_work(&priv->join_timeout)) { - priv->join_complete_status = arg->status; - queue_work(priv->workqueue, &priv->join_complete_work); - } -} - -/* MUST be called with tx_lock held! It will be unlocked for us. */ -static void cw1200_do_join(struct cw1200_common *priv) -{ - const u8 *bssid; - struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; - struct cfg80211_bss *bss = NULL; - struct wsm_protected_mgmt_policy mgmt_policy; - struct wsm_join join = { - .mode = conf->ibss_joined ? - WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, - .preamble_type = WSM_JOIN_PREAMBLE_LONG, - .probe_for_join = 1, - .atim_window = 0, - .basic_rate_set = cw1200_rate_mask_to_wsm(priv, - conf->basic_rates), - }; - if (delayed_work_pending(&priv->join_timeout)) { - pr_warn("[STA] - Join request already pending, skipping..\n"); - wsm_unlock_tx(priv); - return; - } - - if (priv->join_status) - cw1200_do_unjoin(priv); - - bssid = priv->vif->bss_conf.bssid; - - bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0, - IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - - if (!bss && !conf->ibss_joined) { - wsm_unlock_tx(priv); - return; - } - - mutex_lock(&priv->conf_mutex); - - /* Under the conf lock: check scan status and - * bail out if it is in progress. - */ - if (atomic_read(&priv->scan.in_progress)) { - wsm_unlock_tx(priv); - goto done_put; - } - - priv->join_pending = true; - - /* Sanity check basic rates */ - if (!join.basic_rate_set) - join.basic_rate_set = 7; - - /* Sanity check beacon interval */ - if (!priv->beacon_int) - priv->beacon_int = 1; - - join.beacon_interval = priv->beacon_int; - - /* BT Coex related changes */ - if (priv->bt_present) { - if (((priv->conf_listen_interval * 100) % - priv->beacon_int) == 0) - priv->listen_interval = - ((priv->conf_listen_interval * 100) / - priv->beacon_int); - else - priv->listen_interval = - ((priv->conf_listen_interval * 100) / - priv->beacon_int + 1); - } - - if (priv->hw->conf.ps_dtim_period) - priv->join_dtim_period = priv->hw->conf.ps_dtim_period; - join.dtim_period = priv->join_dtim_period; - - join.channel_number = priv->channel->hw_value; - join.band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? - WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; - - memcpy(join.bssid, bssid, sizeof(join.bssid)); - - pr_debug("[STA] Join BSSID: %pM DTIM: %d, interval: %d\n", - join.bssid, - join.dtim_period, priv->beacon_int); - - if (!conf->ibss_joined) { - const u8 *ssidie; - rcu_read_lock(); - ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); - if (ssidie) { - join.ssid_len = ssidie[1]; - memcpy(join.ssid, &ssidie[2], join.ssid_len); - } - rcu_read_unlock(); - } - - if (priv->vif->p2p) { - join.flags |= WSM_JOIN_FLAGS_P2P_GO; - join.basic_rate_set = - cw1200_rate_mask_to_wsm(priv, 0xFF0); - } - - /* Enable asynchronous join calls */ - if (!conf->ibss_joined) { - join.flags |= WSM_JOIN_FLAGS_FORCE; - join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND; - } - - wsm_flush_tx(priv); - - /* Stay Awake for Join and Auth Timeouts and a bit more */ - cw1200_pm_stay_awake(&priv->pm_state, - CW1200_JOIN_TIMEOUT + CW1200_AUTH_TIMEOUT); - - cw1200_update_listening(priv, false); - - /* Turn on Block ACKs */ - wsm_set_block_ack_policy(priv, priv->ba_tx_tid_mask, - priv->ba_rx_tid_mask); - - /* Set up timeout */ - if (join.flags & WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND) { - priv->join_status = CW1200_JOIN_STATUS_JOINING; - queue_delayed_work(priv->workqueue, - &priv->join_timeout, - CW1200_JOIN_TIMEOUT); - } - - /* 802.11w protected mgmt frames */ - mgmt_policy.protectedMgmtEnable = 0; - mgmt_policy.unprotectedMgmtFramesAllowed = 1; - mgmt_policy.encryptionForAuthFrame = 1; - wsm_set_protected_mgmt_policy(priv, &mgmt_policy); - - /* Perform actual join */ - if (wsm_join(priv, &join)) { - pr_err("[STA] cw1200_join_work: wsm_join failed!\n"); - cancel_delayed_work_sync(&priv->join_timeout); - cw1200_update_listening(priv, priv->listening); - /* Tx lock still held, unjoin will clear it. */ - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - } else { - if (!(join.flags & WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND)) - cw1200_join_complete(priv); /* Will clear tx_lock */ - - /* Upload keys */ - cw1200_upload_keys(priv); - - /* Due to beacon filtering it is possible that the - * AP's beacon is not known for the mac80211 stack. - * Disable filtering temporary to make sure the stack - * receives at least one - */ - priv->disable_beacon_filter = true; - } - cw1200_update_filtering(priv); - -done_put: - mutex_unlock(&priv->conf_mutex); - if (bss) - cfg80211_put_bss(priv->hw->wiphy, bss); -} - -void cw1200_join_timeout(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, join_timeout.work); - pr_debug("[WSM] Join timed out.\n"); - wsm_lock_tx(priv); - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); -} - -static void cw1200_do_unjoin(struct cw1200_common *priv) -{ - struct wsm_reset reset = { - .reset_statistics = true, - }; - - cancel_delayed_work_sync(&priv->join_timeout); - - mutex_lock(&priv->conf_mutex); - priv->join_pending = false; - - if (atomic_read(&priv->scan.in_progress)) { - if (priv->delayed_unjoin) - wiphy_dbg(priv->hw->wiphy, "Delayed unjoin is already scheduled.\n"); - else - priv->delayed_unjoin = true; - goto done; - } - - priv->delayed_link_loss = false; - - if (!priv->join_status) - goto done; - - if (priv->join_status == CW1200_JOIN_STATUS_AP) - goto done; - - cancel_work_sync(&priv->update_filtering_work); - cancel_work_sync(&priv->set_beacon_wakeup_period_work); - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - - /* Unjoin is a reset. */ - wsm_flush_tx(priv); - wsm_keep_alive_period(priv, 0); - wsm_reset(priv, &reset); - wsm_set_output_power(priv, priv->output_power * 10); - priv->join_dtim_period = 0; - cw1200_setup_mac(priv); - cw1200_free_event_queue(priv); - cancel_work_sync(&priv->event_handler); - cw1200_update_listening(priv, priv->listening); - cw1200_cqm_bssloss_sm(priv, 0, 0, 0); - - /* Disable Block ACKs */ - wsm_set_block_ack_policy(priv, 0, 0); - - priv->disable_beacon_filter = false; - cw1200_update_filtering(priv); - memset(&priv->association_mode, 0, - sizeof(priv->association_mode)); - memset(&priv->bss_params, 0, sizeof(priv->bss_params)); - priv->setbssparams_done = false; - memset(&priv->firmware_ps_mode, 0, - sizeof(priv->firmware_ps_mode)); - - pr_debug("[STA] Unjoin completed.\n"); - -done: - mutex_unlock(&priv->conf_mutex); -} - -void cw1200_unjoin_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, unjoin_work); - - cw1200_do_unjoin(priv); - - /* Tell the stack we're dead */ - ieee80211_connection_loss(priv->vif); - - wsm_unlock_tx(priv); -} - -int cw1200_enable_listening(struct cw1200_common *priv) -{ - struct wsm_start start = { - .mode = WSM_START_MODE_P2P_DEV, - .band = WSM_PHY_BAND_2_4G, - .beacon_interval = 100, - .dtim_period = 1, - .probe_delay = 0, - .basic_rate_set = 0x0F, - }; - - if (priv->channel) { - start.band = priv->channel->band == IEEE80211_BAND_5GHZ ? - WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; - start.channel_number = priv->channel->hw_value; - } else { - start.band = WSM_PHY_BAND_2_4G; - start.channel_number = 1; - } - - return wsm_start(priv, &start); -} - -int cw1200_disable_listening(struct cw1200_common *priv) -{ - int ret; - struct wsm_reset reset = { - .reset_statistics = true, - }; - ret = wsm_reset(priv, &reset); - return ret; -} - -void cw1200_update_listening(struct cw1200_common *priv, bool enabled) -{ - if (enabled) { - if (priv->join_status == CW1200_JOIN_STATUS_PASSIVE) { - if (!cw1200_enable_listening(priv)) - priv->join_status = CW1200_JOIN_STATUS_MONITOR; - wsm_set_probe_responder(priv, true); - } - } else { - if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { - if (!cw1200_disable_listening(priv)) - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - wsm_set_probe_responder(priv, false); - } - } -} - -int cw1200_set_uapsd_param(struct cw1200_common *priv, - const struct wsm_edca_params *arg) -{ - int ret; - u16 uapsd_flags = 0; - - /* Here's the mapping AC [queue, bit] - * VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0] - */ - - if (arg->uapsd_enable[0]) - uapsd_flags |= 1 << 3; - - if (arg->uapsd_enable[1]) - uapsd_flags |= 1 << 2; - - if (arg->uapsd_enable[2]) - uapsd_flags |= 1 << 1; - - if (arg->uapsd_enable[3]) - uapsd_flags |= 1; - - /* Currently pseudo U-APSD operation is not supported, so setting - * MinAutoTriggerInterval, MaxAutoTriggerInterval and - * AutoTriggerStep to 0 - */ - - priv->uapsd_info.uapsd_flags = cpu_to_le16(uapsd_flags); - priv->uapsd_info.min_auto_trigger_interval = 0; - priv->uapsd_info.max_auto_trigger_interval = 0; - priv->uapsd_info.auto_trigger_step = 0; - - ret = wsm_set_uapsd_info(priv, &priv->uapsd_info); - return ret; -} - -/* ******************************************************************** */ -/* AP API */ - -int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct cw1200_common *priv = hw->priv; - struct cw1200_sta_priv *sta_priv = - (struct cw1200_sta_priv *)&sta->drv_priv; - struct cw1200_link_entry *entry; - struct sk_buff *skb; - - if (priv->mode != NL80211_IFTYPE_AP) - return 0; - - sta_priv->link_id = cw1200_find_link_id(priv, sta->addr); - if (WARN_ON(!sta_priv->link_id)) { - wiphy_info(priv->hw->wiphy, - "[AP] No more link IDs available.\n"); - return -ENOENT; - } - - entry = &priv->link_id_db[sta_priv->link_id - 1]; - spin_lock_bh(&priv->ps_state_lock); - if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == - IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) - priv->sta_asleep_mask |= BIT(sta_priv->link_id); - entry->status = CW1200_LINK_HARD; - while ((skb = skb_dequeue(&entry->rx_queue))) - ieee80211_rx_irqsafe(priv->hw, skb); - spin_unlock_bh(&priv->ps_state_lock); - return 0; -} - -int cw1200_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct cw1200_common *priv = hw->priv; - struct cw1200_sta_priv *sta_priv = - (struct cw1200_sta_priv *)&sta->drv_priv; - struct cw1200_link_entry *entry; - - if (priv->mode != NL80211_IFTYPE_AP || !sta_priv->link_id) - return 0; - - entry = &priv->link_id_db[sta_priv->link_id - 1]; - spin_lock_bh(&priv->ps_state_lock); - entry->status = CW1200_LINK_RESERVE; - entry->timestamp = jiffies; - wsm_lock_tx_async(priv); - if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) - wsm_unlock_tx(priv); - spin_unlock_bh(&priv->ps_state_lock); - flush_workqueue(priv->workqueue); - return 0; -} - -static void __cw1200_sta_notify(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, - int link_id) -{ - struct cw1200_common *priv = dev->priv; - u32 bit, prev; - - /* Zero link id means "for all link IDs" */ - if (link_id) - bit = BIT(link_id); - else if (WARN_ON_ONCE(notify_cmd != STA_NOTIFY_AWAKE)) - bit = 0; - else - bit = priv->link_id_map; - prev = priv->sta_asleep_mask & bit; - - switch (notify_cmd) { - case STA_NOTIFY_SLEEP: - if (!prev) { - if (priv->buffered_multicasts && - !priv->sta_asleep_mask) - queue_work(priv->workqueue, - &priv->multicast_start_work); - priv->sta_asleep_mask |= bit; - } - break; - case STA_NOTIFY_AWAKE: - if (prev) { - priv->sta_asleep_mask &= ~bit; - priv->pspoll_mask &= ~bit; - if (priv->tx_multicast && link_id && - !priv->sta_asleep_mask) - queue_work(priv->workqueue, - &priv->multicast_stop_work); - cw1200_bh_wakeup(priv); - } - break; - } -} - -void cw1200_sta_notify(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, - struct ieee80211_sta *sta) -{ - struct cw1200_common *priv = dev->priv; - struct cw1200_sta_priv *sta_priv = - (struct cw1200_sta_priv *)&sta->drv_priv; - - spin_lock_bh(&priv->ps_state_lock); - __cw1200_sta_notify(dev, vif, notify_cmd, sta_priv->link_id); - spin_unlock_bh(&priv->ps_state_lock); -} - -static void cw1200_ps_notify(struct cw1200_common *priv, - int link_id, bool ps) -{ - if (link_id > CW1200_MAX_STA_IN_AP_MODE) - return; - - pr_debug("%s for LinkId: %d. STAs asleep: %.8X\n", - ps ? "Stop" : "Start", - link_id, priv->sta_asleep_mask); - - __cw1200_sta_notify(priv->hw, priv->vif, - ps ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, link_id); -} - -static int cw1200_set_tim_impl(struct cw1200_common *priv, bool aid0_bit_set) -{ - struct sk_buff *skb; - struct wsm_update_ie update_ie = { - .what = WSM_UPDATE_IE_BEACON, - .count = 1, - }; - u16 tim_offset, tim_length; - - pr_debug("[AP] mcast: %s.\n", aid0_bit_set ? "ena" : "dis"); - - skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, - &tim_offset, &tim_length); - if (!skb) { - if (!__cw1200_flush(priv, true)) - wsm_unlock_tx(priv); - return -ENOENT; - } - - if (tim_offset && tim_length >= 6) { - /* Ignore DTIM count from mac80211: - * firmware handles DTIM internally. - */ - skb->data[tim_offset + 2] = 0; - - /* Set/reset aid0 bit */ - if (aid0_bit_set) - skb->data[tim_offset + 4] |= 1; - else - skb->data[tim_offset + 4] &= ~1; - } - - update_ie.ies = &skb->data[tim_offset]; - update_ie.length = tim_length; - wsm_update_ie(priv, &update_ie); - - dev_kfree_skb(skb); - - return 0; -} - -void cw1200_set_tim_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, set_tim_work); - (void)cw1200_set_tim_impl(priv, priv->aid0_bit_set); -} - -int cw1200_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, - bool set) -{ - struct cw1200_common *priv = dev->priv; - queue_work(priv->workqueue, &priv->set_tim_work); - return 0; -} - -void cw1200_set_cts_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, set_cts_work); - - u8 erp_ie[3] = {WLAN_EID_ERP_INFO, 0x1, 0}; - struct wsm_update_ie update_ie = { - .what = WSM_UPDATE_IE_BEACON, - .count = 1, - .ies = erp_ie, - .length = 3, - }; - u32 erp_info; - __le32 use_cts_prot; - mutex_lock(&priv->conf_mutex); - erp_info = priv->erp_info; - mutex_unlock(&priv->conf_mutex); - use_cts_prot = - erp_info & WLAN_ERP_USE_PROTECTION ? - __cpu_to_le32(1) : 0; - - erp_ie[ERP_INFO_BYTE_OFFSET] = erp_info; - - pr_debug("[STA] ERP information 0x%x\n", erp_info); - - wsm_write_mib(priv, WSM_MIB_ID_NON_ERP_PROTECTION, - &use_cts_prot, sizeof(use_cts_prot)); - wsm_update_ie(priv, &update_ie); - - return; -} - -static int cw1200_set_btcoexinfo(struct cw1200_common *priv) -{ - struct wsm_override_internal_txrate arg; - int ret = 0; - - if (priv->mode == NL80211_IFTYPE_STATION) { - /* Plumb PSPOLL and NULL template */ - cw1200_upload_pspoll(priv); - cw1200_upload_null(priv); - cw1200_upload_qosnull(priv); - } else { - return 0; - } - - memset(&arg, 0, sizeof(struct wsm_override_internal_txrate)); - - if (!priv->vif->p2p) { - /* STATION mode */ - if (priv->bss_params.operational_rate_set & ~0xF) { - pr_debug("[STA] STA has ERP rates\n"); - /* G or BG mode */ - arg.internalTxRate = (__ffs( - priv->bss_params.operational_rate_set & ~0xF)); - } else { - pr_debug("[STA] STA has non ERP rates\n"); - /* B only mode */ - arg.internalTxRate = (__ffs(le32_to_cpu(priv->association_mode.basic_rate_set))); - } - arg.nonErpInternalTxRate = (__ffs(le32_to_cpu(priv->association_mode.basic_rate_set))); - } else { - /* P2P mode */ - arg.internalTxRate = (__ffs(priv->bss_params.operational_rate_set & ~0xF)); - arg.nonErpInternalTxRate = (__ffs(priv->bss_params.operational_rate_set & ~0xF)); - } - - pr_debug("[STA] BTCOEX_INFO MODE %d, internalTxRate : %x, nonErpInternalTxRate: %x\n", - priv->mode, - arg.internalTxRate, - arg.nonErpInternalTxRate); - - ret = wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, - &arg, sizeof(arg)); - - return ret; -} - -void cw1200_bss_info_changed(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct cw1200_common *priv = dev->priv; - bool do_join = false; - - mutex_lock(&priv->conf_mutex); - - pr_debug("BSS CHANGED: %08x\n", changed); - - /* TODO: BSS_CHANGED_QOS */ - /* TODO: BSS_CHANGED_TXPOWER */ - - if (changed & BSS_CHANGED_ARP_FILTER) { - struct wsm_mib_arp_ipv4_filter filter = {0}; - int i; - - pr_debug("[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", - info->arp_addr_cnt); - - /* Currently only one IP address is supported by firmware. - * In case of more IPs arp filtering will be disabled. - */ - if (info->arp_addr_cnt > 0 && - info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { - for (i = 0; i < info->arp_addr_cnt; i++) { - filter.ipv4addrs[i] = info->arp_addr_list[i]; - pr_debug("[STA] addr[%d]: 0x%X\n", - i, filter.ipv4addrs[i]); - } - filter.enable = __cpu_to_le32(1); - } - - pr_debug("[STA] arp ip filter enable: %d\n", - __le32_to_cpu(filter.enable)); - - wsm_set_arp_ipv4_filter(priv, &filter); - } - - if (changed & - (BSS_CHANGED_BEACON | - BSS_CHANGED_AP_PROBE_RESP | - BSS_CHANGED_BSSID | - BSS_CHANGED_SSID | - BSS_CHANGED_IBSS)) { - pr_debug("BSS_CHANGED_BEACON\n"); - priv->beacon_int = info->beacon_int; - cw1200_update_beaconing(priv); - cw1200_upload_beacon(priv); - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) { - pr_debug("BSS_CHANGED_BEACON_ENABLED (%d)\n", info->enable_beacon); - - if (priv->enable_beacon != info->enable_beacon) { - cw1200_enable_beaconing(priv, info->enable_beacon); - priv->enable_beacon = info->enable_beacon; - } - } - - if (changed & BSS_CHANGED_BEACON_INT) { - pr_debug("CHANGED_BEACON_INT\n"); - if (info->ibss_joined) - do_join = true; - else if (priv->join_status == CW1200_JOIN_STATUS_AP) - cw1200_update_beaconing(priv); - } - - /* assoc/disassoc, or maybe AID changed */ - if (changed & BSS_CHANGED_ASSOC) { - wsm_lock_tx(priv); - priv->wep_default_key_id = -1; - wsm_unlock_tx(priv); - } - - if (changed & BSS_CHANGED_BSSID) { - pr_debug("BSS_CHANGED_BSSID\n"); - do_join = true; - } - - if (changed & - (BSS_CHANGED_ASSOC | - BSS_CHANGED_BSSID | - BSS_CHANGED_IBSS | - BSS_CHANGED_BASIC_RATES | - BSS_CHANGED_HT)) { - pr_debug("BSS_CHANGED_ASSOC\n"); - if (info->assoc) { - if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) { - ieee80211_connection_loss(vif); - mutex_unlock(&priv->conf_mutex); - return; - } else if (priv->join_status == CW1200_JOIN_STATUS_PRE_STA) { - priv->join_status = CW1200_JOIN_STATUS_STA; - } - } else { - do_join = true; - } - - if (info->assoc || info->ibss_joined) { - struct ieee80211_sta *sta = NULL; - __le32 htprot = 0; - - if (info->dtim_period) - priv->join_dtim_period = info->dtim_period; - priv->beacon_int = info->beacon_int; - - rcu_read_lock(); - - if (info->bssid && !info->ibss_joined) - sta = ieee80211_find_sta(vif, info->bssid); - if (sta) { - priv->ht_info.ht_cap = sta->ht_cap; - priv->bss_params.operational_rate_set = - cw1200_rate_mask_to_wsm(priv, - sta->supp_rates[priv->channel->band]); - priv->ht_info.channel_type = cfg80211_get_chandef_type(&dev->conf.chandef); - priv->ht_info.operation_mode = info->ht_operation_mode; - } else { - memset(&priv->ht_info, 0, - sizeof(priv->ht_info)); - priv->bss_params.operational_rate_set = -1; - } - rcu_read_unlock(); - - /* Non Greenfield stations present */ - if (priv->ht_info.operation_mode & - IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) - htprot |= cpu_to_le32(WSM_NON_GREENFIELD_STA_PRESENT); - - /* Set HT protection method */ - htprot |= cpu_to_le32((priv->ht_info.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION) << 2); - - /* TODO: - * STBC_param.dual_cts - * STBC_param.LSIG_TXOP_FILL - */ - - wsm_write_mib(priv, WSM_MIB_ID_SET_HT_PROTECTION, - &htprot, sizeof(htprot)); - - priv->association_mode.greenfield = - cw1200_ht_greenfield(&priv->ht_info); - priv->association_mode.flags = - WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES | - WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE | - WSM_ASSOCIATION_MODE_USE_HT_MODE | - WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET | - WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING; - priv->association_mode.preamble = - info->use_short_preamble ? - WSM_JOIN_PREAMBLE_SHORT : - WSM_JOIN_PREAMBLE_LONG; - priv->association_mode.basic_rate_set = __cpu_to_le32( - cw1200_rate_mask_to_wsm(priv, - info->basic_rates)); - priv->association_mode.mpdu_start_spacing = - cw1200_ht_ampdu_density(&priv->ht_info); - - cw1200_cqm_bssloss_sm(priv, 0, 0, 0); - cancel_work_sync(&priv->unjoin_work); - - priv->bss_params.beacon_lost_count = priv->cqm_beacon_loss_count; - priv->bss_params.aid = info->aid; - - if (priv->join_dtim_period < 1) - priv->join_dtim_period = 1; - - pr_debug("[STA] DTIM %d, interval: %d\n", - priv->join_dtim_period, priv->beacon_int); - pr_debug("[STA] Preamble: %d, Greenfield: %d, Aid: %d, Rates: 0x%.8X, Basic: 0x%.8X\n", - priv->association_mode.preamble, - priv->association_mode.greenfield, - priv->bss_params.aid, - priv->bss_params.operational_rate_set, - priv->association_mode.basic_rate_set); - wsm_set_association_mode(priv, &priv->association_mode); - - if (!info->ibss_joined) { - wsm_keep_alive_period(priv, 30 /* sec */); - wsm_set_bss_params(priv, &priv->bss_params); - priv->setbssparams_done = true; - cw1200_set_beacon_wakeup_period_work(&priv->set_beacon_wakeup_period_work); - cw1200_set_pm(priv, &priv->powersave_mode); - } - if (priv->vif->p2p) { - pr_debug("[STA] Setting p2p powersave configuration.\n"); - wsm_set_p2p_ps_modeinfo(priv, - &priv->p2p_ps_modeinfo); - } - if (priv->bt_present) - cw1200_set_btcoexinfo(priv); - } else { - memset(&priv->association_mode, 0, - sizeof(priv->association_mode)); - memset(&priv->bss_params, 0, sizeof(priv->bss_params)); - } - } - - /* ERP Protection */ - if (changed & (BSS_CHANGED_ASSOC | - BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_ERP_PREAMBLE)) { - u32 prev_erp_info = priv->erp_info; - if (info->use_cts_prot) - priv->erp_info |= WLAN_ERP_USE_PROTECTION; - else if (!(prev_erp_info & WLAN_ERP_NON_ERP_PRESENT)) - priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; - - if (info->use_short_preamble) - priv->erp_info |= WLAN_ERP_BARKER_PREAMBLE; - else - priv->erp_info &= ~WLAN_ERP_BARKER_PREAMBLE; - - pr_debug("[STA] ERP Protection: %x\n", priv->erp_info); - - if (prev_erp_info != priv->erp_info) - queue_work(priv->workqueue, &priv->set_cts_work); - } - - /* ERP Slottime */ - if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_SLOT)) { - __le32 slot_time = info->use_short_slot ? - __cpu_to_le32(9) : __cpu_to_le32(20); - pr_debug("[STA] Slot time: %d us.\n", - __le32_to_cpu(slot_time)); - wsm_write_mib(priv, WSM_MIB_ID_DOT11_SLOT_TIME, - &slot_time, sizeof(slot_time)); - } - - if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_CQM)) { - struct wsm_rcpi_rssi_threshold threshold = { - .rollingAverageCount = 8, - }; - pr_debug("[CQM] RSSI threshold subscribe: %d +- %d\n", - info->cqm_rssi_thold, info->cqm_rssi_hyst); - priv->cqm_rssi_thold = info->cqm_rssi_thold; - priv->cqm_rssi_hyst = info->cqm_rssi_hyst; - - if (info->cqm_rssi_thold || info->cqm_rssi_hyst) { - /* RSSI subscription enabled */ - /* TODO: It's not a correct way of setting threshold. - * Upper and lower must be set equal here and adjusted - * in callback. However current implementation is much - * more relaible and stable. - */ - - /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 - * RSSI = RCPI / 2 - 110 - */ - if (priv->cqm_use_rssi) { - threshold.upperThreshold = - info->cqm_rssi_thold + info->cqm_rssi_hyst; - threshold.lowerThreshold = - info->cqm_rssi_thold; - threshold.rssiRcpiMode |= WSM_RCPI_RSSI_USE_RSSI; - } else { - threshold.upperThreshold = (info->cqm_rssi_thold + info->cqm_rssi_hyst + 110) * 2; - threshold.lowerThreshold = (info->cqm_rssi_thold + 110) * 2; - } - threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE; - } else { - /* There is a bug in FW, see sta.c. We have to enable - * dummy subscription to get correct RSSI values. - */ - threshold.rssiRcpiMode |= - WSM_RCPI_RSSI_THRESHOLD_ENABLE | - WSM_RCPI_RSSI_DONT_USE_UPPER | - WSM_RCPI_RSSI_DONT_USE_LOWER; - if (priv->cqm_use_rssi) - threshold.rssiRcpiMode |= WSM_RCPI_RSSI_USE_RSSI; - } - wsm_set_rcpi_rssi_threshold(priv, &threshold); - } - mutex_unlock(&priv->conf_mutex); - - if (do_join) { - wsm_lock_tx(priv); - cw1200_do_join(priv); /* Will unlock it for us */ - } -} - -void cw1200_multicast_start_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, multicast_start_work); - long tmo = priv->join_dtim_period * - (priv->beacon_int + 20) * HZ / 1024; - - cancel_work_sync(&priv->multicast_stop_work); - - if (!priv->aid0_bit_set) { - wsm_lock_tx(priv); - cw1200_set_tim_impl(priv, true); - priv->aid0_bit_set = true; - mod_timer(&priv->mcast_timeout, jiffies + tmo); - wsm_unlock_tx(priv); - } -} - -void cw1200_multicast_stop_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, multicast_stop_work); - - if (priv->aid0_bit_set) { - del_timer_sync(&priv->mcast_timeout); - wsm_lock_tx(priv); - priv->aid0_bit_set = false; - cw1200_set_tim_impl(priv, false); - wsm_unlock_tx(priv); - } -} - -void cw1200_mcast_timeout(unsigned long arg) -{ - struct cw1200_common *priv = - (struct cw1200_common *)arg; - - wiphy_warn(priv->hw->wiphy, - "Multicast delivery timeout.\n"); - spin_lock_bh(&priv->ps_state_lock); - priv->tx_multicast = priv->aid0_bit_set && - priv->buffered_multicasts; - if (priv->tx_multicast) - cw1200_bh_wakeup(priv); - spin_unlock_bh(&priv->ps_state_lock); -} - -int cw1200_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu) -{ - /* Aggregation is implemented fully in firmware, - * including block ack negotiation. Do not allow - * mac80211 stack to do anything: it interferes with - * the firmware. - */ - - /* Note that we still need this function stubbed. */ - return -ENOTSUPP; -} - -/* ******************************************************************** */ -/* WSM callback */ -void cw1200_suspend_resume(struct cw1200_common *priv, - struct wsm_suspend_resume *arg) -{ - pr_debug("[AP] %s: %s\n", - arg->stop ? "stop" : "start", - arg->multicast ? "broadcast" : "unicast"); - - if (arg->multicast) { - bool cancel_tmo = false; - spin_lock_bh(&priv->ps_state_lock); - if (arg->stop) { - priv->tx_multicast = false; - } else { - /* Firmware sends this indication every DTIM if there - * is a STA in powersave connected. There is no reason - * to suspend, following wakeup will consume much more - * power than it could be saved. - */ - cw1200_pm_stay_awake(&priv->pm_state, - priv->join_dtim_period * - (priv->beacon_int + 20) * HZ / 1024); - priv->tx_multicast = (priv->aid0_bit_set && - priv->buffered_multicasts); - if (priv->tx_multicast) { - cancel_tmo = true; - cw1200_bh_wakeup(priv); - } - } - spin_unlock_bh(&priv->ps_state_lock); - if (cancel_tmo) - del_timer_sync(&priv->mcast_timeout); - } else { - spin_lock_bh(&priv->ps_state_lock); - cw1200_ps_notify(priv, arg->link_id, arg->stop); - spin_unlock_bh(&priv->ps_state_lock); - if (!arg->stop) - cw1200_bh_wakeup(priv); - } - return; -} - -/* ******************************************************************** */ -/* AP privates */ - -static int cw1200_upload_beacon(struct cw1200_common *priv) -{ - int ret = 0; - struct ieee80211_mgmt *mgmt; - struct wsm_template_frame frame = { - .frame_type = WSM_FRAME_TYPE_BEACON, - }; - - u16 tim_offset; - u16 tim_len; - - if (priv->mode == NL80211_IFTYPE_STATION || - priv->mode == NL80211_IFTYPE_MONITOR || - priv->mode == NL80211_IFTYPE_UNSPECIFIED) - goto done; - - if (priv->vif->p2p) - frame.rate = WSM_TRANSMIT_RATE_6; - - frame.skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, - &tim_offset, &tim_len); - if (!frame.skb) - return -ENOMEM; - - ret = wsm_set_template_frame(priv, &frame); - - if (ret) - goto done; - - /* TODO: Distill probe resp; remove TIM - * and any other beacon-specific IEs - */ - mgmt = (void *)frame.skb->data; - mgmt->frame_control = - __cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - - frame.frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE; - if (priv->vif->p2p) { - ret = wsm_set_probe_responder(priv, true); - } else { - ret = wsm_set_template_frame(priv, &frame); - wsm_set_probe_responder(priv, false); - } - -done: - dev_kfree_skb(frame.skb); - - return ret; -} - -static int cw1200_upload_pspoll(struct cw1200_common *priv) -{ - int ret = 0; - struct wsm_template_frame frame = { - .frame_type = WSM_FRAME_TYPE_PS_POLL, - .rate = 0xFF, - }; - - - frame.skb = ieee80211_pspoll_get(priv->hw, priv->vif); - if (!frame.skb) - return -ENOMEM; - - ret = wsm_set_template_frame(priv, &frame); - - dev_kfree_skb(frame.skb); - - return ret; -} - -static int cw1200_upload_null(struct cw1200_common *priv) -{ - int ret = 0; - struct wsm_template_frame frame = { - .frame_type = WSM_FRAME_TYPE_NULL, - .rate = 0xFF, - }; - - frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif); - if (!frame.skb) - return -ENOMEM; - - ret = wsm_set_template_frame(priv, &frame); - - dev_kfree_skb(frame.skb); - - return ret; -} - -static int cw1200_upload_qosnull(struct cw1200_common *priv) -{ - /* TODO: This needs to be implemented - - struct wsm_template_frame frame = { - .frame_type = WSM_FRAME_TYPE_QOS_NULL, - .rate = 0xFF, - }; - - frame.skb = ieee80211_qosnullfunc_get(priv->hw, priv->vif); - if (!frame.skb) - return -ENOMEM; - - ret = wsm_set_template_frame(priv, &frame); - - dev_kfree_skb(frame.skb); - - */ - return 0; -} - -static int cw1200_enable_beaconing(struct cw1200_common *priv, - bool enable) -{ - struct wsm_beacon_transmit transmit = { - .enable_beaconing = enable, - }; - - return wsm_beacon_transmit(priv, &transmit); -} - -static int cw1200_start_ap(struct cw1200_common *priv) -{ - int ret; - struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; - struct wsm_start start = { - .mode = priv->vif->p2p ? - WSM_START_MODE_P2P_GO : WSM_START_MODE_AP, - .band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? - WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, - .channel_number = priv->channel->hw_value, - .beacon_interval = conf->beacon_int, - .dtim_period = conf->dtim_period, - .preamble = conf->use_short_preamble ? - WSM_JOIN_PREAMBLE_SHORT : - WSM_JOIN_PREAMBLE_LONG, - .probe_delay = 100, - .basic_rate_set = cw1200_rate_mask_to_wsm(priv, - conf->basic_rates), - }; - struct wsm_operational_mode mode = { - .power_mode = cw1200_power_mode, - .disable_more_flag_usage = true, - }; - - memset(start.ssid, 0, sizeof(start.ssid)); - if (!conf->hidden_ssid) { - start.ssid_len = conf->ssid_len; - memcpy(start.ssid, conf->ssid, start.ssid_len); - } - - priv->beacon_int = conf->beacon_int; - priv->join_dtim_period = conf->dtim_period; - - memset(&priv->link_id_db, 0, sizeof(priv->link_id_db)); - - pr_debug("[AP] ch: %d(%d), bcn: %d(%d), brt: 0x%.8X, ssid: %.*s.\n", - start.channel_number, start.band, - start.beacon_interval, start.dtim_period, - start.basic_rate_set, - start.ssid_len, start.ssid); - ret = wsm_start(priv, &start); - if (!ret) - ret = cw1200_upload_keys(priv); - if (!ret && priv->vif->p2p) { - pr_debug("[AP] Setting p2p powersave configuration.\n"); - wsm_set_p2p_ps_modeinfo(priv, &priv->p2p_ps_modeinfo); - } - if (!ret) { - wsm_set_block_ack_policy(priv, 0, 0); - priv->join_status = CW1200_JOIN_STATUS_AP; - cw1200_update_filtering(priv); - } - wsm_set_operational_mode(priv, &mode); - return ret; -} - -static int cw1200_update_beaconing(struct cw1200_common *priv) -{ - struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; - struct wsm_reset reset = { - .link_id = 0, - .reset_statistics = true, - }; - - if (priv->mode == NL80211_IFTYPE_AP) { - /* TODO: check if changed channel, band */ - if (priv->join_status != CW1200_JOIN_STATUS_AP || - priv->beacon_int != conf->beacon_int) { - pr_debug("ap restarting\n"); - wsm_lock_tx(priv); - if (priv->join_status != CW1200_JOIN_STATUS_PASSIVE) - wsm_reset(priv, &reset); - priv->join_status = CW1200_JOIN_STATUS_PASSIVE; - cw1200_start_ap(priv); - wsm_unlock_tx(priv); - } else - pr_debug("ap started join_status: %d\n", - priv->join_status); - } - return 0; -} diff --git a/drivers/net/wireless/cw1200/sta.h b/drivers/net/wireless/cw1200/sta.h deleted file mode 100644 index bebb337..0000000 --- a/drivers/net/wireless/cw1200/sta.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Mac80211 STA interface for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef STA_H_INCLUDED -#define STA_H_INCLUDED - -/* ******************************************************************** */ -/* mac80211 API */ - -int cw1200_start(struct ieee80211_hw *dev); -void cw1200_stop(struct ieee80211_hw *dev); -int cw1200_add_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif); -void cw1200_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif); -int cw1200_change_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - enum nl80211_iftype new_type, - bool p2p); -int cw1200_config(struct ieee80211_hw *dev, u32 changed); -void cw1200_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast); -int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); -int cw1200_get_stats(struct ieee80211_hw *dev, - struct ieee80211_low_level_stats *stats); -int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); - -int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value); - -void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop); - -u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list); - -int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg); - -/* ******************************************************************** */ -/* WSM callbacks */ - -void cw1200_join_complete_cb(struct cw1200_common *priv, - struct wsm_join_complete *arg); - -/* ******************************************************************** */ -/* WSM events */ - -void cw1200_free_event_queue(struct cw1200_common *priv); -void cw1200_event_handler(struct work_struct *work); -void cw1200_bss_loss_work(struct work_struct *work); -void cw1200_bss_params_work(struct work_struct *work); -void cw1200_keep_alive_work(struct work_struct *work); -void cw1200_tx_failure_work(struct work_struct *work); - -void __cw1200_cqm_bssloss_sm(struct cw1200_common *priv, int init, int good, - int bad); -static inline void cw1200_cqm_bssloss_sm(struct cw1200_common *priv, - int init, int good, int bad) -{ - spin_lock(&priv->bss_loss_lock); - __cw1200_cqm_bssloss_sm(priv, init, good, bad); - spin_unlock(&priv->bss_loss_lock); -} - -/* ******************************************************************** */ -/* Internal API */ - -int cw1200_setup_mac(struct cw1200_common *priv); -void cw1200_join_timeout(struct work_struct *work); -void cw1200_unjoin_work(struct work_struct *work); -void cw1200_join_complete_work(struct work_struct *work); -void cw1200_wep_key_work(struct work_struct *work); -void cw1200_update_listening(struct cw1200_common *priv, bool enabled); -void cw1200_update_filtering(struct cw1200_common *priv); -void cw1200_update_filtering_work(struct work_struct *work); -void cw1200_set_beacon_wakeup_period_work(struct work_struct *work); -int cw1200_enable_listening(struct cw1200_common *priv); -int cw1200_disable_listening(struct cw1200_common *priv); -int cw1200_set_uapsd_param(struct cw1200_common *priv, - const struct wsm_edca_params *arg); -void cw1200_ba_work(struct work_struct *work); -void cw1200_ba_timer(unsigned long arg); - -/* AP stuffs */ -int cw1200_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, - bool set); -int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int cw1200_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, - struct ieee80211_sta *sta); -void cw1200_bss_info_changed(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed); -int cw1200_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size, bool amsdu); - -void cw1200_suspend_resume(struct cw1200_common *priv, - struct wsm_suspend_resume *arg); -void cw1200_set_tim_work(struct work_struct *work); -void cw1200_set_cts_work(struct work_struct *work); -void cw1200_multicast_start_work(struct work_struct *work); -void cw1200_multicast_stop_work(struct work_struct *work); -void cw1200_mcast_timeout(unsigned long arg); - -#endif diff --git a/drivers/net/wireless/cw1200/txrx.c b/drivers/net/wireless/cw1200/txrx.c deleted file mode 100644 index d28bd49..0000000 --- a/drivers/net/wireless/cw1200/txrx.c +++ /dev/null @@ -1,1472 +0,0 @@ -/* - * Datapath implementation for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <net/mac80211.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include "cw1200.h" -#include "wsm.h" -#include "bh.h" -#include "sta.h" -#include "debug.h" - -#define CW1200_INVALID_RATE_ID (0xFF) - -static int cw1200_handle_action_rx(struct cw1200_common *priv, - struct sk_buff *skb); -static const struct ieee80211_rate * -cw1200_get_tx_rate(const struct cw1200_common *priv, - const struct ieee80211_tx_rate *rate); - -/* ******************************************************************** */ -/* TX queue lock / unlock */ - -static inline void cw1200_tx_queues_lock(struct cw1200_common *priv) -{ - int i; - for (i = 0; i < 4; ++i) - cw1200_queue_lock(&priv->tx_queue[i]); -} - -static inline void cw1200_tx_queues_unlock(struct cw1200_common *priv) -{ - int i; - for (i = 0; i < 4; ++i) - cw1200_queue_unlock(&priv->tx_queue[i]); -} - -/* ******************************************************************** */ -/* TX policy cache implementation */ - -static void tx_policy_dump(struct tx_policy *policy) -{ - pr_debug("[TX policy] %.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X %.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X %.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X: %d\n", - policy->raw[0] & 0x0F, policy->raw[0] >> 4, - policy->raw[1] & 0x0F, policy->raw[1] >> 4, - policy->raw[2] & 0x0F, policy->raw[2] >> 4, - policy->raw[3] & 0x0F, policy->raw[3] >> 4, - policy->raw[4] & 0x0F, policy->raw[4] >> 4, - policy->raw[5] & 0x0F, policy->raw[5] >> 4, - policy->raw[6] & 0x0F, policy->raw[6] >> 4, - policy->raw[7] & 0x0F, policy->raw[7] >> 4, - policy->raw[8] & 0x0F, policy->raw[8] >> 4, - policy->raw[9] & 0x0F, policy->raw[9] >> 4, - policy->raw[10] & 0x0F, policy->raw[10] >> 4, - policy->raw[11] & 0x0F, policy->raw[11] >> 4, - policy->defined); -} - -static void tx_policy_build(const struct cw1200_common *priv, - /* [out] */ struct tx_policy *policy, - struct ieee80211_tx_rate *rates, size_t count) -{ - int i, j; - unsigned limit = priv->short_frame_max_tx_count; - unsigned total = 0; - BUG_ON(rates[0].idx < 0); - memset(policy, 0, sizeof(*policy)); - - /* Sort rates in descending order. */ - for (i = 1; i < count; ++i) { - if (rates[i].idx < 0) { - count = i; - break; - } - if (rates[i].idx > rates[i - 1].idx) { - struct ieee80211_tx_rate tmp = rates[i - 1]; - rates[i - 1] = rates[i]; - rates[i] = tmp; - } - } - - /* Eliminate duplicates. */ - total = rates[0].count; - for (i = 0, j = 1; j < count; ++j) { - if (rates[j].idx == rates[i].idx) { - rates[i].count += rates[j].count; - } else if (rates[j].idx > rates[i].idx) { - break; - } else { - ++i; - if (i != j) - rates[i] = rates[j]; - } - total += rates[j].count; - } - count = i + 1; - - /* Re-fill policy trying to keep every requested rate and with - * respect to the global max tx retransmission count. - */ - if (limit < count) - limit = count; - if (total > limit) { - for (i = 0; i < count; ++i) { - int left = count - i - 1; - if (rates[i].count > limit - left) - rates[i].count = limit - left; - limit -= rates[i].count; - } - } - - /* HACK!!! Device has problems (at least) switching from - * 54Mbps CTS to 1Mbps. This switch takes enormous amount - * of time (100-200 ms), leading to valuable throughput drop. - * As a workaround, additional g-rates are injected to the - * policy. - */ - if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && - rates[0].idx > 4 && rates[0].count > 2 && - rates[1].idx < 2) { - int mid_rate = (rates[0].idx + 4) >> 1; - - /* Decrease number of retries for the initial rate */ - rates[0].count -= 2; - - if (mid_rate != 4) { - /* Keep fallback rate at 1Mbps. */ - rates[3] = rates[1]; - - /* Inject 1 transmission on lowest g-rate */ - rates[2].idx = 4; - rates[2].count = 1; - rates[2].flags = rates[1].flags; - - /* Inject 1 transmission on mid-rate */ - rates[1].idx = mid_rate; - rates[1].count = 1; - - /* Fallback to 1 Mbps is a really bad thing, - * so let's try to increase probability of - * successful transmission on the lowest g rate - * even more - */ - if (rates[0].count >= 3) { - --rates[0].count; - ++rates[2].count; - } - - /* Adjust amount of rates defined */ - count += 2; - } else { - /* Keep fallback rate at 1Mbps. */ - rates[2] = rates[1]; - - /* Inject 2 transmissions on lowest g-rate */ - rates[1].idx = 4; - rates[1].count = 2; - - /* Adjust amount of rates defined */ - count += 1; - } - } - - policy->defined = cw1200_get_tx_rate(priv, &rates[0])->hw_value + 1; - - for (i = 0; i < count; ++i) { - register unsigned rateid, off, shift, retries; - - rateid = cw1200_get_tx_rate(priv, &rates[i])->hw_value; - off = rateid >> 3; /* eq. rateid / 8 */ - shift = (rateid & 0x07) << 2; /* eq. (rateid % 8) * 4 */ - - retries = rates[i].count; - if (retries > 0x0F) { - rates[i].count = 0x0f; - retries = 0x0F; - } - policy->tbl[off] |= __cpu_to_le32(retries << shift); - policy->retry_count += retries; - } - - pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d\n", - count, - rates[0].idx, rates[0].count, - rates[1].idx, rates[1].count, - rates[2].idx, rates[2].count, - rates[3].idx, rates[3].count); -} - -static inline bool tx_policy_is_equal(const struct tx_policy *wanted, - const struct tx_policy *cached) -{ - size_t count = wanted->defined >> 1; - if (wanted->defined > cached->defined) - return false; - if (count) { - if (memcmp(wanted->raw, cached->raw, count)) - return false; - } - if (wanted->defined & 1) { - if ((wanted->raw[count] & 0x0F) != (cached->raw[count] & 0x0F)) - return false; - } - return true; -} - -static int tx_policy_find(struct tx_policy_cache *cache, - const struct tx_policy *wanted) -{ - /* O(n) complexity. Not so good, but there's only 8 entries in - * the cache. - * Also lru helps to reduce search time. - */ - struct tx_policy_cache_entry *it; - /* First search for policy in "used" list */ - list_for_each_entry(it, &cache->used, link) { - if (tx_policy_is_equal(wanted, &it->policy)) - return it - cache->cache; - } - /* Then - in "free list" */ - list_for_each_entry(it, &cache->free, link) { - if (tx_policy_is_equal(wanted, &it->policy)) - return it - cache->cache; - } - return -1; -} - -static inline void tx_policy_use(struct tx_policy_cache *cache, - struct tx_policy_cache_entry *entry) -{ - ++entry->policy.usage_count; - list_move(&entry->link, &cache->used); -} - -static inline int tx_policy_release(struct tx_policy_cache *cache, - struct tx_policy_cache_entry *entry) -{ - int ret = --entry->policy.usage_count; - if (!ret) - list_move(&entry->link, &cache->free); - return ret; -} - -void tx_policy_clean(struct cw1200_common *priv) -{ - int idx, locked; - struct tx_policy_cache *cache = &priv->tx_policy_cache; - struct tx_policy_cache_entry *entry; - - cw1200_tx_queues_lock(priv); - spin_lock_bh(&cache->lock); - locked = list_empty(&cache->free); - - for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) { - entry = &cache->cache[idx]; - /* Policy usage count should be 0 at this time as all queues - should be empty - */ - if (WARN_ON(entry->policy.usage_count)) { - entry->policy.usage_count = 0; - list_move(&entry->link, &cache->free); - } - memset(&entry->policy, 0, sizeof(entry->policy)); - } - if (locked) - cw1200_tx_queues_unlock(priv); - - cw1200_tx_queues_unlock(priv); - spin_unlock_bh(&cache->lock); -} - -/* ******************************************************************** */ -/* External TX policy cache API */ - -void tx_policy_init(struct cw1200_common *priv) -{ - struct tx_policy_cache *cache = &priv->tx_policy_cache; - int i; - - memset(cache, 0, sizeof(*cache)); - - spin_lock_init(&cache->lock); - INIT_LIST_HEAD(&cache->used); - INIT_LIST_HEAD(&cache->free); - - for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) - list_add(&cache->cache[i].link, &cache->free); -} - -static int tx_policy_get(struct cw1200_common *priv, - struct ieee80211_tx_rate *rates, - size_t count, bool *renew) -{ - int idx; - struct tx_policy_cache *cache = &priv->tx_policy_cache; - struct tx_policy wanted; - - tx_policy_build(priv, &wanted, rates, count); - - spin_lock_bh(&cache->lock); - if (WARN_ON_ONCE(list_empty(&cache->free))) { - spin_unlock_bh(&cache->lock); - return CW1200_INVALID_RATE_ID; - } - idx = tx_policy_find(cache, &wanted); - if (idx >= 0) { - pr_debug("[TX policy] Used TX policy: %d\n", idx); - *renew = false; - } else { - struct tx_policy_cache_entry *entry; - *renew = true; - /* If policy is not found create a new one - * using the oldest entry in "free" list - */ - entry = list_entry(cache->free.prev, - struct tx_policy_cache_entry, link); - entry->policy = wanted; - idx = entry - cache->cache; - pr_debug("[TX policy] New TX policy: %d\n", idx); - tx_policy_dump(&entry->policy); - } - tx_policy_use(cache, &cache->cache[idx]); - if (list_empty(&cache->free)) { - /* Lock TX queues. */ - cw1200_tx_queues_lock(priv); - } - spin_unlock_bh(&cache->lock); - return idx; -} - -static void tx_policy_put(struct cw1200_common *priv, int idx) -{ - int usage, locked; - struct tx_policy_cache *cache = &priv->tx_policy_cache; - - spin_lock_bh(&cache->lock); - locked = list_empty(&cache->free); - usage = tx_policy_release(cache, &cache->cache[idx]); - if (locked && !usage) { - /* Unlock TX queues. */ - cw1200_tx_queues_unlock(priv); - } - spin_unlock_bh(&cache->lock); -} - -static int tx_policy_upload(struct cw1200_common *priv) -{ - struct tx_policy_cache *cache = &priv->tx_policy_cache; - int i; - struct wsm_set_tx_rate_retry_policy arg = { - .num = 0, - }; - spin_lock_bh(&cache->lock); - - /* Upload only modified entries. */ - for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) { - struct tx_policy *src = &cache->cache[i].policy; - if (src->retry_count && !src->uploaded) { - struct wsm_tx_rate_retry_policy *dst = - &arg.tbl[arg.num]; - dst->index = i; - dst->short_retries = priv->short_frame_max_tx_count; - dst->long_retries = priv->long_frame_max_tx_count; - - dst->flags = WSM_TX_RATE_POLICY_FLAG_TERMINATE_WHEN_FINISHED | - WSM_TX_RATE_POLICY_FLAG_COUNT_INITIAL_TRANSMIT; - memcpy(dst->rate_count_indices, src->tbl, - sizeof(dst->rate_count_indices)); - src->uploaded = 1; - ++arg.num; - } - } - spin_unlock_bh(&cache->lock); - cw1200_debug_tx_cache_miss(priv); - pr_debug("[TX policy] Upload %d policies\n", arg.num); - return wsm_set_tx_rate_retry_policy(priv, &arg); -} - -void tx_policy_upload_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, tx_policy_upload_work); - - pr_debug("[TX] TX policy upload.\n"); - tx_policy_upload(priv); - - wsm_unlock_tx(priv); - cw1200_tx_queues_unlock(priv); -} - -/* ******************************************************************** */ -/* cw1200 TX implementation */ - -struct cw1200_txinfo { - struct sk_buff *skb; - unsigned queue; - struct ieee80211_tx_info *tx_info; - const struct ieee80211_rate *rate; - struct ieee80211_hdr *hdr; - size_t hdrlen; - const u8 *da; - struct cw1200_sta_priv *sta_priv; - struct ieee80211_sta *sta; - struct cw1200_txpriv txpriv; -}; - -u32 cw1200_rate_mask_to_wsm(struct cw1200_common *priv, u32 rates) -{ - u32 ret = 0; - int i; - for (i = 0; i < 32; ++i) { - if (rates & BIT(i)) - ret |= BIT(priv->rates[i].hw_value); - } - return ret; -} - -static const struct ieee80211_rate * -cw1200_get_tx_rate(const struct cw1200_common *priv, - const struct ieee80211_tx_rate *rate) -{ - if (rate->idx < 0) - return NULL; - if (rate->flags & IEEE80211_TX_RC_MCS) - return &priv->mcs_rates[rate->idx]; - return &priv->hw->wiphy->bands[priv->channel->band]-> - bitrates[rate->idx]; -} - -static int -cw1200_tx_h_calc_link_ids(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - if (t->sta && t->sta_priv->link_id) - t->txpriv.raw_link_id = - t->txpriv.link_id = - t->sta_priv->link_id; - else if (priv->mode != NL80211_IFTYPE_AP) - t->txpriv.raw_link_id = - t->txpriv.link_id = 0; - else if (is_multicast_ether_addr(t->da)) { - if (priv->enable_beacon) { - t->txpriv.raw_link_id = 0; - t->txpriv.link_id = CW1200_LINK_ID_AFTER_DTIM; - } else { - t->txpriv.raw_link_id = 0; - t->txpriv.link_id = 0; - } - } else { - t->txpriv.link_id = cw1200_find_link_id(priv, t->da); - if (!t->txpriv.link_id) - t->txpriv.link_id = cw1200_alloc_link_id(priv, t->da); - if (!t->txpriv.link_id) { - wiphy_err(priv->hw->wiphy, - "No more link IDs available.\n"); - return -ENOENT; - } - t->txpriv.raw_link_id = t->txpriv.link_id; - } - if (t->txpriv.raw_link_id) - priv->link_id_db[t->txpriv.raw_link_id - 1].timestamp = - jiffies; - if (t->sta && (t->sta->uapsd_queues & BIT(t->queue))) - t->txpriv.link_id = CW1200_LINK_ID_UAPSD; - return 0; -} - -static void -cw1200_tx_h_pm(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - if (ieee80211_is_auth(t->hdr->frame_control)) { - u32 mask = ~BIT(t->txpriv.raw_link_id); - spin_lock_bh(&priv->ps_state_lock); - priv->sta_asleep_mask &= mask; - priv->pspoll_mask &= mask; - spin_unlock_bh(&priv->ps_state_lock); - } -} - -static void -cw1200_tx_h_calc_tid(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - if (ieee80211_is_data_qos(t->hdr->frame_control)) { - u8 *qos = ieee80211_get_qos_ctl(t->hdr); - t->txpriv.tid = qos[0] & IEEE80211_QOS_CTL_TID_MASK; - } else if (ieee80211_is_data(t->hdr->frame_control)) { - t->txpriv.tid = 0; - } -} - -static int -cw1200_tx_h_crypt(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - if (!t->tx_info->control.hw_key || - !ieee80211_has_protected(t->hdr->frame_control)) - return 0; - - t->hdrlen += t->tx_info->control.hw_key->iv_len; - skb_put(t->skb, t->tx_info->control.hw_key->icv_len); - - if (t->tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) - skb_put(t->skb, 8); /* MIC space */ - - return 0; -} - -static int -cw1200_tx_h_align(struct cw1200_common *priv, - struct cw1200_txinfo *t, - u8 *flags) -{ - size_t offset = (size_t)t->skb->data & 3; - - if (!offset) - return 0; - - if (offset & 1) { - wiphy_err(priv->hw->wiphy, - "Bug: attempt to transmit a frame with wrong alignment: %zu\n", - offset); - return -EINVAL; - } - - if (skb_headroom(t->skb) < offset) { - wiphy_err(priv->hw->wiphy, - "Bug: no space allocated for DMA alignment. headroom: %d\n", - skb_headroom(t->skb)); - return -ENOMEM; - } - skb_push(t->skb, offset); - t->hdrlen += offset; - t->txpriv.offset += offset; - *flags |= WSM_TX_2BYTES_SHIFT; - cw1200_debug_tx_align(priv); - return 0; -} - -static int -cw1200_tx_h_action(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - struct ieee80211_mgmt *mgmt = - (struct ieee80211_mgmt *)t->hdr; - if (ieee80211_is_action(t->hdr->frame_control) && - mgmt->u.action.category == WLAN_CATEGORY_BACK) - return 1; - else - return 0; -} - -/* Add WSM header */ -static struct wsm_tx * -cw1200_tx_h_wsm(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - struct wsm_tx *wsm; - - if (skb_headroom(t->skb) < sizeof(struct wsm_tx)) { - wiphy_err(priv->hw->wiphy, - "Bug: no space allocated for WSM header. headroom: %d\n", - skb_headroom(t->skb)); - return NULL; - } - - wsm = (struct wsm_tx *)skb_push(t->skb, sizeof(struct wsm_tx)); - t->txpriv.offset += sizeof(struct wsm_tx); - memset(wsm, 0, sizeof(*wsm)); - wsm->hdr.len = __cpu_to_le16(t->skb->len); - wsm->hdr.id = __cpu_to_le16(0x0004); - wsm->queue_id = wsm_queue_id_to_wsm(t->queue); - return wsm; -} - -/* BT Coex specific handling */ -static void -cw1200_tx_h_bt(struct cw1200_common *priv, - struct cw1200_txinfo *t, - struct wsm_tx *wsm) -{ - u8 priority = 0; - - if (!priv->bt_present) - return; - - if (ieee80211_is_nullfunc(t->hdr->frame_control)) { - priority = WSM_EPTA_PRIORITY_MGT; - } else if (ieee80211_is_data(t->hdr->frame_control)) { - /* Skip LLC SNAP header (+6) */ - u8 *payload = &t->skb->data[t->hdrlen]; - __be16 *ethertype = (__be16 *)&payload[6]; - if (be16_to_cpu(*ethertype) == ETH_P_PAE) - priority = WSM_EPTA_PRIORITY_EAPOL; - } else if (ieee80211_is_assoc_req(t->hdr->frame_control) || - ieee80211_is_reassoc_req(t->hdr->frame_control)) { - struct ieee80211_mgmt *mgt_frame = - (struct ieee80211_mgmt *)t->hdr; - - if (le16_to_cpu(mgt_frame->u.assoc_req.listen_interval) < - priv->listen_interval) { - pr_debug("Modified Listen Interval to %d from %d\n", - priv->listen_interval, - mgt_frame->u.assoc_req.listen_interval); - /* Replace listen interval derieved from - * the one read from SDD - */ - mgt_frame->u.assoc_req.listen_interval = cpu_to_le16(priv->listen_interval); - } - } - - if (!priority) { - if (ieee80211_is_action(t->hdr->frame_control)) - priority = WSM_EPTA_PRIORITY_ACTION; - else if (ieee80211_is_mgmt(t->hdr->frame_control)) - priority = WSM_EPTA_PRIORITY_MGT; - else if ((wsm->queue_id == WSM_QUEUE_VOICE)) - priority = WSM_EPTA_PRIORITY_VOICE; - else if ((wsm->queue_id == WSM_QUEUE_VIDEO)) - priority = WSM_EPTA_PRIORITY_VIDEO; - else - priority = WSM_EPTA_PRIORITY_DATA; - } - - pr_debug("[TX] EPTA priority %d.\n", priority); - - wsm->flags |= priority << 1; -} - -static int -cw1200_tx_h_rate_policy(struct cw1200_common *priv, - struct cw1200_txinfo *t, - struct wsm_tx *wsm) -{ - bool tx_policy_renew = false; - - t->txpriv.rate_id = tx_policy_get(priv, - t->tx_info->control.rates, IEEE80211_TX_MAX_RATES, - &tx_policy_renew); - if (t->txpriv.rate_id == CW1200_INVALID_RATE_ID) - return -EFAULT; - - wsm->flags |= t->txpriv.rate_id << 4; - - t->rate = cw1200_get_tx_rate(priv, - &t->tx_info->control.rates[0]), - wsm->max_tx_rate = t->rate->hw_value; - if (t->rate->flags & IEEE80211_TX_RC_MCS) { - if (cw1200_ht_greenfield(&priv->ht_info)) - wsm->ht_tx_parameters |= - __cpu_to_le32(WSM_HT_TX_GREENFIELD); - else - wsm->ht_tx_parameters |= - __cpu_to_le32(WSM_HT_TX_MIXED); - } - - if (tx_policy_renew) { - pr_debug("[TX] TX policy renew.\n"); - /* It's not so optimal to stop TX queues every now and then. - * Better to reimplement task scheduling with - * a counter. TODO. - */ - wsm_lock_tx_async(priv); - cw1200_tx_queues_lock(priv); - if (queue_work(priv->workqueue, - &priv->tx_policy_upload_work) <= 0) { - cw1200_tx_queues_unlock(priv); - wsm_unlock_tx(priv); - } - } - return 0; -} - -static bool -cw1200_tx_h_pm_state(struct cw1200_common *priv, - struct cw1200_txinfo *t) -{ - int was_buffered = 1; - - if (t->txpriv.link_id == CW1200_LINK_ID_AFTER_DTIM && - !priv->buffered_multicasts) { - priv->buffered_multicasts = true; - if (priv->sta_asleep_mask) - queue_work(priv->workqueue, - &priv->multicast_start_work); - } - - if (t->txpriv.raw_link_id && t->txpriv.tid < CW1200_MAX_TID) - was_buffered = priv->link_id_db[t->txpriv.raw_link_id - 1].buffered[t->txpriv.tid]++; - - return !was_buffered; -} - -/* ******************************************************************** */ - -void cw1200_tx(struct ieee80211_hw *dev, - struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct cw1200_common *priv = dev->priv; - struct cw1200_txinfo t = { - .skb = skb, - .queue = skb_get_queue_mapping(skb), - .tx_info = IEEE80211_SKB_CB(skb), - .hdr = (struct ieee80211_hdr *)skb->data, - .txpriv.tid = CW1200_MAX_TID, - .txpriv.rate_id = CW1200_INVALID_RATE_ID, - }; - struct ieee80211_sta *sta; - struct wsm_tx *wsm; - bool tid_update = 0; - u8 flags = 0; - int ret; - - if (priv->bh_error) - goto drop; - - t.hdrlen = ieee80211_hdrlen(t.hdr->frame_control); - t.da = ieee80211_get_DA(t.hdr); - if (control) { - t.sta = control->sta; - t.sta_priv = (struct cw1200_sta_priv *)&t.sta->drv_priv; - } - - if (WARN_ON(t.queue >= 4)) - goto drop; - - ret = cw1200_tx_h_calc_link_ids(priv, &t); - if (ret) - goto drop; - - pr_debug("[TX] TX %d bytes (queue: %d, link_id: %d (%d)).\n", - skb->len, t.queue, t.txpriv.link_id, - t.txpriv.raw_link_id); - - cw1200_tx_h_pm(priv, &t); - cw1200_tx_h_calc_tid(priv, &t); - ret = cw1200_tx_h_crypt(priv, &t); - if (ret) - goto drop; - ret = cw1200_tx_h_align(priv, &t, &flags); - if (ret) - goto drop; - ret = cw1200_tx_h_action(priv, &t); - if (ret) - goto drop; - wsm = cw1200_tx_h_wsm(priv, &t); - if (!wsm) { - ret = -ENOMEM; - goto drop; - } - wsm->flags |= flags; - cw1200_tx_h_bt(priv, &t, wsm); - ret = cw1200_tx_h_rate_policy(priv, &t, wsm); - if (ret) - goto drop; - - rcu_read_lock(); - sta = rcu_dereference(t.sta); - - spin_lock_bh(&priv->ps_state_lock); - { - tid_update = cw1200_tx_h_pm_state(priv, &t); - BUG_ON(cw1200_queue_put(&priv->tx_queue[t.queue], - t.skb, &t.txpriv)); - } - spin_unlock_bh(&priv->ps_state_lock); - - if (tid_update && sta) - ieee80211_sta_set_buffered(sta, t.txpriv.tid, true); - - rcu_read_unlock(); - - cw1200_bh_wakeup(priv); - - return; - -drop: - cw1200_skb_dtor(priv, skb, &t.txpriv); - return; -} - -/* ******************************************************************** */ - -static int cw1200_handle_action_rx(struct cw1200_common *priv, - struct sk_buff *skb) -{ - struct ieee80211_mgmt *mgmt = (void *)skb->data; - - /* Filter block ACK negotiation: fully controlled by firmware */ - if (mgmt->u.action.category == WLAN_CATEGORY_BACK) - return 1; - - return 0; -} - -static int cw1200_handle_pspoll(struct cw1200_common *priv, - struct sk_buff *skb) -{ - struct ieee80211_sta *sta; - struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data; - int link_id = 0; - u32 pspoll_mask = 0; - int drop = 1; - int i; - - if (priv->join_status != CW1200_JOIN_STATUS_AP) - goto done; - if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) - goto done; - - rcu_read_lock(); - sta = ieee80211_find_sta(priv->vif, pspoll->ta); - if (sta) { - struct cw1200_sta_priv *sta_priv; - sta_priv = (struct cw1200_sta_priv *)&sta->drv_priv; - link_id = sta_priv->link_id; - pspoll_mask = BIT(sta_priv->link_id); - } - rcu_read_unlock(); - if (!link_id) - goto done; - - priv->pspoll_mask |= pspoll_mask; - drop = 0; - - /* Do not report pspols if data for given link id is queued already. */ - for (i = 0; i < 4; ++i) { - if (cw1200_queue_get_num_queued(&priv->tx_queue[i], - pspoll_mask)) { - cw1200_bh_wakeup(priv); - drop = 1; - break; - } - } - pr_debug("[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); -done: - return drop; -} - -/* ******************************************************************** */ - -void cw1200_tx_confirm_cb(struct cw1200_common *priv, - int link_id, - struct wsm_tx_confirm *arg) -{ - u8 queue_id = cw1200_queue_get_queue_id(arg->packet_id); - struct cw1200_queue *queue = &priv->tx_queue[queue_id]; - struct sk_buff *skb; - const struct cw1200_txpriv *txpriv; - - pr_debug("[TX] TX confirm: %d, %d.\n", - arg->status, arg->ack_failures); - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { - /* STA is stopped. */ - return; - } - - if (WARN_ON(queue_id >= 4)) - return; - - if (arg->status) - pr_debug("TX failed: %d.\n", arg->status); - - if ((arg->status == WSM_REQUEUE) && - (arg->flags & WSM_TX_STATUS_REQUEUE)) { - /* "Requeue" means "implicit suspend" */ - struct wsm_suspend_resume suspend = { - .link_id = link_id, - .stop = 1, - .multicast = !link_id, - }; - cw1200_suspend_resume(priv, &suspend); - wiphy_warn(priv->hw->wiphy, "Requeue for link_id %d (try %d). STAs asleep: 0x%.8X\n", - link_id, - cw1200_queue_get_generation(arg->packet_id) + 1, - priv->sta_asleep_mask); - cw1200_queue_requeue(queue, arg->packet_id); - spin_lock_bh(&priv->ps_state_lock); - if (!link_id) { - priv->buffered_multicasts = true; - if (priv->sta_asleep_mask) { - queue_work(priv->workqueue, - &priv->multicast_start_work); - } - } - spin_unlock_bh(&priv->ps_state_lock); - } else if (!cw1200_queue_get_skb(queue, arg->packet_id, - &skb, &txpriv)) { - struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb); - int tx_count = arg->ack_failures; - u8 ht_flags = 0; - int i; - - if (cw1200_ht_greenfield(&priv->ht_info)) - ht_flags |= IEEE80211_TX_RC_GREEN_FIELD; - - spin_lock(&priv->bss_loss_lock); - if (priv->bss_loss_state && - arg->packet_id == priv->bss_loss_confirm_id) { - if (arg->status) { - /* Recovery failed */ - __cw1200_cqm_bssloss_sm(priv, 0, 0, 1); - } else { - /* Recovery succeeded */ - __cw1200_cqm_bssloss_sm(priv, 0, 1, 0); - } - } - spin_unlock(&priv->bss_loss_lock); - - if (!arg->status) { - tx->flags |= IEEE80211_TX_STAT_ACK; - ++tx_count; - cw1200_debug_txed(priv); - if (arg->flags & WSM_TX_STATUS_AGGREGATION) { - /* Do not report aggregation to mac80211: - * it confuses minstrel a lot. - */ - /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */ - cw1200_debug_txed_agg(priv); - } - } else { - if (tx_count) - ++tx_count; - } - - for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { - if (tx->status.rates[i].count >= tx_count) { - tx->status.rates[i].count = tx_count; - break; - } - tx_count -= tx->status.rates[i].count; - if (tx->status.rates[i].flags & IEEE80211_TX_RC_MCS) - tx->status.rates[i].flags |= ht_flags; - } - - for (++i; i < IEEE80211_TX_MAX_RATES; ++i) { - tx->status.rates[i].count = 0; - tx->status.rates[i].idx = -1; - } - - /* Pull off any crypto trailers that we added on */ - if (tx->control.hw_key) { - skb_trim(skb, skb->len - tx->control.hw_key->icv_len); - if (tx->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) - skb_trim(skb, skb->len - 8); /* MIC space */ - } - cw1200_queue_remove(queue, arg->packet_id); - } - /* XXX TODO: Only wake if there are pending transmits.. */ - cw1200_bh_wakeup(priv); -} - -static void cw1200_notify_buffered_tx(struct cw1200_common *priv, - struct sk_buff *skb, int link_id, int tid) -{ - struct ieee80211_sta *sta; - struct ieee80211_hdr *hdr; - u8 *buffered; - u8 still_buffered = 0; - - if (link_id && tid < CW1200_MAX_TID) { - buffered = priv->link_id_db - [link_id - 1].buffered; - - spin_lock_bh(&priv->ps_state_lock); - if (!WARN_ON(!buffered[tid])) - still_buffered = --buffered[tid]; - spin_unlock_bh(&priv->ps_state_lock); - - if (!still_buffered && tid < CW1200_MAX_TID) { - hdr = (struct ieee80211_hdr *)skb->data; - rcu_read_lock(); - sta = ieee80211_find_sta(priv->vif, hdr->addr1); - if (sta) - ieee80211_sta_set_buffered(sta, tid, false); - rcu_read_unlock(); - } - } -} - -void cw1200_skb_dtor(struct cw1200_common *priv, - struct sk_buff *skb, - const struct cw1200_txpriv *txpriv) -{ - skb_pull(skb, txpriv->offset); - if (txpriv->rate_id != CW1200_INVALID_RATE_ID) { - cw1200_notify_buffered_tx(priv, skb, - txpriv->raw_link_id, txpriv->tid); - tx_policy_put(priv, txpriv->rate_id); - } - ieee80211_tx_status(priv->hw, skb); -} - -void cw1200_rx_cb(struct cw1200_common *priv, - struct wsm_rx *arg, - int link_id, - struct sk_buff **skb_p) -{ - struct sk_buff *skb = *skb_p; - struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - struct cw1200_link_entry *entry = NULL; - unsigned long grace_period; - - bool early_data = false; - bool p2p = priv->vif && priv->vif->p2p; - size_t hdrlen; - hdr->flag = 0; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { - /* STA is stopped. */ - goto drop; - } - - if (link_id && link_id <= CW1200_MAX_STA_IN_AP_MODE) { - entry = &priv->link_id_db[link_id - 1]; - if (entry->status == CW1200_LINK_SOFT && - ieee80211_is_data(frame->frame_control)) - early_data = true; - entry->timestamp = jiffies; - } else if (p2p && - ieee80211_is_action(frame->frame_control) && - (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { - pr_debug("[RX] Going to MAP&RESET link ID\n"); - WARN_ON(work_pending(&priv->linkid_reset_work)); - memcpy(&priv->action_frame_sa[0], - ieee80211_get_SA(frame), ETH_ALEN); - priv->action_linkid = 0; - schedule_work(&priv->linkid_reset_work); - } - - if (link_id && p2p && - ieee80211_is_action(frame->frame_control) && - (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { - /* Link ID already exists for the ACTION frame. - * Reset and Remap - */ - WARN_ON(work_pending(&priv->linkid_reset_work)); - memcpy(&priv->action_frame_sa[0], - ieee80211_get_SA(frame), ETH_ALEN); - priv->action_linkid = link_id; - schedule_work(&priv->linkid_reset_work); - } - if (arg->status) { - if (arg->status == WSM_STATUS_MICFAILURE) { - pr_debug("[RX] MIC failure.\n"); - hdr->flag |= RX_FLAG_MMIC_ERROR; - } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { - pr_debug("[RX] No key found.\n"); - goto drop; - } else { - pr_debug("[RX] Receive failure: %d.\n", - arg->status); - goto drop; - } - } - - if (skb->len < sizeof(struct ieee80211_pspoll)) { - wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed. Size is lesser than IEEE header.\n"); - goto drop; - } - - if (ieee80211_is_pspoll(frame->frame_control)) - if (cw1200_handle_pspoll(priv, skb)) - goto drop; - - hdr->band = ((arg->channel_number & 0xff00) || - (arg->channel_number > 14)) ? - IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; - hdr->freq = ieee80211_channel_to_frequency( - arg->channel_number, - hdr->band); - - if (arg->rx_rate >= 14) { - hdr->flag |= RX_FLAG_HT; - hdr->rate_idx = arg->rx_rate - 14; - } else if (arg->rx_rate >= 4) { - hdr->rate_idx = arg->rx_rate - 2; - } else { - hdr->rate_idx = arg->rx_rate; - } - - hdr->signal = (s8)arg->rcpi_rssi; - hdr->antenna = 0; - - hdrlen = ieee80211_hdrlen(frame->frame_control); - - if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { - size_t iv_len = 0, icv_len = 0; - - hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED; - - /* Oops... There is no fast way to ask mac80211 about - * IV/ICV lengths. Even defineas are not exposed. - */ - switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { - case WSM_RX_STATUS_WEP: - iv_len = 4 /* WEP_IV_LEN */; - icv_len = 4 /* WEP_ICV_LEN */; - break; - case WSM_RX_STATUS_TKIP: - iv_len = 8 /* TKIP_IV_LEN */; - icv_len = 4 /* TKIP_ICV_LEN */ - + 8 /*MICHAEL_MIC_LEN*/; - hdr->flag |= RX_FLAG_MMIC_STRIPPED; - break; - case WSM_RX_STATUS_AES: - iv_len = 8 /* CCMP_HDR_LEN */; - icv_len = 8 /* CCMP_MIC_LEN */; - break; - case WSM_RX_STATUS_WAPI: - iv_len = 18 /* WAPI_HDR_LEN */; - icv_len = 16 /* WAPI_MIC_LEN */; - break; - default: - pr_warn("Unknown encryption type %d\n", - WSM_RX_STATUS_ENCRYPTION(arg->flags)); - goto drop; - } - - /* Firmware strips ICV in case of MIC failure. */ - if (arg->status == WSM_STATUS_MICFAILURE) - icv_len = 0; - - if (skb->len < hdrlen + iv_len + icv_len) { - wiphy_warn(priv->hw->wiphy, "Malformed SDU rx'ed. Size is lesser than crypto headers.\n"); - goto drop; - } - - /* Remove IV, ICV and MIC */ - skb_trim(skb, skb->len - icv_len); - memmove(skb->data + iv_len, skb->data, hdrlen); - skb_pull(skb, iv_len); - } - - /* Remove TSF from the end of frame */ - if (arg->flags & WSM_RX_STATUS_TSF_INCLUDED) { - memcpy(&hdr->mactime, skb->data + skb->len - 8, 8); - hdr->mactime = le64_to_cpu(hdr->mactime); - if (skb->len >= 8) - skb_trim(skb, skb->len - 8); - } else { - hdr->mactime = 0; - } - - cw1200_debug_rxed(priv); - if (arg->flags & WSM_RX_STATUS_AGGREGATE) - cw1200_debug_rxed_agg(priv); - - if (ieee80211_is_action(frame->frame_control) && - (arg->flags & WSM_RX_STATUS_ADDRESS1)) { - if (cw1200_handle_action_rx(priv, skb)) - return; - } else if (ieee80211_is_beacon(frame->frame_control) && - !arg->status && priv->vif && - ether_addr_equal(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid)) { - const u8 *tim_ie; - u8 *ies = ((struct ieee80211_mgmt *) - (skb->data))->u.beacon.variable; - size_t ies_len = skb->len - (ies - (u8 *)(skb->data)); - - tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len); - if (tim_ie) { - struct ieee80211_tim_ie *tim = - (struct ieee80211_tim_ie *)&tim_ie[2]; - - if (priv->join_dtim_period != tim->dtim_period) { - priv->join_dtim_period = tim->dtim_period; - queue_work(priv->workqueue, - &priv->set_beacon_wakeup_period_work); - } - } - - /* Disable beacon filter once we're associated... */ - if (priv->disable_beacon_filter && - (priv->vif->bss_conf.assoc || - priv->vif->bss_conf.ibss_joined)) { - priv->disable_beacon_filter = false; - queue_work(priv->workqueue, - &priv->update_filtering_work); - } - } - - /* Stay awake after frame is received to give - * userspace chance to react and acquire appropriate - * wakelock. - */ - if (ieee80211_is_auth(frame->frame_control)) - grace_period = 5 * HZ; - else if (ieee80211_is_deauth(frame->frame_control)) - grace_period = 5 * HZ; - else - grace_period = 1 * HZ; - cw1200_pm_stay_awake(&priv->pm_state, grace_period); - - if (early_data) { - spin_lock_bh(&priv->ps_state_lock); - /* Double-check status with lock held */ - if (entry->status == CW1200_LINK_SOFT) - skb_queue_tail(&entry->rx_queue, skb); - else - ieee80211_rx_irqsafe(priv->hw, skb); - spin_unlock_bh(&priv->ps_state_lock); - } else { - ieee80211_rx_irqsafe(priv->hw, skb); - } - *skb_p = NULL; - - return; - -drop: - /* TODO: update failure counters */ - return; -} - -/* ******************************************************************** */ -/* Security */ - -int cw1200_alloc_key(struct cw1200_common *priv) -{ - int idx; - - idx = ffs(~priv->key_map) - 1; - if (idx < 0 || idx > WSM_KEY_MAX_INDEX) - return -1; - - priv->key_map |= BIT(idx); - priv->keys[idx].index = idx; - return idx; -} - -void cw1200_free_key(struct cw1200_common *priv, int idx) -{ - BUG_ON(!(priv->key_map & BIT(idx))); - memset(&priv->keys[idx], 0, sizeof(priv->keys[idx])); - priv->key_map &= ~BIT(idx); -} - -void cw1200_free_keys(struct cw1200_common *priv) -{ - memset(&priv->keys, 0, sizeof(priv->keys)); - priv->key_map = 0; -} - -int cw1200_upload_keys(struct cw1200_common *priv) -{ - int idx, ret = 0; - for (idx = 0; idx <= WSM_KEY_MAX_INDEX; ++idx) - if (priv->key_map & BIT(idx)) { - ret = wsm_add_key(priv, &priv->keys[idx]); - if (ret < 0) - break; - } - return ret; -} - -/* Workaround for WFD test case 6.1.10 */ -void cw1200_link_id_reset(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, linkid_reset_work); - int temp_linkid; - - if (!priv->action_linkid) { - /* In GO mode we can receive ACTION frames without a linkID */ - temp_linkid = cw1200_alloc_link_id(priv, - &priv->action_frame_sa[0]); - WARN_ON(!temp_linkid); - if (temp_linkid) { - /* Make sure we execute the WQ */ - flush_workqueue(priv->workqueue); - /* Release the link ID */ - spin_lock_bh(&priv->ps_state_lock); - priv->link_id_db[temp_linkid - 1].prev_status = - priv->link_id_db[temp_linkid - 1].status; - priv->link_id_db[temp_linkid - 1].status = - CW1200_LINK_RESET; - spin_unlock_bh(&priv->ps_state_lock); - wsm_lock_tx_async(priv); - if (queue_work(priv->workqueue, - &priv->link_id_work) <= 0) - wsm_unlock_tx(priv); - } - } else { - spin_lock_bh(&priv->ps_state_lock); - priv->link_id_db[priv->action_linkid - 1].prev_status = - priv->link_id_db[priv->action_linkid - 1].status; - priv->link_id_db[priv->action_linkid - 1].status = - CW1200_LINK_RESET_REMAP; - spin_unlock_bh(&priv->ps_state_lock); - wsm_lock_tx_async(priv); - if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) - wsm_unlock_tx(priv); - flush_workqueue(priv->workqueue); - } -} - -int cw1200_find_link_id(struct cw1200_common *priv, const u8 *mac) -{ - int i, ret = 0; - spin_lock_bh(&priv->ps_state_lock); - for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { - if (!memcmp(mac, priv->link_id_db[i].mac, ETH_ALEN) && - priv->link_id_db[i].status) { - priv->link_id_db[i].timestamp = jiffies; - ret = i + 1; - break; - } - } - spin_unlock_bh(&priv->ps_state_lock); - return ret; -} - -int cw1200_alloc_link_id(struct cw1200_common *priv, const u8 *mac) -{ - int i, ret = 0; - unsigned long max_inactivity = 0; - unsigned long now = jiffies; - - spin_lock_bh(&priv->ps_state_lock); - for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { - if (!priv->link_id_db[i].status) { - ret = i + 1; - break; - } else if (priv->link_id_db[i].status != CW1200_LINK_HARD && - !priv->tx_queue_stats.link_map_cache[i + 1]) { - unsigned long inactivity = - now - priv->link_id_db[i].timestamp; - if (inactivity < max_inactivity) - continue; - max_inactivity = inactivity; - ret = i + 1; - } - } - if (ret) { - struct cw1200_link_entry *entry = &priv->link_id_db[ret - 1]; - pr_debug("[AP] STA added, link_id: %d\n", ret); - entry->status = CW1200_LINK_RESERVE; - memcpy(&entry->mac, mac, ETH_ALEN); - memset(&entry->buffered, 0, CW1200_MAX_TID); - skb_queue_head_init(&entry->rx_queue); - wsm_lock_tx_async(priv); - if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) - wsm_unlock_tx(priv); - } else { - wiphy_info(priv->hw->wiphy, - "[AP] Early: no more link IDs available.\n"); - } - - spin_unlock_bh(&priv->ps_state_lock); - return ret; -} - -void cw1200_link_id_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, link_id_work); - wsm_flush_tx(priv); - cw1200_link_id_gc_work(&priv->link_id_gc_work.work); - wsm_unlock_tx(priv); -} - -void cw1200_link_id_gc_work(struct work_struct *work) -{ - struct cw1200_common *priv = - container_of(work, struct cw1200_common, link_id_gc_work.work); - struct wsm_reset reset = { - .reset_statistics = false, - }; - struct wsm_map_link map_link = { - .link_id = 0, - }; - unsigned long now = jiffies; - unsigned long next_gc = -1; - long ttl; - bool need_reset; - u32 mask; - int i; - - if (priv->join_status != CW1200_JOIN_STATUS_AP) - return; - - wsm_lock_tx(priv); - spin_lock_bh(&priv->ps_state_lock); - for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { - need_reset = false; - mask = BIT(i + 1); - if (priv->link_id_db[i].status == CW1200_LINK_RESERVE || - (priv->link_id_db[i].status == CW1200_LINK_HARD && - !(priv->link_id_map & mask))) { - if (priv->link_id_map & mask) { - priv->sta_asleep_mask &= ~mask; - priv->pspoll_mask &= ~mask; - need_reset = true; - } - priv->link_id_map |= mask; - if (priv->link_id_db[i].status != CW1200_LINK_HARD) - priv->link_id_db[i].status = CW1200_LINK_SOFT; - memcpy(map_link.mac_addr, priv->link_id_db[i].mac, - ETH_ALEN); - spin_unlock_bh(&priv->ps_state_lock); - if (need_reset) { - reset.link_id = i + 1; - wsm_reset(priv, &reset); - } - map_link.link_id = i + 1; - wsm_map_link(priv, &map_link); - next_gc = min(next_gc, CW1200_LINK_ID_GC_TIMEOUT); - spin_lock_bh(&priv->ps_state_lock); - } else if (priv->link_id_db[i].status == CW1200_LINK_SOFT) { - ttl = priv->link_id_db[i].timestamp - now + - CW1200_LINK_ID_GC_TIMEOUT; - if (ttl <= 0) { - need_reset = true; - priv->link_id_db[i].status = CW1200_LINK_OFF; - priv->link_id_map &= ~mask; - priv->sta_asleep_mask &= ~mask; - priv->pspoll_mask &= ~mask; - eth_zero_addr(map_link.mac_addr); - spin_unlock_bh(&priv->ps_state_lock); - reset.link_id = i + 1; - wsm_reset(priv, &reset); - spin_lock_bh(&priv->ps_state_lock); - } else { - next_gc = min_t(unsigned long, next_gc, ttl); - } - } else if (priv->link_id_db[i].status == CW1200_LINK_RESET || - priv->link_id_db[i].status == - CW1200_LINK_RESET_REMAP) { - int status = priv->link_id_db[i].status; - priv->link_id_db[i].status = - priv->link_id_db[i].prev_status; - priv->link_id_db[i].timestamp = now; - reset.link_id = i + 1; - spin_unlock_bh(&priv->ps_state_lock); - wsm_reset(priv, &reset); - if (status == CW1200_LINK_RESET_REMAP) { - memcpy(map_link.mac_addr, - priv->link_id_db[i].mac, - ETH_ALEN); - map_link.link_id = i + 1; - wsm_map_link(priv, &map_link); - next_gc = min(next_gc, - CW1200_LINK_ID_GC_TIMEOUT); - } - spin_lock_bh(&priv->ps_state_lock); - } - if (need_reset) { - skb_queue_purge(&priv->link_id_db[i].rx_queue); - pr_debug("[AP] STA removed, link_id: %d\n", - reset.link_id); - } - } - spin_unlock_bh(&priv->ps_state_lock); - if (next_gc != -1) - queue_delayed_work(priv->workqueue, - &priv->link_id_gc_work, next_gc); - wsm_unlock_tx(priv); -} diff --git a/drivers/net/wireless/cw1200/txrx.h b/drivers/net/wireless/cw1200/txrx.h deleted file mode 100644 index 492a4e1..0000000 --- a/drivers/net/wireless/cw1200/txrx.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Datapath interface for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_TXRX_H -#define CW1200_TXRX_H - -#include <linux/list.h> - -/* extern */ struct ieee80211_hw; -/* extern */ struct sk_buff; -/* extern */ struct wsm_tx; -/* extern */ struct wsm_rx; -/* extern */ struct wsm_tx_confirm; -/* extern */ struct cw1200_txpriv; - -struct tx_policy { - union { - __le32 tbl[3]; - u8 raw[12]; - }; - u8 defined; - u8 usage_count; - u8 retry_count; - u8 uploaded; -}; - -struct tx_policy_cache_entry { - struct tx_policy policy; - struct list_head link; -}; - -#define TX_POLICY_CACHE_SIZE (8) -struct tx_policy_cache { - struct tx_policy_cache_entry cache[TX_POLICY_CACHE_SIZE]; - struct list_head used; - struct list_head free; - spinlock_t lock; /* Protect policy cache */ -}; - -/* ******************************************************************** */ -/* TX policy cache */ -/* Intention of TX policy cache is an overcomplicated WSM API. - * Device does not accept per-PDU tx retry sequence. - * It uses "tx retry policy id" instead, so driver code has to sync - * linux tx retry sequences with a retry policy table in the device. - */ -void tx_policy_init(struct cw1200_common *priv); -void tx_policy_upload_work(struct work_struct *work); -void tx_policy_clean(struct cw1200_common *priv); - -/* ******************************************************************** */ -/* TX implementation */ - -u32 cw1200_rate_mask_to_wsm(struct cw1200_common *priv, - u32 rates); -void cw1200_tx(struct ieee80211_hw *dev, - struct ieee80211_tx_control *control, - struct sk_buff *skb); -void cw1200_skb_dtor(struct cw1200_common *priv, - struct sk_buff *skb, - const struct cw1200_txpriv *txpriv); - -/* ******************************************************************** */ -/* WSM callbacks */ - -void cw1200_tx_confirm_cb(struct cw1200_common *priv, - int link_id, - struct wsm_tx_confirm *arg); -void cw1200_rx_cb(struct cw1200_common *priv, - struct wsm_rx *arg, - int link_id, - struct sk_buff **skb_p); - -/* ******************************************************************** */ -/* Timeout */ - -void cw1200_tx_timeout(struct work_struct *work); - -/* ******************************************************************** */ -/* Security */ -int cw1200_alloc_key(struct cw1200_common *priv); -void cw1200_free_key(struct cw1200_common *priv, int idx); -void cw1200_free_keys(struct cw1200_common *priv); -int cw1200_upload_keys(struct cw1200_common *priv); - -/* ******************************************************************** */ -/* Workaround for WFD test case 6.1.10 */ -void cw1200_link_id_reset(struct work_struct *work); - -#define CW1200_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ)) - -int cw1200_find_link_id(struct cw1200_common *priv, const u8 *mac); -int cw1200_alloc_link_id(struct cw1200_common *priv, const u8 *mac); -void cw1200_link_id_work(struct work_struct *work); -void cw1200_link_id_gc_work(struct work_struct *work); - - -#endif /* CW1200_TXRX_H */ diff --git a/drivers/net/wireless/cw1200/wsm.c b/drivers/net/wireless/cw1200/wsm.c deleted file mode 100644 index 9e0ca30..0000000 --- a/drivers/net/wireless/cw1200/wsm.c +++ /dev/null @@ -1,1822 +0,0 @@ -/* - * WSM host interface (HI) implementation for - * ST-Ericsson CW1200 mac80211 drivers. - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/skbuff.h> -#include <linux/wait.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/random.h> - -#include "cw1200.h" -#include "wsm.h" -#include "bh.h" -#include "sta.h" -#include "debug.h" - -#define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */ -#define WSM_CMD_START_TIMEOUT (7 * HZ) -#define WSM_CMD_RESET_TIMEOUT (3 * HZ) /* 2 sec. timeout was observed. */ -#define WSM_CMD_MAX_TIMEOUT (3 * HZ) - -#define WSM_SKIP(buf, size) \ - do { \ - if ((buf)->data + size > (buf)->end) \ - goto underflow; \ - (buf)->data += size; \ - } while (0) - -#define WSM_GET(buf, ptr, size) \ - do { \ - if ((buf)->data + size > (buf)->end) \ - goto underflow; \ - memcpy(ptr, (buf)->data, size); \ - (buf)->data += size; \ - } while (0) - -#define __WSM_GET(buf, type, type2, cvt) \ - ({ \ - type val; \ - if ((buf)->data + sizeof(type) > (buf)->end) \ - goto underflow; \ - val = cvt(*(type2 *)(buf)->data); \ - (buf)->data += sizeof(type); \ - val; \ - }) - -#define WSM_GET8(buf) __WSM_GET(buf, u8, u8, (u8)) -#define WSM_GET16(buf) __WSM_GET(buf, u16, __le16, __le16_to_cpu) -#define WSM_GET32(buf) __WSM_GET(buf, u32, __le32, __le32_to_cpu) - -#define WSM_PUT(buf, ptr, size) \ - do { \ - if ((buf)->data + size > (buf)->end) \ - if (wsm_buf_reserve((buf), size)) \ - goto nomem; \ - memcpy((buf)->data, ptr, size); \ - (buf)->data += size; \ - } while (0) - -#define __WSM_PUT(buf, val, type, type2, cvt) \ - do { \ - if ((buf)->data + sizeof(type) > (buf)->end) \ - if (wsm_buf_reserve((buf), sizeof(type))) \ - goto nomem; \ - *(type2 *)(buf)->data = cvt(val); \ - (buf)->data += sizeof(type); \ - } while (0) - -#define WSM_PUT8(buf, val) __WSM_PUT(buf, val, u8, u8, (u8)) -#define WSM_PUT16(buf, val) __WSM_PUT(buf, val, u16, __le16, __cpu_to_le16) -#define WSM_PUT32(buf, val) __WSM_PUT(buf, val, u32, __le32, __cpu_to_le32) - -static void wsm_buf_reset(struct wsm_buf *buf); -static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size); - -static int wsm_cmd_send(struct cw1200_common *priv, - struct wsm_buf *buf, - void *arg, u16 cmd, long tmo); - -#define wsm_cmd_lock(__priv) mutex_lock(&((__priv)->wsm_cmd_mux)) -#define wsm_cmd_unlock(__priv) mutex_unlock(&((__priv)->wsm_cmd_mux)) - -/* ******************************************************************** */ -/* WSM API implementation */ - -static int wsm_generic_confirm(struct cw1200_common *priv, - void *arg, - struct wsm_buf *buf) -{ - u32 status = WSM_GET32(buf); - if (status != WSM_STATUS_SUCCESS) - return -EINVAL; - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -int wsm_configuration(struct cw1200_common *priv, struct wsm_configuration *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT32(buf, arg->dot11MaxTransmitMsduLifeTime); - WSM_PUT32(buf, arg->dot11MaxReceiveLifeTime); - WSM_PUT32(buf, arg->dot11RtsThreshold); - - /* DPD block. */ - WSM_PUT16(buf, arg->dpdData_size + 12); - WSM_PUT16(buf, 1); /* DPD version */ - WSM_PUT(buf, arg->dot11StationId, ETH_ALEN); - WSM_PUT16(buf, 5); /* DPD flags */ - WSM_PUT(buf, arg->dpdData, arg->dpdData_size); - - ret = wsm_cmd_send(priv, buf, arg, - WSM_CONFIGURATION_REQ_ID, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -static int wsm_configuration_confirm(struct cw1200_common *priv, - struct wsm_configuration *arg, - struct wsm_buf *buf) -{ - int i; - int status; - - status = WSM_GET32(buf); - if (WARN_ON(status != WSM_STATUS_SUCCESS)) - return -EINVAL; - - WSM_GET(buf, arg->dot11StationId, ETH_ALEN); - arg->dot11FrequencyBandsSupported = WSM_GET8(buf); - WSM_SKIP(buf, 1); - arg->supportedRateMask = WSM_GET32(buf); - for (i = 0; i < 2; ++i) { - arg->txPowerRange[i].min_power_level = WSM_GET32(buf); - arg->txPowerRange[i].max_power_level = WSM_GET32(buf); - arg->txPowerRange[i].stepping = WSM_GET32(buf); - } - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -/* ******************************************************************** */ - -int wsm_reset(struct cw1200_common *priv, const struct wsm_reset *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - u16 cmd = WSM_RESET_REQ_ID | WSM_TX_LINK_ID(arg->link_id); - - wsm_cmd_lock(priv); - - WSM_PUT32(buf, arg->reset_statistics ? 0 : 1); - ret = wsm_cmd_send(priv, buf, NULL, cmd, WSM_CMD_RESET_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -struct wsm_mib { - u16 mib_id; - void *buf; - size_t buf_size; -}; - -int wsm_read_mib(struct cw1200_common *priv, u16 mib_id, void *_buf, - size_t buf_size) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - struct wsm_mib mib_buf = { - .mib_id = mib_id, - .buf = _buf, - .buf_size = buf_size, - }; - wsm_cmd_lock(priv); - - WSM_PUT16(buf, mib_id); - WSM_PUT16(buf, 0); - - ret = wsm_cmd_send(priv, buf, &mib_buf, - WSM_READ_MIB_REQ_ID, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -static int wsm_read_mib_confirm(struct cw1200_common *priv, - struct wsm_mib *arg, - struct wsm_buf *buf) -{ - u16 size; - if (WARN_ON(WSM_GET32(buf) != WSM_STATUS_SUCCESS)) - return -EINVAL; - - if (WARN_ON(WSM_GET16(buf) != arg->mib_id)) - return -EINVAL; - - size = WSM_GET16(buf); - if (size > arg->buf_size) - size = arg->buf_size; - - WSM_GET(buf, arg->buf, size); - arg->buf_size = size; - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -/* ******************************************************************** */ - -int wsm_write_mib(struct cw1200_common *priv, u16 mib_id, void *_buf, - size_t buf_size) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - struct wsm_mib mib_buf = { - .mib_id = mib_id, - .buf = _buf, - .buf_size = buf_size, - }; - - wsm_cmd_lock(priv); - - WSM_PUT16(buf, mib_id); - WSM_PUT16(buf, buf_size); - WSM_PUT(buf, _buf, buf_size); - - ret = wsm_cmd_send(priv, buf, &mib_buf, - WSM_WRITE_MIB_REQ_ID, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -static int wsm_write_mib_confirm(struct cw1200_common *priv, - struct wsm_mib *arg, - struct wsm_buf *buf) -{ - int ret; - - ret = wsm_generic_confirm(priv, arg, buf); - if (ret) - return ret; - - if (arg->mib_id == WSM_MIB_ID_OPERATIONAL_POWER_MODE) { - /* OperationalMode: update PM status. */ - const char *p = arg->buf; - cw1200_enable_powersave(priv, (p[0] & 0x0F) ? true : false); - } - return 0; -} - -/* ******************************************************************** */ - -int wsm_scan(struct cw1200_common *priv, const struct wsm_scan *arg) -{ - int i; - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - if (arg->num_channels > 48) - return -EINVAL; - - if (arg->num_ssids > 2) - return -EINVAL; - - if (arg->band > 1) - return -EINVAL; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, arg->band); - WSM_PUT8(buf, arg->type); - WSM_PUT8(buf, arg->flags); - WSM_PUT8(buf, arg->max_tx_rate); - WSM_PUT32(buf, arg->auto_scan_interval); - WSM_PUT8(buf, arg->num_probes); - WSM_PUT8(buf, arg->num_channels); - WSM_PUT8(buf, arg->num_ssids); - WSM_PUT8(buf, arg->probe_delay); - - for (i = 0; i < arg->num_channels; ++i) { - WSM_PUT16(buf, arg->ch[i].number); - WSM_PUT16(buf, 0); - WSM_PUT32(buf, arg->ch[i].min_chan_time); - WSM_PUT32(buf, arg->ch[i].max_chan_time); - WSM_PUT32(buf, 0); - } - - for (i = 0; i < arg->num_ssids; ++i) { - WSM_PUT32(buf, arg->ssids[i].length); - WSM_PUT(buf, &arg->ssids[i].ssid[0], - sizeof(arg->ssids[i].ssid)); - } - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_START_SCAN_REQ_ID, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_stop_scan(struct cw1200_common *priv) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - wsm_cmd_lock(priv); - ret = wsm_cmd_send(priv, buf, NULL, - WSM_STOP_SCAN_REQ_ID, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; -} - - -static int wsm_tx_confirm(struct cw1200_common *priv, - struct wsm_buf *buf, - int link_id) -{ - struct wsm_tx_confirm tx_confirm; - - tx_confirm.packet_id = WSM_GET32(buf); - tx_confirm.status = WSM_GET32(buf); - tx_confirm.tx_rate = WSM_GET8(buf); - tx_confirm.ack_failures = WSM_GET8(buf); - tx_confirm.flags = WSM_GET16(buf); - tx_confirm.media_delay = WSM_GET32(buf); - tx_confirm.tx_queue_delay = WSM_GET32(buf); - - cw1200_tx_confirm_cb(priv, link_id, &tx_confirm); - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -static int wsm_multi_tx_confirm(struct cw1200_common *priv, - struct wsm_buf *buf, int link_id) -{ - int ret; - int count; - int i; - - count = WSM_GET32(buf); - if (WARN_ON(count <= 0)) - return -EINVAL; - - if (count > 1) { - /* We already released one buffer, now for the rest */ - ret = wsm_release_tx_buffer(priv, count - 1); - if (ret < 0) - return ret; - else if (ret > 0) - cw1200_bh_wakeup(priv); - } - - cw1200_debug_txed_multi(priv, count); - for (i = 0; i < count; ++i) { - ret = wsm_tx_confirm(priv, buf, link_id); - if (ret) - return ret; - } - return ret; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -/* ******************************************************************** */ - -static int wsm_join_confirm(struct cw1200_common *priv, - struct wsm_join_cnf *arg, - struct wsm_buf *buf) -{ - arg->status = WSM_GET32(buf); - if (WARN_ON(arg->status) != WSM_STATUS_SUCCESS) - return -EINVAL; - - arg->min_power_level = WSM_GET32(buf); - arg->max_power_level = WSM_GET32(buf); - - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -int wsm_join(struct cw1200_common *priv, struct wsm_join *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - struct wsm_join_cnf resp; - wsm_cmd_lock(priv); - - WSM_PUT8(buf, arg->mode); - WSM_PUT8(buf, arg->band); - WSM_PUT16(buf, arg->channel_number); - WSM_PUT(buf, &arg->bssid[0], sizeof(arg->bssid)); - WSM_PUT16(buf, arg->atim_window); - WSM_PUT8(buf, arg->preamble_type); - WSM_PUT8(buf, arg->probe_for_join); - WSM_PUT8(buf, arg->dtim_period); - WSM_PUT8(buf, arg->flags); - WSM_PUT32(buf, arg->ssid_len); - WSM_PUT(buf, &arg->ssid[0], sizeof(arg->ssid)); - WSM_PUT32(buf, arg->beacon_interval); - WSM_PUT32(buf, arg->basic_rate_set); - - priv->tx_burst_idx = -1; - ret = wsm_cmd_send(priv, buf, &resp, - WSM_JOIN_REQ_ID, WSM_CMD_TIMEOUT); - /* TODO: Update state based on resp.min|max_power_level */ - - priv->join_complete_status = resp.status; - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_set_bss_params(struct cw1200_common *priv, - const struct wsm_set_bss_params *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, (arg->reset_beacon_loss ? 0x1 : 0)); - WSM_PUT8(buf, arg->beacon_lost_count); - WSM_PUT16(buf, arg->aid); - WSM_PUT32(buf, arg->operational_rate_set); - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_SET_BSS_PARAMS_REQ_ID, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_add_key(struct cw1200_common *priv, const struct wsm_add_key *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT(buf, arg, sizeof(*arg)); - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_ADD_KEY_REQ_ID, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_remove_key(struct cw1200_common *priv, const struct wsm_remove_key *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, arg->index); - WSM_PUT8(buf, 0); - WSM_PUT16(buf, 0); - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_REMOVE_KEY_REQ_ID, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_set_tx_queue_params(struct cw1200_common *priv, - const struct wsm_set_tx_queue_params *arg, u8 id) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - u8 queue_id_to_wmm_aci[] = {3, 2, 0, 1}; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, queue_id_to_wmm_aci[id]); - WSM_PUT8(buf, 0); - WSM_PUT8(buf, arg->ackPolicy); - WSM_PUT8(buf, 0); - WSM_PUT32(buf, arg->maxTransmitLifetime); - WSM_PUT16(buf, arg->allowedMediumTime); - WSM_PUT16(buf, 0); - - ret = wsm_cmd_send(priv, buf, NULL, 0x0012, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_set_edca_params(struct cw1200_common *priv, - const struct wsm_edca_params *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - /* Implemented according to specification. */ - - WSM_PUT16(buf, arg->params[3].cwmin); - WSM_PUT16(buf, arg->params[2].cwmin); - WSM_PUT16(buf, arg->params[1].cwmin); - WSM_PUT16(buf, arg->params[0].cwmin); - - WSM_PUT16(buf, arg->params[3].cwmax); - WSM_PUT16(buf, arg->params[2].cwmax); - WSM_PUT16(buf, arg->params[1].cwmax); - WSM_PUT16(buf, arg->params[0].cwmax); - - WSM_PUT8(buf, arg->params[3].aifns); - WSM_PUT8(buf, arg->params[2].aifns); - WSM_PUT8(buf, arg->params[1].aifns); - WSM_PUT8(buf, arg->params[0].aifns); - - WSM_PUT16(buf, arg->params[3].txop_limit); - WSM_PUT16(buf, arg->params[2].txop_limit); - WSM_PUT16(buf, arg->params[1].txop_limit); - WSM_PUT16(buf, arg->params[0].txop_limit); - - WSM_PUT32(buf, arg->params[3].max_rx_lifetime); - WSM_PUT32(buf, arg->params[2].max_rx_lifetime); - WSM_PUT32(buf, arg->params[1].max_rx_lifetime); - WSM_PUT32(buf, arg->params[0].max_rx_lifetime); - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_EDCA_PARAMS_REQ_ID, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_switch_channel(struct cw1200_common *priv, - const struct wsm_switch_channel *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, arg->mode); - WSM_PUT8(buf, arg->switch_count); - WSM_PUT16(buf, arg->channel_number); - - priv->channel_switch_in_progress = 1; - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_SWITCH_CHANNEL_REQ_ID, WSM_CMD_TIMEOUT); - if (ret) - priv->channel_switch_in_progress = 0; - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - priv->ps_mode_switch_in_progress = 1; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, arg->mode); - WSM_PUT8(buf, arg->fast_psm_idle_period); - WSM_PUT8(buf, arg->ap_psm_change_period); - WSM_PUT8(buf, arg->min_auto_pspoll_period); - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_SET_PM_REQ_ID, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_start(struct cw1200_common *priv, const struct wsm_start *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT8(buf, arg->mode); - WSM_PUT8(buf, arg->band); - WSM_PUT16(buf, arg->channel_number); - WSM_PUT32(buf, arg->ct_window); - WSM_PUT32(buf, arg->beacon_interval); - WSM_PUT8(buf, arg->dtim_period); - WSM_PUT8(buf, arg->preamble); - WSM_PUT8(buf, arg->probe_delay); - WSM_PUT8(buf, arg->ssid_len); - WSM_PUT(buf, arg->ssid, sizeof(arg->ssid)); - WSM_PUT32(buf, arg->basic_rate_set); - - priv->tx_burst_idx = -1; - ret = wsm_cmd_send(priv, buf, NULL, - WSM_START_REQ_ID, WSM_CMD_START_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_beacon_transmit(struct cw1200_common *priv, - const struct wsm_beacon_transmit *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT32(buf, arg->enable_beaconing ? 1 : 0); - - ret = wsm_cmd_send(priv, buf, NULL, - WSM_BEACON_TRANSMIT_REQ_ID, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_start_find(struct cw1200_common *priv) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - ret = wsm_cmd_send(priv, buf, NULL, 0x0019, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; -} - -/* ******************************************************************** */ - -int wsm_stop_find(struct cw1200_common *priv) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - ret = wsm_cmd_send(priv, buf, NULL, 0x001A, WSM_CMD_TIMEOUT); - wsm_cmd_unlock(priv); - return ret; -} - -/* ******************************************************************** */ - -int wsm_map_link(struct cw1200_common *priv, const struct wsm_map_link *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - u16 cmd = 0x001C | WSM_TX_LINK_ID(arg->link_id); - - wsm_cmd_lock(priv); - - WSM_PUT(buf, &arg->mac_addr[0], sizeof(arg->mac_addr)); - WSM_PUT16(buf, 0); - - ret = wsm_cmd_send(priv, buf, NULL, cmd, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ - -int wsm_update_ie(struct cw1200_common *priv, - const struct wsm_update_ie *arg) -{ - int ret; - struct wsm_buf *buf = &priv->wsm_cmd_buf; - - wsm_cmd_lock(priv); - - WSM_PUT16(buf, arg->what); - WSM_PUT16(buf, arg->count); - WSM_PUT(buf, arg->ies, arg->length); - - ret = wsm_cmd_send(priv, buf, NULL, 0x001B, WSM_CMD_TIMEOUT); - - wsm_cmd_unlock(priv); - return ret; - -nomem: - wsm_cmd_unlock(priv); - return -ENOMEM; -} - -/* ******************************************************************** */ -int wsm_set_probe_responder(struct cw1200_common *priv, bool enable) -{ - priv->rx_filter.probeResponder = enable; - return wsm_set_rx_filter(priv, &priv->rx_filter); -} - -/* ******************************************************************** */ -/* WSM indication events implementation */ -const char * const cw1200_fw_types[] = { - "ETF", - "WFM", - "WSM", - "HI test", - "Platform test" -}; - -static int wsm_startup_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - priv->wsm_caps.input_buffers = WSM_GET16(buf); - priv->wsm_caps.input_buffer_size = WSM_GET16(buf); - priv->wsm_caps.hw_id = WSM_GET16(buf); - priv->wsm_caps.hw_subid = WSM_GET16(buf); - priv->wsm_caps.status = WSM_GET16(buf); - priv->wsm_caps.fw_cap = WSM_GET16(buf); - priv->wsm_caps.fw_type = WSM_GET16(buf); - priv->wsm_caps.fw_api = WSM_GET16(buf); - priv->wsm_caps.fw_build = WSM_GET16(buf); - priv->wsm_caps.fw_ver = WSM_GET16(buf); - WSM_GET(buf, priv->wsm_caps.fw_label, sizeof(priv->wsm_caps.fw_label)); - priv->wsm_caps.fw_label[sizeof(priv->wsm_caps.fw_label) - 1] = 0; /* Do not trust FW too much... */ - - if (WARN_ON(priv->wsm_caps.status)) - return -EINVAL; - - if (WARN_ON(priv->wsm_caps.fw_type > 4)) - return -EINVAL; - - pr_info("CW1200 WSM init done.\n" - " Input buffers: %d x %d bytes\n" - " Hardware: %d.%d\n" - " %s firmware [%s], ver: %d, build: %d," - " api: %d, cap: 0x%.4X\n", - priv->wsm_caps.input_buffers, - priv->wsm_caps.input_buffer_size, - priv->wsm_caps.hw_id, priv->wsm_caps.hw_subid, - cw1200_fw_types[priv->wsm_caps.fw_type], - priv->wsm_caps.fw_label, priv->wsm_caps.fw_ver, - priv->wsm_caps.fw_build, - priv->wsm_caps.fw_api, priv->wsm_caps.fw_cap); - - /* Disable unsupported frequency bands */ - if (!(priv->wsm_caps.fw_cap & 0x1)) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; - if (!(priv->wsm_caps.fw_cap & 0x2)) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - - priv->firmware_ready = 1; - wake_up(&priv->wsm_startup_done); - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -static int wsm_receive_indication(struct cw1200_common *priv, - int link_id, - struct wsm_buf *buf, - struct sk_buff **skb_p) -{ - struct wsm_rx rx; - struct ieee80211_hdr *hdr; - size_t hdr_len; - __le16 fctl; - - rx.status = WSM_GET32(buf); - rx.channel_number = WSM_GET16(buf); - rx.rx_rate = WSM_GET8(buf); - rx.rcpi_rssi = WSM_GET8(buf); - rx.flags = WSM_GET32(buf); - - /* FW Workaround: Drop probe resp or - beacon when RSSI is 0 - */ - hdr = (struct ieee80211_hdr *)(*skb_p)->data; - - if (!rx.rcpi_rssi && - (ieee80211_is_probe_resp(hdr->frame_control) || - ieee80211_is_beacon(hdr->frame_control))) - return 0; - - /* If no RSSI subscription has been made, - * convert RCPI to RSSI here - */ - if (!priv->cqm_use_rssi) - rx.rcpi_rssi = rx.rcpi_rssi / 2 - 110; - - fctl = *(__le16 *)buf->data; - hdr_len = buf->data - buf->begin; - skb_pull(*skb_p, hdr_len); - if (!rx.status && ieee80211_is_deauth(fctl)) { - if (priv->join_status == CW1200_JOIN_STATUS_STA) { - /* Shedule unjoin work */ - pr_debug("[WSM] Issue unjoin command (RX).\n"); - wsm_lock_tx_async(priv); - if (queue_work(priv->workqueue, - &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - } - } - cw1200_rx_cb(priv, &rx, link_id, skb_p); - if (*skb_p) - skb_push(*skb_p, hdr_len); - - return 0; - -underflow: - return -EINVAL; -} - -static int wsm_event_indication(struct cw1200_common *priv, struct wsm_buf *buf) -{ - int first; - struct cw1200_wsm_event *event; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { - /* STA is stopped. */ - return 0; - } - - event = kzalloc(sizeof(struct cw1200_wsm_event), GFP_KERNEL); - if (!event) - return -ENOMEM; - - event->evt.id = WSM_GET32(buf); - event->evt.data = WSM_GET32(buf); - - pr_debug("[WSM] Event: %d(%d)\n", - event->evt.id, event->evt.data); - - spin_lock(&priv->event_queue_lock); - first = list_empty(&priv->event_queue); - list_add_tail(&event->link, &priv->event_queue); - spin_unlock(&priv->event_queue_lock); - - if (first) - queue_work(priv->workqueue, &priv->event_handler); - - return 0; - -underflow: - kfree(event); - return -EINVAL; -} - -static int wsm_channel_switch_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - WARN_ON(WSM_GET32(buf)); - - priv->channel_switch_in_progress = 0; - wake_up(&priv->channel_switch_done); - - wsm_unlock_tx(priv); - - return 0; - -underflow: - return -EINVAL; -} - -static int wsm_set_pm_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - /* TODO: Check buf (struct wsm_set_pm_complete) for validity */ - if (priv->ps_mode_switch_in_progress) { - priv->ps_mode_switch_in_progress = 0; - wake_up(&priv->ps_mode_switch_done); - } - return 0; -} - -static int wsm_scan_started(struct cw1200_common *priv, void *arg, - struct wsm_buf *buf) -{ - u32 status = WSM_GET32(buf); - if (status != WSM_STATUS_SUCCESS) { - cw1200_scan_failed_cb(priv); - return -EINVAL; - } - return 0; - -underflow: - WARN_ON(1); - return -EINVAL; -} - -static int wsm_scan_complete_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - struct wsm_scan_complete arg; - arg.status = WSM_GET32(buf); - arg.psm = WSM_GET8(buf); - arg.num_channels = WSM_GET8(buf); - cw1200_scan_complete_cb(priv, &arg); - - return 0; - -underflow: - return -EINVAL; -} - -static int wsm_join_complete_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - struct wsm_join_complete arg; - arg.status = WSM_GET32(buf); - pr_debug("[WSM] Join complete indication, status: %d\n", arg.status); - cw1200_join_complete_cb(priv, &arg); - - return 0; - -underflow: - return -EINVAL; -} - -static int wsm_find_complete_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - pr_warn("Implement find_complete_indication\n"); - return 0; -} - -static int wsm_ba_timeout_indication(struct cw1200_common *priv, - struct wsm_buf *buf) -{ - u32 dummy; - u8 tid; - u8 dummy2; - u8 addr[ETH_ALEN]; - - dummy = WSM_GET32(buf); - tid = WSM_GET8(buf); - dummy2 = WSM_GET8(buf); - WSM_GET(buf, addr, ETH_ALEN); - - pr_info("BlockACK timeout, tid %d, addr %pM\n", - tid, addr); - - return 0; - -underflow: - return -EINVAL; -} - -static int wsm_suspend_resume_indication(struct cw1200_common *priv, - int link_id, struct wsm_buf *buf) -{ - u32 flags; - struct wsm_suspend_resume arg; - - flags = WSM_GET32(buf); - arg.link_id = link_id; - arg.stop = !(flags & 1); - arg.multicast = !!(flags & 8); - arg.queue = (flags >> 1) & 3; - - cw1200_suspend_resume(priv, &arg); - - return 0; - -underflow: - return -EINVAL; -} - - -/* ******************************************************************** */ -/* WSM TX */ - -static int wsm_cmd_send(struct cw1200_common *priv, - struct wsm_buf *buf, - void *arg, u16 cmd, long tmo) -{ - size_t buf_len = buf->data - buf->begin; - int ret; - - /* Don't bother if we're dead. */ - if (priv->bh_error) { - ret = 0; - goto done; - } - - /* Block until the cmd buffer is completed. Tortuous. */ - spin_lock(&priv->wsm_cmd.lock); - while (!priv->wsm_cmd.done) { - spin_unlock(&priv->wsm_cmd.lock); - spin_lock(&priv->wsm_cmd.lock); - } - priv->wsm_cmd.done = 0; - spin_unlock(&priv->wsm_cmd.lock); - - if (cmd == WSM_WRITE_MIB_REQ_ID || - cmd == WSM_READ_MIB_REQ_ID) - pr_debug("[WSM] >>> 0x%.4X [MIB: 0x%.4X] (%zu)\n", - cmd, __le16_to_cpu(((__le16 *)buf->begin)[2]), - buf_len); - else - pr_debug("[WSM] >>> 0x%.4X (%zu)\n", cmd, buf_len); - - /* Due to buggy SPI on CW1200, we need to - * pad the message by a few bytes to ensure - * that it's completely received. - */ - buf_len += 4; - - /* Fill HI message header */ - /* BH will add sequence number */ - ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); - ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd); - - spin_lock(&priv->wsm_cmd.lock); - BUG_ON(priv->wsm_cmd.ptr); - priv->wsm_cmd.ptr = buf->begin; - priv->wsm_cmd.len = buf_len; - priv->wsm_cmd.arg = arg; - priv->wsm_cmd.cmd = cmd; - spin_unlock(&priv->wsm_cmd.lock); - - cw1200_bh_wakeup(priv); - - /* Wait for command completion */ - ret = wait_event_timeout(priv->wsm_cmd_wq, - priv->wsm_cmd.done, tmo); - - if (!ret && !priv->wsm_cmd.done) { - spin_lock(&priv->wsm_cmd.lock); - priv->wsm_cmd.done = 1; - priv->wsm_cmd.ptr = NULL; - spin_unlock(&priv->wsm_cmd.lock); - if (priv->bh_error) { - /* Return ok to help system cleanup */ - ret = 0; - } else { - pr_err("CMD req (0x%04x) stuck in firmware, killing BH\n", priv->wsm_cmd.cmd); - print_hex_dump_bytes("REQDUMP: ", DUMP_PREFIX_NONE, - buf->begin, buf_len); - pr_err("Outstanding outgoing frames: %d\n", priv->hw_bufs_used); - - /* Kill BH thread to report the error to the top layer. */ - atomic_add(1, &priv->bh_term); - wake_up(&priv->bh_wq); - ret = -ETIMEDOUT; - } - } else { - spin_lock(&priv->wsm_cmd.lock); - BUG_ON(!priv->wsm_cmd.done); - ret = priv->wsm_cmd.ret; - spin_unlock(&priv->wsm_cmd.lock); - } -done: - wsm_buf_reset(buf); - return ret; -} - -/* ******************************************************************** */ -/* WSM TX port control */ - -void wsm_lock_tx(struct cw1200_common *priv) -{ - wsm_cmd_lock(priv); - if (atomic_add_return(1, &priv->tx_lock) == 1) { - if (wsm_flush_tx(priv)) - pr_debug("[WSM] TX is locked.\n"); - } - wsm_cmd_unlock(priv); -} - -void wsm_lock_tx_async(struct cw1200_common *priv) -{ - if (atomic_add_return(1, &priv->tx_lock) == 1) - pr_debug("[WSM] TX is locked (async).\n"); -} - -bool wsm_flush_tx(struct cw1200_common *priv) -{ - unsigned long timestamp = jiffies; - bool pending = false; - long timeout; - int i; - - /* Flush must be called with TX lock held. */ - BUG_ON(!atomic_read(&priv->tx_lock)); - - /* First check if we really need to do something. - * It is safe to use unprotected access, as hw_bufs_used - * can only decrements. - */ - if (!priv->hw_bufs_used) - return true; - - if (priv->bh_error) { - /* In case of failure do not wait for magic. */ - pr_err("[WSM] Fatal error occurred, will not flush TX.\n"); - return false; - } else { - /* Get a timestamp of "oldest" frame */ - for (i = 0; i < 4; ++i) - pending |= cw1200_queue_get_xmit_timestamp( - &priv->tx_queue[i], - ×tamp, 0xffffffff); - /* If there's nothing pending, we're good */ - if (!pending) - return true; - - timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT - jiffies; - if (timeout < 0 || wait_event_timeout(priv->bh_evt_wq, - !priv->hw_bufs_used, - timeout) <= 0) { - /* Hmmm... Not good. Frame had stuck in firmware. */ - priv->bh_error = 1; - wiphy_err(priv->hw->wiphy, "[WSM] TX Frames (%d) stuck in firmware, killing BH\n", priv->hw_bufs_used); - wake_up(&priv->bh_wq); - return false; - } - - /* Ok, everything is flushed. */ - return true; - } -} - -void wsm_unlock_tx(struct cw1200_common *priv) -{ - int tx_lock; - tx_lock = atomic_sub_return(1, &priv->tx_lock); - BUG_ON(tx_lock < 0); - - if (tx_lock == 0) { - if (!priv->bh_error) - cw1200_bh_wakeup(priv); - pr_debug("[WSM] TX is unlocked.\n"); - } -} - -/* ******************************************************************** */ -/* WSM RX */ - -int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len) -{ - struct wsm_buf buf; - u32 reason; - u32 reg[18]; - char fname[48]; - unsigned int i; - - static const char * const reason_str[] = { - "undefined instruction", - "prefetch abort", - "data abort", - "unknown error", - }; - - buf.begin = buf.data = data; - buf.end = &buf.begin[len]; - - reason = WSM_GET32(&buf); - for (i = 0; i < ARRAY_SIZE(reg); ++i) - reg[i] = WSM_GET32(&buf); - WSM_GET(&buf, fname, sizeof(fname)); - - if (reason < 4) - wiphy_err(priv->hw->wiphy, - "Firmware exception: %s.\n", - reason_str[reason]); - else - wiphy_err(priv->hw->wiphy, - "Firmware assert at %.*s, line %d\n", - (int) sizeof(fname), fname, reg[1]); - - for (i = 0; i < 12; i += 4) - wiphy_err(priv->hw->wiphy, - "R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X,\n", - i + 0, reg[i + 0], i + 1, reg[i + 1], - i + 2, reg[i + 2], i + 3, reg[i + 3]); - wiphy_err(priv->hw->wiphy, - "R12: 0x%.8X, SP: 0x%.8X, LR: 0x%.8X, PC: 0x%.8X,\n", - reg[i + 0], reg[i + 1], reg[i + 2], reg[i + 3]); - i += 4; - wiphy_err(priv->hw->wiphy, - "CPSR: 0x%.8X, SPSR: 0x%.8X\n", - reg[i + 0], reg[i + 1]); - - print_hex_dump_bytes("R1: ", DUMP_PREFIX_NONE, - fname, sizeof(fname)); - return 0; - -underflow: - wiphy_err(priv->hw->wiphy, "Firmware exception.\n"); - print_hex_dump_bytes("Exception: ", DUMP_PREFIX_NONE, - data, len); - return -EINVAL; -} - -int wsm_handle_rx(struct cw1200_common *priv, u16 id, - struct wsm_hdr *wsm, struct sk_buff **skb_p) -{ - int ret = 0; - struct wsm_buf wsm_buf; - int link_id = (id >> 6) & 0x0F; - - /* Strip link id. */ - id &= ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); - - wsm_buf.begin = (u8 *)&wsm[0]; - wsm_buf.data = (u8 *)&wsm[1]; - wsm_buf.end = &wsm_buf.begin[__le16_to_cpu(wsm->len)]; - - pr_debug("[WSM] <<< 0x%.4X (%td)\n", id, - wsm_buf.end - wsm_buf.begin); - - if (id == WSM_TX_CONFIRM_IND_ID) { - ret = wsm_tx_confirm(priv, &wsm_buf, link_id); - } else if (id == WSM_MULTI_TX_CONFIRM_ID) { - ret = wsm_multi_tx_confirm(priv, &wsm_buf, link_id); - } else if (id & 0x0400) { - void *wsm_arg; - u16 wsm_cmd; - - /* Do not trust FW too much. Protection against repeated - * response and race condition removal (see above). - */ - spin_lock(&priv->wsm_cmd.lock); - wsm_arg = priv->wsm_cmd.arg; - wsm_cmd = priv->wsm_cmd.cmd & - ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); - priv->wsm_cmd.cmd = 0xFFFF; - spin_unlock(&priv->wsm_cmd.lock); - - if (WARN_ON((id & ~0x0400) != wsm_cmd)) { - /* Note that any non-zero is a fatal retcode. */ - ret = -EINVAL; - goto out; - } - - /* Note that wsm_arg can be NULL in case of timeout in - * wsm_cmd_send(). - */ - - switch (id) { - case WSM_READ_MIB_RESP_ID: - if (wsm_arg) - ret = wsm_read_mib_confirm(priv, wsm_arg, - &wsm_buf); - break; - case WSM_WRITE_MIB_RESP_ID: - if (wsm_arg) - ret = wsm_write_mib_confirm(priv, wsm_arg, - &wsm_buf); - break; - case WSM_START_SCAN_RESP_ID: - if (wsm_arg) - ret = wsm_scan_started(priv, wsm_arg, &wsm_buf); - break; - case WSM_CONFIGURATION_RESP_ID: - if (wsm_arg) - ret = wsm_configuration_confirm(priv, wsm_arg, - &wsm_buf); - break; - case WSM_JOIN_RESP_ID: - if (wsm_arg) - ret = wsm_join_confirm(priv, wsm_arg, &wsm_buf); - break; - case WSM_STOP_SCAN_RESP_ID: - case WSM_RESET_RESP_ID: - case WSM_ADD_KEY_RESP_ID: - case WSM_REMOVE_KEY_RESP_ID: - case WSM_SET_PM_RESP_ID: - case WSM_SET_BSS_PARAMS_RESP_ID: - case 0x0412: /* set_tx_queue_params */ - case WSM_EDCA_PARAMS_RESP_ID: - case WSM_SWITCH_CHANNEL_RESP_ID: - case WSM_START_RESP_ID: - case WSM_BEACON_TRANSMIT_RESP_ID: - case 0x0419: /* start_find */ - case 0x041A: /* stop_find */ - case 0x041B: /* update_ie */ - case 0x041C: /* map_link */ - WARN_ON(wsm_arg != NULL); - ret = wsm_generic_confirm(priv, wsm_arg, &wsm_buf); - if (ret) { - wiphy_warn(priv->hw->wiphy, - "wsm_generic_confirm failed for request 0x%04x.\n", - id & ~0x0400); - - /* often 0x407 and 0x410 occur, this means we're dead.. */ - if (priv->join_status >= CW1200_JOIN_STATUS_JOINING) { - wsm_lock_tx(priv); - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - } - } - break; - default: - wiphy_warn(priv->hw->wiphy, - "Unrecognized confirmation 0x%04x\n", - id & ~0x0400); - } - - spin_lock(&priv->wsm_cmd.lock); - priv->wsm_cmd.ret = ret; - priv->wsm_cmd.done = 1; - spin_unlock(&priv->wsm_cmd.lock); - - ret = 0; /* Error response from device should ne stop BH. */ - - wake_up(&priv->wsm_cmd_wq); - } else if (id & 0x0800) { - switch (id) { - case WSM_STARTUP_IND_ID: - ret = wsm_startup_indication(priv, &wsm_buf); - break; - case WSM_RECEIVE_IND_ID: - ret = wsm_receive_indication(priv, link_id, - &wsm_buf, skb_p); - break; - case 0x0805: - ret = wsm_event_indication(priv, &wsm_buf); - break; - case WSM_SCAN_COMPLETE_IND_ID: - ret = wsm_scan_complete_indication(priv, &wsm_buf); - break; - case 0x0808: - ret = wsm_ba_timeout_indication(priv, &wsm_buf); - break; - case 0x0809: - ret = wsm_set_pm_indication(priv, &wsm_buf); - break; - case 0x080A: - ret = wsm_channel_switch_indication(priv, &wsm_buf); - break; - case 0x080B: - ret = wsm_find_complete_indication(priv, &wsm_buf); - break; - case 0x080C: - ret = wsm_suspend_resume_indication(priv, - link_id, &wsm_buf); - break; - case 0x080F: - ret = wsm_join_complete_indication(priv, &wsm_buf); - break; - default: - pr_warn("Unrecognised WSM ID %04x\n", id); - } - } else { - WARN_ON(1); - ret = -EINVAL; - } -out: - return ret; -} - -static bool wsm_handle_tx_data(struct cw1200_common *priv, - struct wsm_tx *wsm, - const struct ieee80211_tx_info *tx_info, - const struct cw1200_txpriv *txpriv, - struct cw1200_queue *queue) -{ - bool handled = false; - const struct ieee80211_hdr *frame = - (struct ieee80211_hdr *)&((u8 *)wsm)[txpriv->offset]; - __le16 fctl = frame->frame_control; - enum { - do_probe, - do_drop, - do_wep, - do_tx, - } action = do_tx; - - switch (priv->mode) { - case NL80211_IFTYPE_STATION: - if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) - action = do_tx; - else if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) - action = do_drop; - break; - case NL80211_IFTYPE_AP: - if (!priv->join_status) { - action = do_drop; - } else if (!(BIT(txpriv->raw_link_id) & - (BIT(0) | priv->link_id_map))) { - wiphy_warn(priv->hw->wiphy, - "A frame with expired link id is dropped.\n"); - action = do_drop; - } - if (cw1200_queue_get_generation(wsm->packet_id) > - CW1200_MAX_REQUEUE_ATTEMPTS) { - /* HACK!!! WSM324 firmware has tendency to requeue - * multicast frames in a loop, causing performance - * drop and high power consumption of the driver. - * In this situation it is better just to drop - * the problematic frame. - */ - wiphy_warn(priv->hw->wiphy, - "Too many attempts to requeue a frame; dropped.\n"); - action = do_drop; - } - break; - case NL80211_IFTYPE_ADHOC: - if (priv->join_status != CW1200_JOIN_STATUS_IBSS) - action = do_drop; - break; - case NL80211_IFTYPE_MESH_POINT: - action = do_tx; /* TODO: Test me! */ - break; - case NL80211_IFTYPE_MONITOR: - default: - action = do_drop; - break; - } - - if (action == do_tx) { - if (ieee80211_is_nullfunc(fctl)) { - spin_lock(&priv->bss_loss_lock); - if (priv->bss_loss_state) { - priv->bss_loss_confirm_id = wsm->packet_id; - wsm->queue_id = WSM_QUEUE_VOICE; - } - spin_unlock(&priv->bss_loss_lock); - } else if (ieee80211_is_probe_req(fctl)) { - action = do_probe; - } else if (ieee80211_is_deauth(fctl) && - priv->mode != NL80211_IFTYPE_AP) { - pr_debug("[WSM] Issue unjoin command due to tx deauth.\n"); - wsm_lock_tx_async(priv); - if (queue_work(priv->workqueue, - &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - } else if (ieee80211_has_protected(fctl) && - tx_info->control.hw_key && - tx_info->control.hw_key->keyidx != priv->wep_default_key_id && - (tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 || - tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) { - action = do_wep; - } - } - - switch (action) { - case do_probe: - /* An interesting FW "feature". Device filters probe responses. - * The easiest way to get it back is to convert - * probe request into WSM start_scan command. - */ - pr_debug("[WSM] Convert probe request to scan.\n"); - wsm_lock_tx_async(priv); - priv->pending_frame_id = wsm->packet_id; - if (queue_delayed_work(priv->workqueue, - &priv->scan.probe_work, 0) <= 0) - wsm_unlock_tx(priv); - handled = true; - break; - case do_drop: - pr_debug("[WSM] Drop frame (0x%.4X).\n", fctl); - BUG_ON(cw1200_queue_remove(queue, wsm->packet_id)); - handled = true; - break; - case do_wep: - pr_debug("[WSM] Issue set_default_wep_key.\n"); - wsm_lock_tx_async(priv); - priv->wep_default_key_id = tx_info->control.hw_key->keyidx; - priv->pending_frame_id = wsm->packet_id; - if (queue_work(priv->workqueue, &priv->wep_key_work) <= 0) - wsm_unlock_tx(priv); - handled = true; - break; - case do_tx: - pr_debug("[WSM] Transmit frame.\n"); - break; - default: - /* Do nothing */ - break; - } - return handled; -} - -static int cw1200_get_prio_queue(struct cw1200_common *priv, - u32 link_id_map, int *total) -{ - static const int urgent = BIT(CW1200_LINK_ID_AFTER_DTIM) | - BIT(CW1200_LINK_ID_UAPSD); - struct wsm_edca_queue_params *edca; - unsigned score, best = -1; - int winner = -1; - int queued; - int i; - - /* search for a winner using edca params */ - for (i = 0; i < 4; ++i) { - queued = cw1200_queue_get_num_queued(&priv->tx_queue[i], - link_id_map); - if (!queued) - continue; - *total += queued; - edca = &priv->edca.params[i]; - score = ((edca->aifns + edca->cwmin) << 16) + - ((edca->cwmax - edca->cwmin) * - (get_random_int() & 0xFFFF)); - if (score < best && (winner < 0 || i != 3)) { - best = score; - winner = i; - } - } - - /* override winner if bursting */ - if (winner >= 0 && priv->tx_burst_idx >= 0 && - winner != priv->tx_burst_idx && - !cw1200_queue_get_num_queued( - &priv->tx_queue[winner], - link_id_map & urgent) && - cw1200_queue_get_num_queued( - &priv->tx_queue[priv->tx_burst_idx], - link_id_map)) - winner = priv->tx_burst_idx; - - return winner; -} - -static int wsm_get_tx_queue_and_mask(struct cw1200_common *priv, - struct cw1200_queue **queue_p, - u32 *tx_allowed_mask_p, - bool *more) -{ - int idx; - u32 tx_allowed_mask; - int total = 0; - - /* Search for a queue with multicast frames buffered */ - if (priv->tx_multicast) { - tx_allowed_mask = BIT(CW1200_LINK_ID_AFTER_DTIM); - idx = cw1200_get_prio_queue(priv, - tx_allowed_mask, &total); - if (idx >= 0) { - *more = total > 1; - goto found; - } - } - - /* Search for unicast traffic */ - tx_allowed_mask = ~priv->sta_asleep_mask; - tx_allowed_mask |= BIT(CW1200_LINK_ID_UAPSD); - if (priv->sta_asleep_mask) { - tx_allowed_mask |= priv->pspoll_mask; - tx_allowed_mask &= ~BIT(CW1200_LINK_ID_AFTER_DTIM); - } else { - tx_allowed_mask |= BIT(CW1200_LINK_ID_AFTER_DTIM); - } - idx = cw1200_get_prio_queue(priv, - tx_allowed_mask, &total); - if (idx < 0) - return -ENOENT; - -found: - *queue_p = &priv->tx_queue[idx]; - *tx_allowed_mask_p = tx_allowed_mask; - return 0; -} - -int wsm_get_tx(struct cw1200_common *priv, u8 **data, - size_t *tx_len, int *burst) -{ - struct wsm_tx *wsm = NULL; - struct ieee80211_tx_info *tx_info; - struct cw1200_queue *queue = NULL; - int queue_num; - u32 tx_allowed_mask = 0; - const struct cw1200_txpriv *txpriv = NULL; - int count = 0; - - /* More is used only for broadcasts. */ - bool more = false; - - if (priv->wsm_cmd.ptr) { /* CMD request */ - ++count; - spin_lock(&priv->wsm_cmd.lock); - BUG_ON(!priv->wsm_cmd.ptr); - *data = priv->wsm_cmd.ptr; - *tx_len = priv->wsm_cmd.len; - *burst = 1; - spin_unlock(&priv->wsm_cmd.lock); - } else { - for (;;) { - int ret; - - if (atomic_add_return(0, &priv->tx_lock)) - break; - - spin_lock_bh(&priv->ps_state_lock); - - ret = wsm_get_tx_queue_and_mask(priv, &queue, - &tx_allowed_mask, &more); - queue_num = queue - priv->tx_queue; - - if (priv->buffered_multicasts && - (ret || !more) && - (priv->tx_multicast || !priv->sta_asleep_mask)) { - priv->buffered_multicasts = false; - if (priv->tx_multicast) { - priv->tx_multicast = false; - queue_work(priv->workqueue, - &priv->multicast_stop_work); - } - } - - spin_unlock_bh(&priv->ps_state_lock); - - if (ret) - break; - - if (cw1200_queue_get(queue, - tx_allowed_mask, - &wsm, &tx_info, &txpriv)) - continue; - - if (wsm_handle_tx_data(priv, wsm, - tx_info, txpriv, queue)) - continue; /* Handled by WSM */ - - wsm->hdr.id &= __cpu_to_le16( - ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)); - wsm->hdr.id |= cpu_to_le16( - WSM_TX_LINK_ID(txpriv->raw_link_id)); - priv->pspoll_mask &= ~BIT(txpriv->raw_link_id); - - *data = (u8 *)wsm; - *tx_len = __le16_to_cpu(wsm->hdr.len); - - /* allow bursting if txop is set */ - if (priv->edca.params[queue_num].txop_limit) - *burst = min(*burst, - (int)cw1200_queue_get_num_queued(queue, tx_allowed_mask) + 1); - else - *burst = 1; - - /* store index of bursting queue */ - if (*burst > 1) - priv->tx_burst_idx = queue_num; - else - priv->tx_burst_idx = -1; - - if (more) { - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) - &((u8 *)wsm)[txpriv->offset]; - /* more buffered multicast/broadcast frames - * ==> set MoreData flag in IEEE 802.11 header - * to inform PS STAs - */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - pr_debug("[WSM] >>> 0x%.4X (%zu) %p %c\n", - 0x0004, *tx_len, *data, - wsm->more ? 'M' : ' '); - ++count; - break; - } - } - - return count; -} - -void wsm_txed(struct cw1200_common *priv, u8 *data) -{ - if (data == priv->wsm_cmd.ptr) { - spin_lock(&priv->wsm_cmd.lock); - priv->wsm_cmd.ptr = NULL; - spin_unlock(&priv->wsm_cmd.lock); - } -} - -/* ******************************************************************** */ -/* WSM buffer */ - -void wsm_buf_init(struct wsm_buf *buf) -{ - BUG_ON(buf->begin); - buf->begin = kmalloc(FWLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); - buf->end = buf->begin ? &buf->begin[FWLOAD_BLOCK_SIZE] : buf->begin; - wsm_buf_reset(buf); -} - -void wsm_buf_deinit(struct wsm_buf *buf) -{ - kfree(buf->begin); - buf->begin = buf->data = buf->end = NULL; -} - -static void wsm_buf_reset(struct wsm_buf *buf) -{ - if (buf->begin) { - buf->data = &buf->begin[4]; - *(u32 *)buf->begin = 0; - } else { - buf->data = buf->begin; - } -} - -static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size) -{ - size_t pos = buf->data - buf->begin; - size_t size = pos + extra_size; - - size = round_up(size, FWLOAD_BLOCK_SIZE); - - buf->begin = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA); - if (buf->begin) { - buf->data = &buf->begin[pos]; - buf->end = &buf->begin[size]; - return 0; - } else { - buf->end = buf->data = buf->begin; - return -ENOMEM; - } -} diff --git a/drivers/net/wireless/cw1200/wsm.h b/drivers/net/wireless/cw1200/wsm.h deleted file mode 100644 index 48086e8..0000000 --- a/drivers/net/wireless/cw1200/wsm.h +++ /dev/null @@ -1,1870 +0,0 @@ -/* - * WSM host interface (HI) interface for ST-Ericsson CW1200 mac80211 drivers - * - * Copyright (c) 2010, ST-Ericsson - * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> - * - * Based on CW1200 UMAC WSM API, which is - * Copyright (C) ST-Ericsson SA 2010 - * Author: Stewart Mathers <stewart.mathers@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CW1200_WSM_H_INCLUDED -#define CW1200_WSM_H_INCLUDED - -#include <linux/spinlock.h> - -struct cw1200_common; - -/* Bands */ -/* Radio band 2.412 -2.484 GHz. */ -#define WSM_PHY_BAND_2_4G (0) - -/* Radio band 4.9375-5.8250 GHz. */ -#define WSM_PHY_BAND_5G (1) - -/* Transmit rates */ -/* 1 Mbps ERP-DSSS */ -#define WSM_TRANSMIT_RATE_1 (0) - -/* 2 Mbps ERP-DSSS */ -#define WSM_TRANSMIT_RATE_2 (1) - -/* 5.5 Mbps ERP-CCK */ -#define WSM_TRANSMIT_RATE_5 (2) - -/* 11 Mbps ERP-CCK */ -#define WSM_TRANSMIT_RATE_11 (3) - -/* 22 Mbps ERP-PBCC (Not supported) */ -/* #define WSM_TRANSMIT_RATE_22 (4) */ - -/* 33 Mbps ERP-PBCC (Not supported) */ -/* #define WSM_TRANSMIT_RATE_33 (5) */ - -/* 6 Mbps (3 Mbps) ERP-OFDM, BPSK coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_6 (6) - -/* 9 Mbps (4.5 Mbps) ERP-OFDM, BPSK coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_9 (7) - -/* 12 Mbps (6 Mbps) ERP-OFDM, QPSK coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_12 (8) - -/* 18 Mbps (9 Mbps) ERP-OFDM, QPSK coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_18 (9) - -/* 24 Mbps (12 Mbps) ERP-OFDM, 16QAM coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_24 (10) - -/* 36 Mbps (18 Mbps) ERP-OFDM, 16QAM coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_36 (11) - -/* 48 Mbps (24 Mbps) ERP-OFDM, 64QAM coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_48 (12) - -/* 54 Mbps (27 Mbps) ERP-OFDM, 64QAM coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_54 (13) - -/* 6.5 Mbps HT-OFDM, BPSK coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_HT_6 (14) - -/* 13 Mbps HT-OFDM, QPSK coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_HT_13 (15) - -/* 19.5 Mbps HT-OFDM, QPSK coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_HT_19 (16) - -/* 26 Mbps HT-OFDM, 16QAM coding rate 1/2 */ -#define WSM_TRANSMIT_RATE_HT_26 (17) - -/* 39 Mbps HT-OFDM, 16QAM coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_HT_39 (18) - -/* 52 Mbps HT-OFDM, 64QAM coding rate 2/3 */ -#define WSM_TRANSMIT_RATE_HT_52 (19) - -/* 58.5 Mbps HT-OFDM, 64QAM coding rate 3/4 */ -#define WSM_TRANSMIT_RATE_HT_58 (20) - -/* 65 Mbps HT-OFDM, 64QAM coding rate 5/6 */ -#define WSM_TRANSMIT_RATE_HT_65 (21) - -/* Scan types */ -/* Foreground scan */ -#define WSM_SCAN_TYPE_FOREGROUND (0) - -/* Background scan */ -#define WSM_SCAN_TYPE_BACKGROUND (1) - -/* Auto scan */ -#define WSM_SCAN_TYPE_AUTO (2) - -/* Scan flags */ -/* Forced background scan means if the station cannot */ -/* enter the power-save mode, it shall force to perform a */ -/* background scan. Only valid when ScanType is */ -/* background scan. */ -#define WSM_SCAN_FLAG_FORCE_BACKGROUND (BIT(0)) - -/* The WLAN device scans one channel at a time so */ -/* that disturbance to the data traffic is minimized. */ -#define WSM_SCAN_FLAG_SPLIT_METHOD (BIT(1)) - -/* Preamble Type. Long if not set. */ -#define WSM_SCAN_FLAG_SHORT_PREAMBLE (BIT(2)) - -/* 11n Tx Mode. Mixed if not set. */ -#define WSM_SCAN_FLAG_11N_GREENFIELD (BIT(3)) - -/* Scan constraints */ -/* Maximum number of channels to be scanned. */ -#define WSM_SCAN_MAX_NUM_OF_CHANNELS (48) - -/* The maximum number of SSIDs that the device can scan for. */ -#define WSM_SCAN_MAX_NUM_OF_SSIDS (2) - -/* Power management modes */ -/* 802.11 Active mode */ -#define WSM_PSM_ACTIVE (0) - -/* 802.11 PS mode */ -#define WSM_PSM_PS BIT(0) - -/* Fast Power Save bit */ -#define WSM_PSM_FAST_PS_FLAG BIT(7) - -/* Dynamic aka Fast power save */ -#define WSM_PSM_FAST_PS (BIT(0) | BIT(7)) - -/* Undetermined */ -/* Note : Undetermined status is reported when the */ -/* NULL data frame used to advertise the PM mode to */ -/* the AP at Pre or Post Background Scan is not Acknowledged */ -#define WSM_PSM_UNKNOWN BIT(1) - -/* Queue IDs */ -/* best effort/legacy */ -#define WSM_QUEUE_BEST_EFFORT (0) - -/* background */ -#define WSM_QUEUE_BACKGROUND (1) - -/* video */ -#define WSM_QUEUE_VIDEO (2) - -/* voice */ -#define WSM_QUEUE_VOICE (3) - -/* HT TX parameters */ -/* Non-HT */ -#define WSM_HT_TX_NON_HT (0) - -/* Mixed format */ -#define WSM_HT_TX_MIXED (1) - -/* Greenfield format */ -#define WSM_HT_TX_GREENFIELD (2) - -/* STBC allowed */ -#define WSM_HT_TX_STBC (BIT(7)) - -/* EPTA prioirty flags for BT Coex */ -/* default epta priority */ -#define WSM_EPTA_PRIORITY_DEFAULT 4 -/* use for normal data */ -#define WSM_EPTA_PRIORITY_DATA 4 -/* use for connect/disconnect/roaming*/ -#define WSM_EPTA_PRIORITY_MGT 5 -/* use for action frames */ -#define WSM_EPTA_PRIORITY_ACTION 5 -/* use for AC_VI data */ -#define WSM_EPTA_PRIORITY_VIDEO 5 -/* use for AC_VO data */ -#define WSM_EPTA_PRIORITY_VOICE 6 -/* use for EAPOL exchange */ -#define WSM_EPTA_PRIORITY_EAPOL 7 - -/* TX status */ -/* Frame was sent aggregated */ -/* Only valid for WSM_SUCCESS status. */ -#define WSM_TX_STATUS_AGGREGATION (BIT(0)) - -/* Host should requeue this frame later. */ -/* Valid only when status is WSM_REQUEUE. */ -#define WSM_TX_STATUS_REQUEUE (BIT(1)) - -/* Normal Ack */ -#define WSM_TX_STATUS_NORMAL_ACK (0<<2) - -/* No Ack */ -#define WSM_TX_STATUS_NO_ACK (1<<2) - -/* No explicit acknowledgement */ -#define WSM_TX_STATUS_NO_EXPLICIT_ACK (2<<2) - -/* Block Ack */ -/* Only valid for WSM_SUCCESS status. */ -#define WSM_TX_STATUS_BLOCK_ACK (3<<2) - -/* RX status */ -/* Unencrypted */ -#define WSM_RX_STATUS_UNENCRYPTED (0<<0) - -/* WEP */ -#define WSM_RX_STATUS_WEP (1<<0) - -/* TKIP */ -#define WSM_RX_STATUS_TKIP (2<<0) - -/* AES */ -#define WSM_RX_STATUS_AES (3<<0) - -/* WAPI */ -#define WSM_RX_STATUS_WAPI (4<<0) - -/* Macro to fetch encryption subfield. */ -#define WSM_RX_STATUS_ENCRYPTION(status) ((status) & 0x07) - -/* Frame was part of an aggregation */ -#define WSM_RX_STATUS_AGGREGATE (BIT(3)) - -/* Frame was first in the aggregation */ -#define WSM_RX_STATUS_AGGREGATE_FIRST (BIT(4)) - -/* Frame was last in the aggregation */ -#define WSM_RX_STATUS_AGGREGATE_LAST (BIT(5)) - -/* Indicates a defragmented frame */ -#define WSM_RX_STATUS_DEFRAGMENTED (BIT(6)) - -/* Indicates a Beacon frame */ -#define WSM_RX_STATUS_BEACON (BIT(7)) - -/* Indicates STA bit beacon TIM field */ -#define WSM_RX_STATUS_TIM (BIT(8)) - -/* Indicates Beacon frame's virtual bitmap contains multicast bit */ -#define WSM_RX_STATUS_MULTICAST (BIT(9)) - -/* Indicates frame contains a matching SSID */ -#define WSM_RX_STATUS_MATCHING_SSID (BIT(10)) - -/* Indicates frame contains a matching BSSI */ -#define WSM_RX_STATUS_MATCHING_BSSI (BIT(11)) - -/* Indicates More bit set in Framectl field */ -#define WSM_RX_STATUS_MORE_DATA (BIT(12)) - -/* Indicates frame received during a measurement process */ -#define WSM_RX_STATUS_MEASUREMENT (BIT(13)) - -/* Indicates frame received as an HT packet */ -#define WSM_RX_STATUS_HT (BIT(14)) - -/* Indicates frame received with STBC */ -#define WSM_RX_STATUS_STBC (BIT(15)) - -/* Indicates Address 1 field matches dot11StationId */ -#define WSM_RX_STATUS_ADDRESS1 (BIT(16)) - -/* Indicates Group address present in the Address 1 field */ -#define WSM_RX_STATUS_GROUP (BIT(17)) - -/* Indicates Broadcast address present in the Address 1 field */ -#define WSM_RX_STATUS_BROADCAST (BIT(18)) - -/* Indicates group key used with encrypted frames */ -#define WSM_RX_STATUS_GROUP_KEY (BIT(19)) - -/* Macro to fetch encryption key index. */ -#define WSM_RX_STATUS_KEY_IDX(status) (((status >> 20)) & 0x0F) - -/* Indicates TSF inclusion after 802.11 frame body */ -#define WSM_RX_STATUS_TSF_INCLUDED (BIT(24)) - -/* Frame Control field starts at Frame offset + 2 */ -#define WSM_TX_2BYTES_SHIFT (BIT(7)) - -/* Join mode */ -/* IBSS */ -#define WSM_JOIN_MODE_IBSS (0) - -/* BSS */ -#define WSM_JOIN_MODE_BSS (1) - -/* PLCP preamble type */ -/* For long preamble */ -#define WSM_JOIN_PREAMBLE_LONG (0) - -/* For short preamble (Long for 1Mbps) */ -#define WSM_JOIN_PREAMBLE_SHORT (1) - -/* For short preamble (Long for 1 and 2Mbps) */ -#define WSM_JOIN_PREAMBLE_SHORT_2 (2) - -/* Join flags */ -/* Unsynchronized */ -#define WSM_JOIN_FLAGS_UNSYNCRONIZED BIT(0) -/* The BSS owner is a P2P GO */ -#define WSM_JOIN_FLAGS_P2P_GO BIT(1) -/* Force to join BSS with the BSSID and the - * SSID specified without waiting for beacons. The - * ProbeForJoin parameter is ignored. - */ -#define WSM_JOIN_FLAGS_FORCE BIT(2) -/* Give probe request/response higher - * priority over the BT traffic - */ -#define WSM_JOIN_FLAGS_PRIO BIT(3) -/* Issue immediate join confirmation and use - * join complete to notify about completion - */ -#define WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND BIT(5) - -/* Key types */ -#define WSM_KEY_TYPE_WEP_DEFAULT (0) -#define WSM_KEY_TYPE_WEP_PAIRWISE (1) -#define WSM_KEY_TYPE_TKIP_GROUP (2) -#define WSM_KEY_TYPE_TKIP_PAIRWISE (3) -#define WSM_KEY_TYPE_AES_GROUP (4) -#define WSM_KEY_TYPE_AES_PAIRWISE (5) -#define WSM_KEY_TYPE_WAPI_GROUP (6) -#define WSM_KEY_TYPE_WAPI_PAIRWISE (7) - -/* Key indexes */ -#define WSM_KEY_MAX_INDEX (10) - -/* ACK policy */ -#define WSM_ACK_POLICY_NORMAL (0) -#define WSM_ACK_POLICY_NO_ACK (1) - -/* Start modes */ -#define WSM_START_MODE_AP (0) /* Mini AP */ -#define WSM_START_MODE_P2P_GO (1) /* P2P GO */ -#define WSM_START_MODE_P2P_DEV (2) /* P2P device */ - -/* SetAssociationMode MIB flags */ -#define WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE (BIT(0)) -#define WSM_ASSOCIATION_MODE_USE_HT_MODE (BIT(1)) -#define WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET (BIT(2)) -#define WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING (BIT(3)) -#define WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES (BIT(4)) - -/* RcpiRssiThreshold MIB flags */ -#define WSM_RCPI_RSSI_THRESHOLD_ENABLE (BIT(0)) -#define WSM_RCPI_RSSI_USE_RSSI (BIT(1)) -#define WSM_RCPI_RSSI_DONT_USE_UPPER (BIT(2)) -#define WSM_RCPI_RSSI_DONT_USE_LOWER (BIT(3)) - -/* Update-ie constants */ -#define WSM_UPDATE_IE_BEACON (BIT(0)) -#define WSM_UPDATE_IE_PROBE_RESP (BIT(1)) -#define WSM_UPDATE_IE_PROBE_REQ (BIT(2)) - -/* WSM events */ -/* Error */ -#define WSM_EVENT_ERROR (0) - -/* BSS lost */ -#define WSM_EVENT_BSS_LOST (1) - -/* BSS regained */ -#define WSM_EVENT_BSS_REGAINED (2) - -/* Radar detected */ -#define WSM_EVENT_RADAR_DETECTED (3) - -/* RCPI or RSSI threshold triggered */ -#define WSM_EVENT_RCPI_RSSI (4) - -/* BT inactive */ -#define WSM_EVENT_BT_INACTIVE (5) - -/* BT active */ -#define WSM_EVENT_BT_ACTIVE (6) - -/* MIB IDs */ -/* 4.1 dot11StationId */ -#define WSM_MIB_ID_DOT11_STATION_ID 0x0000 - -/* 4.2 dot11MaxtransmitMsduLifeTime */ -#define WSM_MIB_ID_DOT11_MAX_TRANSMIT_LIFTIME 0x0001 - -/* 4.3 dot11MaxReceiveLifeTime */ -#define WSM_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME 0x0002 - -/* 4.4 dot11SlotTime */ -#define WSM_MIB_ID_DOT11_SLOT_TIME 0x0003 - -/* 4.5 dot11GroupAddressesTable */ -#define WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE 0x0004 -#define WSM_MAX_GRP_ADDRTABLE_ENTRIES 8 - -/* 4.6 dot11WepDefaultKeyId */ -#define WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID 0x0005 - -/* 4.7 dot11CurrentTxPowerLevel */ -#define WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL 0x0006 - -/* 4.8 dot11RTSThreshold */ -#define WSM_MIB_ID_DOT11_RTS_THRESHOLD 0x0007 - -/* 4.9 NonErpProtection */ -#define WSM_MIB_ID_NON_ERP_PROTECTION 0x1000 - -/* 4.10 ArpIpAddressesTable */ -#define WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE 0x1001 -#define WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES 1 - -/* 4.11 TemplateFrame */ -#define WSM_MIB_ID_TEMPLATE_FRAME 0x1002 - -/* 4.12 RxFilter */ -#define WSM_MIB_ID_RX_FILTER 0x1003 - -/* 4.13 BeaconFilterTable */ -#define WSM_MIB_ID_BEACON_FILTER_TABLE 0x1004 - -/* 4.14 BeaconFilterEnable */ -#define WSM_MIB_ID_BEACON_FILTER_ENABLE 0x1005 - -/* 4.15 OperationalPowerMode */ -#define WSM_MIB_ID_OPERATIONAL_POWER_MODE 0x1006 - -/* 4.16 BeaconWakeUpPeriod */ -#define WSM_MIB_ID_BEACON_WAKEUP_PERIOD 0x1007 - -/* 4.17 RcpiRssiThreshold */ -#define WSM_MIB_ID_RCPI_RSSI_THRESHOLD 0x1009 - -/* 4.18 StatisticsTable */ -#define WSM_MIB_ID_STATISTICS_TABLE 0x100A - -/* 4.19 IbssPsConfig */ -#define WSM_MIB_ID_IBSS_PS_CONFIG 0x100B - -/* 4.20 CountersTable */ -#define WSM_MIB_ID_COUNTERS_TABLE 0x100C - -/* 4.21 BlockAckPolicy */ -#define WSM_MIB_ID_BLOCK_ACK_POLICY 0x100E - -/* 4.22 OverrideInternalTxRate */ -#define WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE 0x100F - -/* 4.23 SetAssociationMode */ -#define WSM_MIB_ID_SET_ASSOCIATION_MODE 0x1010 - -/* 4.24 UpdateEptaConfigData */ -#define WSM_MIB_ID_UPDATE_EPTA_CONFIG_DATA 0x1011 - -/* 4.25 SelectCcaMethod */ -#define WSM_MIB_ID_SELECT_CCA_METHOD 0x1012 - -/* 4.26 SetUpasdInformation */ -#define WSM_MIB_ID_SET_UAPSD_INFORMATION 0x1013 - -/* 4.27 SetAutoCalibrationMode WBF00004073 */ -#define WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE 0x1015 - -/* 4.28 SetTxRateRetryPolicy */ -#define WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY 0x1016 - -/* 4.29 SetHostMessageTypeFilter */ -#define WSM_MIB_ID_SET_HOST_MSG_TYPE_FILTER 0x1017 - -/* 4.30 P2PFindInfo */ -#define WSM_MIB_ID_P2P_FIND_INFO 0x1018 - -/* 4.31 P2PPsModeInfo */ -#define WSM_MIB_ID_P2P_PS_MODE_INFO 0x1019 - -/* 4.32 SetEtherTypeDataFrameFilter */ -#define WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER 0x101A - -/* 4.33 SetUDPPortDataFrameFilter */ -#define WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER 0x101B - -/* 4.34 SetMagicDataFrameFilter */ -#define WSM_MIB_ID_SET_MAGIC_DATAFRAME_FILTER 0x101C - -/* 4.35 P2PDeviceInfo */ -#define WSM_MIB_ID_P2P_DEVICE_INFO 0x101D - -/* 4.36 SetWCDMABand */ -#define WSM_MIB_ID_SET_WCDMA_BAND 0x101E - -/* 4.37 GroupTxSequenceCounter */ -#define WSM_MIB_ID_GRP_SEQ_COUNTER 0x101F - -/* 4.38 ProtectedMgmtPolicy */ -#define WSM_MIB_ID_PROTECTED_MGMT_POLICY 0x1020 - -/* 4.39 SetHtProtection */ -#define WSM_MIB_ID_SET_HT_PROTECTION 0x1021 - -/* 4.40 GPIO Command */ -#define WSM_MIB_ID_GPIO_COMMAND 0x1022 - -/* 4.41 TSF Counter Value */ -#define WSM_MIB_ID_TSF_COUNTER 0x1023 - -/* Test Purposes Only */ -#define WSM_MIB_ID_BLOCK_ACK_INFO 0x100D - -/* 4.42 UseMultiTxConfMessage */ -#define WSM_MIB_USE_MULTI_TX_CONF 0x1024 - -/* 4.43 Keep-alive period */ -#define WSM_MIB_ID_KEEP_ALIVE_PERIOD 0x1025 - -/* 4.44 Disable BSSID filter */ -#define WSM_MIB_ID_DISABLE_BSSID_FILTER 0x1026 - -/* Frame template types */ -#define WSM_FRAME_TYPE_PROBE_REQUEST (0) -#define WSM_FRAME_TYPE_BEACON (1) -#define WSM_FRAME_TYPE_NULL (2) -#define WSM_FRAME_TYPE_QOS_NULL (3) -#define WSM_FRAME_TYPE_PS_POLL (4) -#define WSM_FRAME_TYPE_PROBE_RESPONSE (5) - -#define WSM_FRAME_GREENFIELD (0x80) /* See 4.11 */ - -/* Status */ -/* The WSM firmware has completed a request */ -/* successfully. */ -#define WSM_STATUS_SUCCESS (0) - -/* This is a generic failure code if other error codes do */ -/* not apply. */ -#define WSM_STATUS_FAILURE (1) - -/* A request contains one or more invalid parameters. */ -#define WSM_INVALID_PARAMETER (2) - -/* The request cannot perform because the device is in */ -/* an inappropriate mode. */ -#define WSM_ACCESS_DENIED (3) - -/* The frame received includes a decryption error. */ -#define WSM_STATUS_DECRYPTFAILURE (4) - -/* A MIC failure is detected in the received packets. */ -#define WSM_STATUS_MICFAILURE (5) - -/* The transmit request failed due to retry limit being */ -/* exceeded. */ -#define WSM_STATUS_RETRY_EXCEEDED (6) - -/* The transmit request failed due to MSDU life time */ -/* being exceeded. */ -#define WSM_STATUS_TX_LIFETIME_EXCEEDED (7) - -/* The link to the AP is lost. */ -#define WSM_STATUS_LINK_LOST (8) - -/* No key was found for the encrypted frame */ -#define WSM_STATUS_NO_KEY_FOUND (9) - -/* Jammer was detected when transmitting this frame */ -#define WSM_STATUS_JAMMER_DETECTED (10) - -/* The message should be requeued later. */ -/* This is applicable only to Transmit */ -#define WSM_REQUEUE (11) - -/* Advanced filtering options */ -#define WSM_MAX_FILTER_ELEMENTS (4) - -#define WSM_FILTER_ACTION_IGNORE (0) -#define WSM_FILTER_ACTION_FILTER_IN (1) -#define WSM_FILTER_ACTION_FILTER_OUT (2) - -#define WSM_FILTER_PORT_TYPE_DST (0) -#define WSM_FILTER_PORT_TYPE_SRC (1) - -/* Actual header of WSM messages */ -struct wsm_hdr { - __le16 len; - __le16 id; -}; - -#define WSM_TX_SEQ_MAX (7) -#define WSM_TX_SEQ(seq) \ - ((seq & WSM_TX_SEQ_MAX) << 13) -#define WSM_TX_LINK_ID_MAX (0x0F) -#define WSM_TX_LINK_ID(link_id) \ - ((link_id & WSM_TX_LINK_ID_MAX) << 6) - -#define MAX_BEACON_SKIP_TIME_MS 1000 - -#define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 3 / 2) - -/* ******************************************************************** */ -/* WSM capability */ - -#define WSM_STARTUP_IND_ID 0x0801 - -struct wsm_startup_ind { - u16 input_buffers; - u16 input_buffer_size; - u16 status; - u16 hw_id; - u16 hw_subid; - u16 fw_cap; - u16 fw_type; - u16 fw_api; - u16 fw_build; - u16 fw_ver; - char fw_label[128]; - u32 config[4]; -}; - -/* ******************************************************************** */ -/* WSM commands */ - -/* 3.1 */ -#define WSM_CONFIGURATION_REQ_ID 0x0009 -#define WSM_CONFIGURATION_RESP_ID 0x0409 - -struct wsm_tx_power_range { - int min_power_level; - int max_power_level; - u32 stepping; -}; - -struct wsm_configuration { - /* [in] */ u32 dot11MaxTransmitMsduLifeTime; - /* [in] */ u32 dot11MaxReceiveLifeTime; - /* [in] */ u32 dot11RtsThreshold; - /* [in, out] */ u8 *dot11StationId; - /* [in] */ const void *dpdData; - /* [in] */ size_t dpdData_size; - /* [out] */ u8 dot11FrequencyBandsSupported; - /* [out] */ u32 supportedRateMask; - /* [out] */ struct wsm_tx_power_range txPowerRange[2]; -}; - -int wsm_configuration(struct cw1200_common *priv, - struct wsm_configuration *arg); - -/* 3.3 */ -#define WSM_RESET_REQ_ID 0x000A -#define WSM_RESET_RESP_ID 0x040A -struct wsm_reset { - /* [in] */ int link_id; - /* [in] */ bool reset_statistics; -}; - -int wsm_reset(struct cw1200_common *priv, const struct wsm_reset *arg); - -/* 3.5 */ -#define WSM_READ_MIB_REQ_ID 0x0005 -#define WSM_READ_MIB_RESP_ID 0x0405 -int wsm_read_mib(struct cw1200_common *priv, u16 mib_id, void *buf, - size_t buf_size); - -/* 3.7 */ -#define WSM_WRITE_MIB_REQ_ID 0x0006 -#define WSM_WRITE_MIB_RESP_ID 0x0406 -int wsm_write_mib(struct cw1200_common *priv, u16 mib_id, void *buf, - size_t buf_size); - -/* 3.9 */ -#define WSM_START_SCAN_REQ_ID 0x0007 -#define WSM_START_SCAN_RESP_ID 0x0407 - -struct wsm_ssid { - u8 ssid[32]; - u32 length; -}; - -struct wsm_scan_ch { - u16 number; - u32 min_chan_time; - u32 max_chan_time; - u32 tx_power_level; -}; - -struct wsm_scan { - /* WSM_PHY_BAND_... */ - u8 band; - - /* WSM_SCAN_TYPE_... */ - u8 type; - - /* WSM_SCAN_FLAG_... */ - u8 flags; - - /* WSM_TRANSMIT_RATE_... */ - u8 max_tx_rate; - - /* Interval period in TUs that the device shall the re- */ - /* execute the requested scan. Max value supported by the device */ - /* is 256s. */ - u32 auto_scan_interval; - - /* Number of probe requests (per SSID) sent to one (1) */ - /* channel. Zero (0) means that none is send, which */ - /* means that a passive scan is to be done. Value */ - /* greater than zero (0) means that an active scan is to */ - /* be done. */ - u32 num_probes; - - /* Number of channels to be scanned. */ - /* Maximum value is WSM_SCAN_MAX_NUM_OF_CHANNELS. */ - u8 num_channels; - - /* Number of SSID provided in the scan command (this */ - /* is zero (0) in broadcast scan) */ - /* The maximum number of SSIDs is WSM_SCAN_MAX_NUM_OF_SSIDS. */ - u8 num_ssids; - - /* The delay time (in microseconds) period */ - /* before sending a probe-request. */ - u8 probe_delay; - - /* SSIDs to be scanned [numOfSSIDs]; */ - struct wsm_ssid *ssids; - - /* Channels to be scanned [numOfChannels]; */ - struct wsm_scan_ch *ch; -}; - -int wsm_scan(struct cw1200_common *priv, const struct wsm_scan *arg); - -/* 3.11 */ -#define WSM_STOP_SCAN_REQ_ID 0x0008 -#define WSM_STOP_SCAN_RESP_ID 0x0408 -int wsm_stop_scan(struct cw1200_common *priv); - -/* 3.13 */ -#define WSM_SCAN_COMPLETE_IND_ID 0x0806 -struct wsm_scan_complete { - /* WSM_STATUS_... */ - u32 status; - - /* WSM_PSM_... */ - u8 psm; - - /* Number of channels that the scan operation completed. */ - u8 num_channels; -}; - -/* 3.14 */ -#define WSM_TX_CONFIRM_IND_ID 0x0404 -#define WSM_MULTI_TX_CONFIRM_ID 0x041E - -struct wsm_tx_confirm { - /* Packet identifier used in wsm_tx. */ - u32 packet_id; - - /* WSM_STATUS_... */ - u32 status; - - /* WSM_TRANSMIT_RATE_... */ - u8 tx_rate; - - /* The number of times the frame was transmitted */ - /* without receiving an acknowledgement. */ - u8 ack_failures; - - /* WSM_TX_STATUS_... */ - u16 flags; - - /* The total time in microseconds that the frame spent in */ - /* the WLAN device before transmission as completed. */ - u32 media_delay; - - /* The total time in microseconds that the frame spent in */ - /* the WLAN device before transmission was started. */ - u32 tx_queue_delay; -}; - -/* 3.15 */ -typedef void (*wsm_tx_confirm_cb) (struct cw1200_common *priv, - struct wsm_tx_confirm *arg); - -/* Note that ideology of wsm_tx struct is different against the rest of - * WSM API. wsm_hdr is /not/ a caller-adapted struct to be used as an input - * argument for WSM call, but a prepared bytestream to be sent to firmware. - * It is filled partly in cw1200_tx, partly in low-level WSM code. - * Please pay attention once again: ideology is different. - * - * Legend: - * - [in]: cw1200_tx must fill this field. - * - [wsm]: the field is filled by low-level WSM. - */ -struct wsm_tx { - /* common WSM header */ - struct wsm_hdr hdr; - - /* Packet identifier that meant to be used in completion. */ - u32 packet_id; /* Note this is actually a cookie */ - - /* WSM_TRANSMIT_RATE_... */ - u8 max_tx_rate; - - /* WSM_QUEUE_... */ - u8 queue_id; - - /* True: another packet is pending on the host for transmission. */ - u8 more; - - /* Bit 0 = 0 - Start expiry time from first Tx attempt (default) */ - /* Bit 0 = 1 - Start expiry time from receipt of Tx Request */ - /* Bits 3:1 - PTA Priority */ - /* Bits 6:4 - Tx Rate Retry Policy */ - /* Bit 7 - Reserved */ - u8 flags; - - /* Should be 0. */ - u32 reserved; - - /* The elapsed time in TUs, after the initial transmission */ - /* of an MSDU, after which further attempts to transmit */ - /* the MSDU shall be terminated. Overrides the global */ - /* dot11MaxTransmitMsduLifeTime setting [optional] */ - /* Device will set the default value if this is 0. */ - __le32 expire_time; - - /* WSM_HT_TX_... */ - __le32 ht_tx_parameters; -} __packed; - -/* = sizeof(generic hi hdr) + sizeof(wsm hdr) + sizeof(alignment) */ -#define WSM_TX_EXTRA_HEADROOM (28) - -/* 3.16 */ -#define WSM_RECEIVE_IND_ID 0x0804 - -struct wsm_rx { - /* WSM_STATUS_... */ - u32 status; - - /* Specifies the channel of the received packet. */ - u16 channel_number; - - /* WSM_TRANSMIT_RATE_... */ - u8 rx_rate; - - /* This value is expressed in signed Q8.0 format for */ - /* RSSI and unsigned Q7.1 format for RCPI. */ - u8 rcpi_rssi; - - /* WSM_RX_STATUS_... */ - u32 flags; -}; - -/* = sizeof(generic hi hdr) + sizeof(wsm hdr) */ -#define WSM_RX_EXTRA_HEADROOM (16) - -typedef void (*wsm_rx_cb) (struct cw1200_common *priv, struct wsm_rx *arg, - struct sk_buff **skb_p); - -/* 3.17 */ -struct wsm_event { - /* WSM_STATUS_... */ - /* [out] */ u32 id; - - /* Indication parameters. */ - /* For error indication, this shall be a 32-bit WSM status. */ - /* For RCPI or RSSI indication, this should be an 8-bit */ - /* RCPI or RSSI value. */ - /* [out] */ u32 data; -}; - -struct cw1200_wsm_event { - struct list_head link; - struct wsm_event evt; -}; - -/* 3.18 - 3.22 */ -/* Measurement. Skipped for now. Irrelevent. */ - -typedef void (*wsm_event_cb) (struct cw1200_common *priv, - struct wsm_event *arg); - -/* 3.23 */ -#define WSM_JOIN_REQ_ID 0x000B -#define WSM_JOIN_RESP_ID 0x040B - -struct wsm_join { - /* WSM_JOIN_MODE_... */ - u8 mode; - - /* WSM_PHY_BAND_... */ - u8 band; - - /* Specifies the channel number to join. The channel */ - /* number will be mapped to an actual frequency */ - /* according to the band */ - u16 channel_number; - - /* Specifies the BSSID of the BSS or IBSS to be joined */ - /* or the IBSS to be started. */ - u8 bssid[6]; - - /* ATIM window of IBSS */ - /* When ATIM window is zero the initiated IBSS does */ - /* not support power saving. */ - u16 atim_window; - - /* WSM_JOIN_PREAMBLE_... */ - u8 preamble_type; - - /* Specifies if a probe request should be send with the */ - /* specified SSID when joining to the network. */ - u8 probe_for_join; - - /* DTIM Period (In multiples of beacon interval) */ - u8 dtim_period; - - /* WSM_JOIN_FLAGS_... */ - u8 flags; - - /* Length of the SSID */ - u32 ssid_len; - - /* Specifies the SSID of the IBSS to join or start */ - u8 ssid[32]; - - /* Specifies the time between TBTTs in TUs */ - u32 beacon_interval; - - /* A bit mask that defines the BSS basic rate set. */ - u32 basic_rate_set; -}; - -struct wsm_join_cnf { - u32 status; - - /* Minimum transmission power level in units of 0.1dBm */ - u32 min_power_level; - - /* Maximum transmission power level in units of 0.1dBm */ - u32 max_power_level; -}; - -int wsm_join(struct cw1200_common *priv, struct wsm_join *arg); - -/* 3.24 */ -struct wsm_join_complete { - /* WSM_STATUS_... */ - u32 status; -}; - -/* 3.25 */ -#define WSM_SET_PM_REQ_ID 0x0010 -#define WSM_SET_PM_RESP_ID 0x0410 -struct wsm_set_pm { - /* WSM_PSM_... */ - u8 mode; - - /* in unit of 500us; 0 to use default */ - u8 fast_psm_idle_period; - - /* in unit of 500us; 0 to use default */ - u8 ap_psm_change_period; - - /* in unit of 500us; 0 to disable auto-pspoll */ - u8 min_auto_pspoll_period; -}; - -int wsm_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg); - -/* 3.27 */ -struct wsm_set_pm_complete { - u8 psm; /* WSM_PSM_... */ -}; - -/* 3.28 */ -#define WSM_SET_BSS_PARAMS_REQ_ID 0x0011 -#define WSM_SET_BSS_PARAMS_RESP_ID 0x0411 -struct wsm_set_bss_params { - /* This resets the beacon loss counters only */ - u8 reset_beacon_loss; - - /* The number of lost consecutive beacons after which */ - /* the WLAN device should indicate the BSS-Lost event */ - /* to the WLAN host driver. */ - u8 beacon_lost_count; - - /* The AID received during the association process. */ - u16 aid; - - /* The operational rate set mask */ - u32 operational_rate_set; -}; - -int wsm_set_bss_params(struct cw1200_common *priv, - const struct wsm_set_bss_params *arg); - -/* 3.30 */ -#define WSM_ADD_KEY_REQ_ID 0x000C -#define WSM_ADD_KEY_RESP_ID 0x040C -struct wsm_add_key { - u8 type; /* WSM_KEY_TYPE_... */ - u8 index; /* Key entry index: 0 -- WSM_KEY_MAX_INDEX */ - u16 reserved; - union { - struct { - u8 peer[6]; /* MAC address of the peer station */ - u8 reserved; - u8 keylen; /* Key length in bytes */ - u8 keydata[16]; /* Key data */ - } __packed wep_pairwise; - struct { - u8 keyid; /* Unique per key identifier (0..3) */ - u8 keylen; /* Key length in bytes */ - u16 reserved; - u8 keydata[16]; /* Key data */ - } __packed wep_group; - struct { - u8 peer[6]; /* MAC address of the peer station */ - u16 reserved; - u8 keydata[16]; /* TKIP key data */ - u8 rx_mic_key[8]; /* Rx MIC key */ - u8 tx_mic_key[8]; /* Tx MIC key */ - } __packed tkip_pairwise; - struct { - u8 keydata[16]; /* TKIP key data */ - u8 rx_mic_key[8]; /* Rx MIC key */ - u8 keyid; /* Key ID */ - u8 reserved[3]; - u8 rx_seqnum[8]; /* Receive Sequence Counter */ - } __packed tkip_group; - struct { - u8 peer[6]; /* MAC address of the peer station */ - u16 reserved; - u8 keydata[16]; /* AES key data */ - } __packed aes_pairwise; - struct { - u8 keydata[16]; /* AES key data */ - u8 keyid; /* Key ID */ - u8 reserved[3]; - u8 rx_seqnum[8]; /* Receive Sequence Counter */ - } __packed aes_group; - struct { - u8 peer[6]; /* MAC address of the peer station */ - u8 keyid; /* Key ID */ - u8 reserved; - u8 keydata[16]; /* WAPI key data */ - u8 mic_key[16]; /* MIC key data */ - } __packed wapi_pairwise; - struct { - u8 keydata[16]; /* WAPI key data */ - u8 mic_key[16]; /* MIC key data */ - u8 keyid; /* Key ID */ - u8 reserved[3]; - } __packed wapi_group; - } __packed; -} __packed; - -int wsm_add_key(struct cw1200_common *priv, const struct wsm_add_key *arg); - -/* 3.32 */ -#define WSM_REMOVE_KEY_REQ_ID 0x000D -#define WSM_REMOVE_KEY_RESP_ID 0x040D -struct wsm_remove_key { - u8 index; /* Key entry index : 0-10 */ -}; - -int wsm_remove_key(struct cw1200_common *priv, - const struct wsm_remove_key *arg); - -/* 3.34 */ -struct wsm_set_tx_queue_params { - /* WSM_ACK_POLICY_... */ - u8 ackPolicy; - - /* Medium Time of TSPEC (in 32us units) allowed per */ - /* One Second Averaging Period for this queue. */ - u16 allowedMediumTime; - - /* dot11MaxTransmitMsduLifetime to be used for the */ - /* specified queue. */ - u32 maxTransmitLifetime; -}; - -struct wsm_tx_queue_params { - /* NOTE: index is a linux queue id. */ - struct wsm_set_tx_queue_params params[4]; -}; - - -#define WSM_TX_QUEUE_SET(queue_params, queue, ack_policy, allowed_time,\ - max_life_time) \ -do { \ - struct wsm_set_tx_queue_params *p = &(queue_params)->params[queue]; \ - p->ackPolicy = (ack_policy); \ - p->allowedMediumTime = (allowed_time); \ - p->maxTransmitLifetime = (max_life_time); \ -} while (0) - -int wsm_set_tx_queue_params(struct cw1200_common *priv, - const struct wsm_set_tx_queue_params *arg, u8 id); - -/* 3.36 */ -#define WSM_EDCA_PARAMS_REQ_ID 0x0013 -#define WSM_EDCA_PARAMS_RESP_ID 0x0413 -struct wsm_edca_queue_params { - /* CWmin (in slots) for the access class. */ - u16 cwmin; - - /* CWmax (in slots) for the access class. */ - u16 cwmax; - - /* AIFS (in slots) for the access class. */ - u16 aifns; - - /* TX OP Limit (in microseconds) for the access class. */ - u16 txop_limit; - - /* dot11MaxReceiveLifetime to be used for the specified */ - /* the access class. Overrides the global */ - /* dot11MaxReceiveLifetime value */ - u32 max_rx_lifetime; -}; - -struct wsm_edca_params { - /* NOTE: index is a linux queue id. */ - struct wsm_edca_queue_params params[4]; - bool uapsd_enable[4]; -}; - -#define TXOP_UNIT 32 -#define WSM_EDCA_SET(__edca, __queue, __aifs, __cw_min, __cw_max, __txop, __lifetime,\ - __uapsd) \ - do { \ - struct wsm_edca_queue_params *p = &(__edca)->params[__queue]; \ - p->cwmin = __cw_min; \ - p->cwmax = __cw_max; \ - p->aifns = __aifs; \ - p->txop_limit = ((__txop) * TXOP_UNIT); \ - p->max_rx_lifetime = __lifetime; \ - (__edca)->uapsd_enable[__queue] = (__uapsd); \ - } while (0) - -int wsm_set_edca_params(struct cw1200_common *priv, - const struct wsm_edca_params *arg); - -int wsm_set_uapsd_param(struct cw1200_common *priv, - const struct wsm_edca_params *arg); - -/* 3.38 */ -/* Set-System info. Skipped for now. Irrelevent. */ - -/* 3.40 */ -#define WSM_SWITCH_CHANNEL_REQ_ID 0x0016 -#define WSM_SWITCH_CHANNEL_RESP_ID 0x0416 - -struct wsm_switch_channel { - /* 1 - means the STA shall not transmit any further */ - /* frames until the channel switch has completed */ - u8 mode; - - /* Number of TBTTs until channel switch occurs. */ - /* 0 - indicates switch shall occur at any time */ - /* 1 - occurs immediately before the next TBTT */ - u8 switch_count; - - /* The new channel number to switch to. */ - /* Note this is defined as per section 2.7. */ - u16 channel_number; -}; - -int wsm_switch_channel(struct cw1200_common *priv, - const struct wsm_switch_channel *arg); - -typedef void (*wsm_channel_switch_cb) (struct cw1200_common *priv); - -#define WSM_START_REQ_ID 0x0017 -#define WSM_START_RESP_ID 0x0417 - -struct wsm_start { - /* WSM_START_MODE_... */ - /* [in] */ u8 mode; - - /* WSM_PHY_BAND_... */ - /* [in] */ u8 band; - - /* Channel number */ - /* [in] */ u16 channel_number; - - /* Client Traffic window in units of TU */ - /* Valid only when mode == ..._P2P */ - /* [in] */ u32 ct_window; - - /* Interval between two consecutive */ - /* beacon transmissions in TU. */ - /* [in] */ u32 beacon_interval; - - /* DTIM period in terms of beacon intervals */ - /* [in] */ u8 dtim_period; - - /* WSM_JOIN_PREAMBLE_... */ - /* [in] */ u8 preamble; - - /* The delay time (in microseconds) period */ - /* before sending a probe-request. */ - /* [in] */ u8 probe_delay; - - /* Length of the SSID */ - /* [in] */ u8 ssid_len; - - /* SSID of the BSS or P2P_GO to be started now. */ - /* [in] */ u8 ssid[32]; - - /* The basic supported rates for the MiniAP. */ - /* [in] */ u32 basic_rate_set; -}; - -int wsm_start(struct cw1200_common *priv, const struct wsm_start *arg); - -#define WSM_BEACON_TRANSMIT_REQ_ID 0x0018 -#define WSM_BEACON_TRANSMIT_RESP_ID 0x0418 - -struct wsm_beacon_transmit { - /* 1: enable; 0: disable */ - /* [in] */ u8 enable_beaconing; -}; - -int wsm_beacon_transmit(struct cw1200_common *priv, - const struct wsm_beacon_transmit *arg); - -int wsm_start_find(struct cw1200_common *priv); - -int wsm_stop_find(struct cw1200_common *priv); - -typedef void (*wsm_find_complete_cb) (struct cw1200_common *priv, u32 status); - -struct wsm_suspend_resume { - /* See 3.52 */ - /* Link ID */ - /* [out] */ int link_id; - /* Stop sending further Tx requests down to device for this link */ - /* [out] */ bool stop; - /* Transmit multicast Frames */ - /* [out] */ bool multicast; - /* The AC on which Tx to be suspended /resumed. */ - /* This is applicable only for U-APSD */ - /* WSM_QUEUE_... */ - /* [out] */ int queue; -}; - -typedef void (*wsm_suspend_resume_cb) (struct cw1200_common *priv, - struct wsm_suspend_resume *arg); - -/* 3.54 Update-IE request. */ -struct wsm_update_ie { - /* WSM_UPDATE_IE_... */ - /* [in] */ u16 what; - /* [in] */ u16 count; - /* [in] */ u8 *ies; - /* [in] */ size_t length; -}; - -int wsm_update_ie(struct cw1200_common *priv, - const struct wsm_update_ie *arg); - -/* 3.56 */ -struct wsm_map_link { - /* MAC address of the remote device */ - /* [in] */ u8 mac_addr[6]; - /* [in] */ u8 link_id; -}; - -int wsm_map_link(struct cw1200_common *priv, const struct wsm_map_link *arg); - -/* ******************************************************************** */ -/* MIB shortcats */ - -static inline int wsm_set_output_power(struct cw1200_common *priv, - int power_level) -{ - __le32 val = __cpu_to_le32(power_level); - return wsm_write_mib(priv, WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL, - &val, sizeof(val)); -} - -static inline int wsm_set_beacon_wakeup_period(struct cw1200_common *priv, - unsigned dtim_interval, - unsigned listen_interval) -{ - struct { - u8 numBeaconPeriods; - u8 reserved; - __le16 listenInterval; - } val = { - dtim_interval, 0, __cpu_to_le16(listen_interval) - }; - - if (dtim_interval > 0xFF || listen_interval > 0xFFFF) - return -EINVAL; - else - return wsm_write_mib(priv, WSM_MIB_ID_BEACON_WAKEUP_PERIOD, - &val, sizeof(val)); -} - -struct wsm_rcpi_rssi_threshold { - u8 rssiRcpiMode; /* WSM_RCPI_RSSI_... */ - u8 lowerThreshold; - u8 upperThreshold; - u8 rollingAverageCount; -}; - -static inline int wsm_set_rcpi_rssi_threshold(struct cw1200_common *priv, - struct wsm_rcpi_rssi_threshold *arg) -{ - return wsm_write_mib(priv, WSM_MIB_ID_RCPI_RSSI_THRESHOLD, arg, - sizeof(*arg)); -} - -struct wsm_mib_counters_table { - __le32 plcp_errors; - __le32 fcs_errors; - __le32 tx_packets; - __le32 rx_packets; - __le32 rx_packet_errors; - __le32 rx_decryption_failures; - __le32 rx_mic_failures; - __le32 rx_no_key_failures; - __le32 tx_multicast_frames; - __le32 tx_frames_success; - __le32 tx_frame_failures; - __le32 tx_frames_retried; - __le32 tx_frames_multi_retried; - __le32 rx_frame_duplicates; - __le32 rts_success; - __le32 rts_failures; - __le32 ack_failures; - __le32 rx_multicast_frames; - __le32 rx_frames_success; - __le32 rx_cmac_icv_errors; - __le32 rx_cmac_replays; - __le32 rx_mgmt_ccmp_replays; -} __packed; - -static inline int wsm_get_counters_table(struct cw1200_common *priv, - struct wsm_mib_counters_table *arg) -{ - return wsm_read_mib(priv, WSM_MIB_ID_COUNTERS_TABLE, - arg, sizeof(*arg)); -} - -static inline int wsm_get_station_id(struct cw1200_common *priv, u8 *mac) -{ - return wsm_read_mib(priv, WSM_MIB_ID_DOT11_STATION_ID, mac, ETH_ALEN); -} - -struct wsm_rx_filter { - bool promiscuous; - bool bssid; - bool fcs; - bool probeResponder; -}; - -static inline int wsm_set_rx_filter(struct cw1200_common *priv, - const struct wsm_rx_filter *arg) -{ - __le32 val = 0; - if (arg->promiscuous) - val |= __cpu_to_le32(BIT(0)); - if (arg->bssid) - val |= __cpu_to_le32(BIT(1)); - if (arg->fcs) - val |= __cpu_to_le32(BIT(2)); - if (arg->probeResponder) - val |= __cpu_to_le32(BIT(3)); - return wsm_write_mib(priv, WSM_MIB_ID_RX_FILTER, &val, sizeof(val)); -} - -int wsm_set_probe_responder(struct cw1200_common *priv, bool enable); - -#define WSM_BEACON_FILTER_IE_HAS_CHANGED BIT(0) -#define WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT BIT(1) -#define WSM_BEACON_FILTER_IE_HAS_APPEARED BIT(2) - -struct wsm_beacon_filter_table_entry { - u8 ie_id; - u8 flags; - u8 oui[3]; - u8 match_data[3]; -} __packed; - -struct wsm_mib_beacon_filter_table { - __le32 num; - struct wsm_beacon_filter_table_entry entry[10]; -} __packed; - -static inline int wsm_set_beacon_filter_table(struct cw1200_common *priv, - struct wsm_mib_beacon_filter_table *ft) -{ - size_t size = __le32_to_cpu(ft->num) * - sizeof(struct wsm_beacon_filter_table_entry) + - sizeof(__le32); - - return wsm_write_mib(priv, WSM_MIB_ID_BEACON_FILTER_TABLE, ft, size); -} - -#define WSM_BEACON_FILTER_ENABLE BIT(0) /* Enable/disable beacon filtering */ -#define WSM_BEACON_FILTER_AUTO_ERP BIT(1) /* If 1 FW will handle ERP IE changes internally */ - -struct wsm_beacon_filter_control { - int enabled; - int bcn_count; -}; - -static inline int wsm_beacon_filter_control(struct cw1200_common *priv, - struct wsm_beacon_filter_control *arg) -{ - struct { - __le32 enabled; - __le32 bcn_count; - } val; - val.enabled = __cpu_to_le32(arg->enabled); - val.bcn_count = __cpu_to_le32(arg->bcn_count); - return wsm_write_mib(priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, &val, - sizeof(val)); -} - -enum wsm_power_mode { - wsm_power_mode_active = 0, - wsm_power_mode_doze = 1, - wsm_power_mode_quiescent = 2, -}; - -struct wsm_operational_mode { - enum wsm_power_mode power_mode; - int disable_more_flag_usage; - int perform_ant_diversity; -}; - -static inline int wsm_set_operational_mode(struct cw1200_common *priv, - const struct wsm_operational_mode *arg) -{ - u8 val = arg->power_mode; - if (arg->disable_more_flag_usage) - val |= BIT(4); - if (arg->perform_ant_diversity) - val |= BIT(5); - return wsm_write_mib(priv, WSM_MIB_ID_OPERATIONAL_POWER_MODE, &val, - sizeof(val)); -} - -struct wsm_template_frame { - u8 frame_type; - u8 rate; - struct sk_buff *skb; -}; - -static inline int wsm_set_template_frame(struct cw1200_common *priv, - struct wsm_template_frame *arg) -{ - int ret; - u8 *p = skb_push(arg->skb, 4); - p[0] = arg->frame_type; - p[1] = arg->rate; - ((__le16 *)p)[1] = __cpu_to_le16(arg->skb->len - 4); - ret = wsm_write_mib(priv, WSM_MIB_ID_TEMPLATE_FRAME, p, arg->skb->len); - skb_pull(arg->skb, 4); - return ret; -} - - -struct wsm_protected_mgmt_policy { - bool protectedMgmtEnable; - bool unprotectedMgmtFramesAllowed; - bool encryptionForAuthFrame; -}; - -static inline int wsm_set_protected_mgmt_policy(struct cw1200_common *priv, - struct wsm_protected_mgmt_policy *arg) -{ - __le32 val = 0; - int ret; - if (arg->protectedMgmtEnable) - val |= __cpu_to_le32(BIT(0)); - if (arg->unprotectedMgmtFramesAllowed) - val |= __cpu_to_le32(BIT(1)); - if (arg->encryptionForAuthFrame) - val |= __cpu_to_le32(BIT(2)); - ret = wsm_write_mib(priv, WSM_MIB_ID_PROTECTED_MGMT_POLICY, - &val, sizeof(val)); - return ret; -} - -struct wsm_mib_block_ack_policy { - u8 tx_tid; - u8 reserved1; - u8 rx_tid; - u8 reserved2; -} __packed; - -static inline int wsm_set_block_ack_policy(struct cw1200_common *priv, - u8 tx_tid_policy, - u8 rx_tid_policy) -{ - struct wsm_mib_block_ack_policy val = { - .tx_tid = tx_tid_policy, - .rx_tid = rx_tid_policy, - }; - return wsm_write_mib(priv, WSM_MIB_ID_BLOCK_ACK_POLICY, &val, - sizeof(val)); -} - -struct wsm_mib_association_mode { - u8 flags; /* WSM_ASSOCIATION_MODE_... */ - u8 preamble; /* WSM_JOIN_PREAMBLE_... */ - u8 greenfield; /* 1 for greenfield */ - u8 mpdu_start_spacing; - __le32 basic_rate_set; -} __packed; - -static inline int wsm_set_association_mode(struct cw1200_common *priv, - struct wsm_mib_association_mode *arg) -{ - return wsm_write_mib(priv, WSM_MIB_ID_SET_ASSOCIATION_MODE, arg, - sizeof(*arg)); -} - -#define WSM_TX_RATE_POLICY_FLAG_TERMINATE_WHEN_FINISHED BIT(2) -#define WSM_TX_RATE_POLICY_FLAG_COUNT_INITIAL_TRANSMIT BIT(3) -struct wsm_tx_rate_retry_policy { - u8 index; - u8 short_retries; - u8 long_retries; - /* BIT(2) - Terminate retries when Tx rate retry policy - * finishes. - * BIT(3) - Count initial frame transmission as part of - * rate retry counting but not as a retry - * attempt - */ - u8 flags; - u8 rate_recoveries; - u8 reserved[3]; - __le32 rate_count_indices[3]; -} __packed; - -struct wsm_set_tx_rate_retry_policy { - u8 num; - u8 reserved[3]; - struct wsm_tx_rate_retry_policy tbl[8]; -} __packed; - -static inline int wsm_set_tx_rate_retry_policy(struct cw1200_common *priv, - struct wsm_set_tx_rate_retry_policy *arg) -{ - size_t size = 4 + arg->num * sizeof(struct wsm_tx_rate_retry_policy); - return wsm_write_mib(priv, WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, - size); -} - -/* 4.32 SetEtherTypeDataFrameFilter */ -struct wsm_ether_type_filter_hdr { - u8 num; /* Up to WSM_MAX_FILTER_ELEMENTS */ - u8 reserved[3]; -} __packed; - -struct wsm_ether_type_filter { - u8 action; /* WSM_FILTER_ACTION_XXX */ - u8 reserved; - __le16 type; /* Type of ethernet frame */ -} __packed; - -static inline int wsm_set_ether_type_filter(struct cw1200_common *priv, - struct wsm_ether_type_filter_hdr *arg) -{ - size_t size = sizeof(struct wsm_ether_type_filter_hdr) + - arg->num * sizeof(struct wsm_ether_type_filter); - return wsm_write_mib(priv, WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER, - arg, size); -} - -/* 4.33 SetUDPPortDataFrameFilter */ -struct wsm_udp_port_filter_hdr { - u8 num; /* Up to WSM_MAX_FILTER_ELEMENTS */ - u8 reserved[3]; -} __packed; - -struct wsm_udp_port_filter { - u8 action; /* WSM_FILTER_ACTION_XXX */ - u8 type; /* WSM_FILTER_PORT_TYPE_XXX */ - __le16 port; /* Port number */ -} __packed; - -static inline int wsm_set_udp_port_filter(struct cw1200_common *priv, - struct wsm_udp_port_filter_hdr *arg) -{ - size_t size = sizeof(struct wsm_udp_port_filter_hdr) + - arg->num * sizeof(struct wsm_udp_port_filter); - return wsm_write_mib(priv, WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER, - arg, size); -} - -/* Undocumented MIBs: */ -/* 4.35 P2PDeviceInfo */ -#define D11_MAX_SSID_LEN (32) - -struct wsm_p2p_device_type { - __le16 category_id; - u8 oui[4]; - __le16 subcategory_id; -} __packed; - -struct wsm_p2p_device_info { - struct wsm_p2p_device_type primaryDevice; - u8 reserved1[3]; - u8 devname_size; - u8 local_devname[D11_MAX_SSID_LEN]; - u8 reserved2[3]; - u8 num_secdev_supported; - struct wsm_p2p_device_type secdevs[0]; -} __packed; - -/* 4.36 SetWCDMABand - WO */ -struct wsm_cdma_band { - u8 wcdma_band; - u8 reserved[3]; -} __packed; - -/* 4.37 GroupTxSequenceCounter - RO */ -struct wsm_group_tx_seq { - __le32 bits_47_16; - __le16 bits_15_00; - __le16 reserved; -} __packed; - -/* 4.39 SetHtProtection - WO */ -#define WSM_DUAL_CTS_PROT_ENB (1 << 0) -#define WSM_NON_GREENFIELD_STA_PRESENT (1 << 1) -#define WSM_HT_PROT_MODE__NO_PROT (0 << 2) -#define WSM_HT_PROT_MODE__NON_MEMBER (1 << 2) -#define WSM_HT_PROT_MODE__20_MHZ (2 << 2) -#define WSM_HT_PROT_MODE__NON_HT_MIXED (3 << 2) -#define WSM_LSIG_TXOP_PROT_FULL (1 << 4) -#define WSM_LARGE_L_LENGTH_PROT (1 << 5) - -struct wsm_ht_protection { - __le32 flags; -} __packed; - -/* 4.40 GPIO Command - R/W */ -#define WSM_GPIO_COMMAND_SETUP 0 -#define WSM_GPIO_COMMAND_READ 1 -#define WSM_GPIO_COMMAND_WRITE 2 -#define WSM_GPIO_COMMAND_RESET 3 -#define WSM_GPIO_ALL_PINS 0xFF - -struct wsm_gpio_command { - u8 command; - u8 pin; - __le16 config; -} __packed; - -/* 4.41 TSFCounter - RO */ -struct wsm_tsf_counter { - __le64 tsf_counter; -} __packed; - -/* 4.43 Keep alive period */ -struct wsm_keep_alive_period { - __le16 period; - u8 reserved[2]; -} __packed; - -static inline int wsm_keep_alive_period(struct cw1200_common *priv, - int period) -{ - struct wsm_keep_alive_period arg = { - .period = __cpu_to_le16(period), - }; - return wsm_write_mib(priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD, - &arg, sizeof(arg)); -}; - -/* BSSID filtering */ -struct wsm_set_bssid_filtering { - u8 filter; - u8 reserved[3]; -} __packed; - -static inline int wsm_set_bssid_filtering(struct cw1200_common *priv, - bool enabled) -{ - struct wsm_set_bssid_filtering arg = { - .filter = !enabled, - }; - return wsm_write_mib(priv, WSM_MIB_ID_DISABLE_BSSID_FILTER, - &arg, sizeof(arg)); -} - -/* Multicast filtering - 4.5 */ -struct wsm_mib_multicast_filter { - __le32 enable; - __le32 num_addrs; - u8 macaddrs[WSM_MAX_GRP_ADDRTABLE_ENTRIES][ETH_ALEN]; -} __packed; - -static inline int wsm_set_multicast_filter(struct cw1200_common *priv, - struct wsm_mib_multicast_filter *fp) -{ - return wsm_write_mib(priv, WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE, - fp, sizeof(*fp)); -} - -/* ARP IPv4 filtering - 4.10 */ -struct wsm_mib_arp_ipv4_filter { - __le32 enable; - __be32 ipv4addrs[WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES]; -} __packed; - -static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv, - struct wsm_mib_arp_ipv4_filter *fp) -{ - return wsm_write_mib(priv, WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE, - fp, sizeof(*fp)); -} - -/* P2P Power Save Mode Info - 4.31 */ -struct wsm_p2p_ps_modeinfo { - u8 opp_ps_ct_window; - u8 count; - u8 reserved; - u8 dtim_count; - __le32 duration; - __le32 interval; - __le32 start_time; -} __packed; - -static inline int wsm_set_p2p_ps_modeinfo(struct cw1200_common *priv, - struct wsm_p2p_ps_modeinfo *mi) -{ - return wsm_write_mib(priv, WSM_MIB_ID_P2P_PS_MODE_INFO, - mi, sizeof(*mi)); -} - -static inline int wsm_get_p2p_ps_modeinfo(struct cw1200_common *priv, - struct wsm_p2p_ps_modeinfo *mi) -{ - return wsm_read_mib(priv, WSM_MIB_ID_P2P_PS_MODE_INFO, - mi, sizeof(*mi)); -} - -/* UseMultiTxConfMessage */ - -static inline int wsm_use_multi_tx_conf(struct cw1200_common *priv, - bool enabled) -{ - __le32 arg = enabled ? __cpu_to_le32(1) : 0; - - return wsm_write_mib(priv, WSM_MIB_USE_MULTI_TX_CONF, - &arg, sizeof(arg)); -} - - -/* 4.26 SetUpasdInformation */ -struct wsm_uapsd_info { - __le16 uapsd_flags; - __le16 min_auto_trigger_interval; - __le16 max_auto_trigger_interval; - __le16 auto_trigger_step; -}; - -static inline int wsm_set_uapsd_info(struct cw1200_common *priv, - struct wsm_uapsd_info *arg) -{ - return wsm_write_mib(priv, WSM_MIB_ID_SET_UAPSD_INFORMATION, - arg, sizeof(*arg)); -} - -/* 4.22 OverrideInternalTxRate */ -struct wsm_override_internal_txrate { - u8 internalTxRate; - u8 nonErpInternalTxRate; - u8 reserved[2]; -} __packed; - -static inline int wsm_set_override_internal_txrate(struct cw1200_common *priv, - struct wsm_override_internal_txrate *arg) -{ - return wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, - arg, sizeof(*arg)); -} - -/* ******************************************************************** */ -/* WSM TX port control */ - -void wsm_lock_tx(struct cw1200_common *priv); -void wsm_lock_tx_async(struct cw1200_common *priv); -bool wsm_flush_tx(struct cw1200_common *priv); -void wsm_unlock_tx(struct cw1200_common *priv); - -/* ******************************************************************** */ -/* WSM / BH API */ - -int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len); -int wsm_handle_rx(struct cw1200_common *priv, u16 id, struct wsm_hdr *wsm, - struct sk_buff **skb_p); - -/* ******************************************************************** */ -/* wsm_buf API */ - -struct wsm_buf { - u8 *begin; - u8 *data; - u8 *end; -}; - -void wsm_buf_init(struct wsm_buf *buf); -void wsm_buf_deinit(struct wsm_buf *buf); - -/* ******************************************************************** */ -/* wsm_cmd API */ - -struct wsm_cmd { - spinlock_t lock; /* Protect structure from multiple access */ - int done; - u8 *ptr; - size_t len; - void *arg; - int ret; - u16 cmd; -}; - -/* ******************************************************************** */ -/* WSM TX buffer access */ - -int wsm_get_tx(struct cw1200_common *priv, u8 **data, - size_t *tx_len, int *burst); -void wsm_txed(struct cw1200_common *priv, u8 *data); - -/* ******************************************************************** */ -/* Queue mapping: WSM <---> linux */ -/* Linux: VO VI BE BK */ -/* WSM: BE BK VI VO */ - -static inline u8 wsm_queue_id_to_linux(u8 queue_id) -{ - static const u8 queue_mapping[] = { - 2, 3, 1, 0 - }; - return queue_mapping[queue_id]; -} - -static inline u8 wsm_queue_id_to_wsm(u8 queue_id) -{ - static const u8 queue_mapping[] = { - 3, 2, 0, 1 - }; - return queue_mapping[queue_id]; -} - -#endif /* CW1200_HWIO_H_INCLUDED */ |