config WCN36XX
tristate "Qualcomm Atheros WCN3660/3680 support"
- depends on MAC80211 && HAS_DMA
+ depends on MAC80211 && HAS_DMA && QCOM_SMD
---help---
This module adds support for wireless adapters based on
Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
-obj-$(CONFIG_WCN36XX) := wcn36xx.o wcn36xx-platform.o
+obj-$(CONFIG_WCN36XX) := wcn36xx.o
wcn36xx-y += main.o \
dxe.o \
txrx.o \
smd.o \
pmc.o \
debug.o
-
-wcn36xx-platform-y += wcn36xx-msm.o
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
#include "wcn36xx.h"
#include "txrx.h"
return ch->head_blk_ctl->bd_cpu_addr;
}
+static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
+{
+ wcn36xx_dbg(WCN36XX_DBG_DXE,
+ "wcn36xx_ccu_write_register: addr=%x, data=%x\n",
+ addr, data);
+
+ writel(data, wcn->ccu_base + addr);
+}
+
static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
{
wcn36xx_dbg(WCN36XX_DBG_DXE,
"wcn36xx_dxe_write_register: addr=%x, data=%x\n",
addr, data);
- writel(data, wcn->mmio + addr);
+ writel(data, wcn->dxe_base + addr);
}
-#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \
-do { \
- if (wcn->chip_version != WCN36XX_CHIP_3660) \
- wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
- else \
- wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
-} while (0) \
-
static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
{
- *data = readl(wcn->mmio + addr);
+ *data = readl(wcn->dxe_base + addr);
wcn36xx_dbg(WCN36XX_DBG_DXE,
"wcn36xx_dxe_read_register: addr=%x, data=%x\n",
goto out_err;
/* Initialize SMSM state Clear TX Enable RING EMPTY STATE */
- ret = wcn->ctrl_ops->smsm_change_state(
- WCN36XX_SMSM_WLAN_TX_ENABLE,
- WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+ ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
+ WCN36XX_SMSM_WLAN_TX_ENABLE |
+ WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
+ WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+ if (ret)
+ goto out_err;
return 0;
* notify chip about new frame through SMSM bus.
*/
if (is_low && vif_priv->pw_state == WCN36XX_BMPS) {
- wcn->ctrl_ops->smsm_change_state(
- 0,
- WCN36XX_SMSM_WLAN_TX_ENABLE);
+ qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
+ WCN36XX_SMSM_WLAN_TX_ENABLE,
+ WCN36XX_SMSM_WLAN_TX_ENABLE);
} else {
/* indicate End Of Packet and generate interrupt on descriptor
* done.
reg_data = WCN36XX_DXE_REG_RESET;
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
- /* Setting interrupt path */
- reg_data = WCN36XX_DXE_CCU_INT;
- wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
+ /* Select channels for rx avail and xfer done interrupts... */
+ reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
+ WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK;
+ if (wcn->is_pronto)
+ wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data);
+ else
+ wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data);
/***************************************/
/* Init descriptors for TX LOW channel */
*/
/* DXE registers */
-#define WCN36XX_DXE_MEM_REG 0x202000
+#define WCN36XX_DXE_MEM_REG 0
-#define WCN36XX_DXE_CCU_INT 0xA0011
-#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10
-#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc
+#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
+#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
/* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44
#define WCN36XX_HAL_STA_INVALID_IDX 0xFF
#define WCN36XX_HAL_BSS_INVALID_IDX 0xFF
-/* Default Beacon template size. */
+/* Default Beacon template size */
#define BEACON_TEMPLATE_SIZE 0x180
/* Minimum PVM size that the FW expects. See comment in smd.c for details. */
WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
- WCN36XX_HAL_PRINT_REG_INFO_IND = 259,
-
WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
};
struct wcn36xx_hal_send_beacon_req_msg {
struct wcn36xx_hal_msg_header header;
- /* length of the template + sizeof(beacon_length) */
- u32 template_length;
+ /* length of the template + 6. Only qcom knows why */
+ u32 beacon_length6;
- /* Beacon data. */
+ /* length of the template. */
u32 beacon_length;
+
+ /* Beacon data. */
u8 beacon[BEACON_TEMPLATE_SIZE - sizeof(u32)];
u8 bssid[ETH_ALEN];
/* Update scan params - sent from host to PNO to be used during PNO
* scanningx */
-struct update_scan_params_req_ex {
+struct wcn36xx_hal_update_scan_params_req_ex {
struct wcn36xx_hal_msg_header header;
/* Cb State */
enum phy_chan_bond_state state;
-};
+} __packed;
/* Update scan params - sent from host to PNO to be used during PNO
* scanningx */
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/smem_state.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
#include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask;
MODULE_PARM_DESC(debug_mask, "Debugging mask");
#define CHAN2G(_freq, _idx) { \
- .band = IEEE80211_BAND_2GHZ, \
+ .band = NL80211_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 25, \
}
#define CHAN5G(_freq, _idx) { \
- .band = IEEE80211_BAND_5GHZ, \
+ .band = NL80211_BAND_5GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 25, \
wcn36xx_feat_caps_info(wcn);
}
- wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
-
/* DMA channel initialization */
ret = wcn36xx_dxe_init(wcn);
if (ret) {
return 0;
}
-#define WCN36XX_SUPPORTED_FILTERS (FIF_ALLMULTI)
-
static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
unsigned int *total, u64 multicast)
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
- *total &= WCN36XX_SUPPORTED_FILTERS;
+ *total &= FIF_ALLMULTI;
fp = (void *)(unsigned long)multicast;
list_for_each_entry(tmp, &wcn->vif_list, list) {
return ret;
}
-static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const u8 *mac_addr)
+static void wcn36xx_hw_scan_worker(struct work_struct *work)
{
- struct wcn36xx *wcn = hw->priv;
+ struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work);
+ struct cfg80211_scan_request *req = wcn->scan_req;
+ u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX];
+ int i;
+
+ wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 scan %d channels worker\n", req->n_channels);
+
+ for (i = 0; i < req->n_channels; i++)
+ channels[i] = req->channels[i]->hw_value;
+
+ wcn36xx_smd_update_scan_params(wcn, channels, req->n_channels);
wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
- wcn36xx_smd_start_scan(wcn);
+ for (i = 0; i < req->n_channels; i++) {
+ wcn->scan_freq = req->channels[i]->center_freq;
+ wcn->scan_band = req->channels[i]->band;
+
+ wcn36xx_smd_start_scan(wcn, req->channels[i]->hw_value);
+ msleep(30);
+ wcn36xx_smd_end_scan(wcn, req->channels[i]->hw_value);
+
+ wcn->scan_freq = 0;
+ }
+ wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+
+ ieee80211_scan_completed(wcn->hw, false);
+
+ mutex_lock(&wcn->scan_lock);
+ wcn->scan_req = NULL;
+ mutex_unlock(&wcn->scan_lock);
}
-static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_scan_request *hw_req)
{
struct wcn36xx *wcn = hw->priv;
- wcn36xx_smd_end_scan(wcn);
- wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+ mutex_lock(&wcn->scan_lock);
+ if (wcn->scan_req) {
+ mutex_unlock(&wcn->scan_lock);
+ return -EBUSY;
+ }
+ wcn->scan_req = &hw_req->req;
+ mutex_unlock(&wcn->scan_lock);
+
+ schedule_work(&wcn->scan_work);
+
+ return 0;
}
static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
- enum ieee80211_band band)
+ enum nl80211_band band)
{
int i, size;
u16 *rates_table;
size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
rates_table = sta_priv->supported_rates.dsss_rates;
- if (band == IEEE80211_BAND_2GHZ) {
+ if (band == NL80211_BAND_2GHZ) {
for (i = 0; i < size; i++) {
if (rates & 0x01) {
rates_table[i] = wcn_2ghz_rates[i].hw_value;
.configure_filter = wcn36xx_configure_filter,
.tx = wcn36xx_tx,
.set_key = wcn36xx_set_key,
- .sw_scan_start = wcn36xx_sw_scan_start,
- .sw_scan_complete = wcn36xx_sw_scan_complete,
+ .hw_scan = wcn36xx_hw_scan,
.bss_info_changed = wcn36xx_bss_info_changed,
.set_rts_threshold = wcn36xx_set_rts_threshold,
.sta_add = wcn36xx_sta_add,
ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
-
- /* 3620 powersaving currently unstable */
- if (wcn->chip_version == WCN36XX_CHIP_3620)
- __clear_bit(IEEE80211_HW_SUPPORTS_PS, wcn->hw->flags);
+ ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);
wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
- wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz;
- wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz;
+ wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz;
+ wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;
+
+ wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;
+ wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;
wcn->hw->wiphy->cipher_suites = cipher_suites;
wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
- /* TODO: Figure out why this is necessary */
- wcn->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
#ifdef CONFIG_PM
wcn->hw->wiphy->wowlan = &wowlan_support;
#endif
static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
struct platform_device *pdev)
{
- u32 mmio[2];
+ struct device_node *mmio_node;
+ struct resource *res;
+ int index;
int ret;
/* Set TX IRQ */
- wcn->tx_irq = irq_of_parse_and_map(pdev->dev.parent->of_node, 0);
- if (!wcn->tx_irq) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
+ if (!res) {
wcn36xx_err("failed to get tx_irq\n");
return -ENOENT;
}
+ wcn->tx_irq = res->start;
/* Set RX IRQ */
- wcn->rx_irq = irq_of_parse_and_map(pdev->dev.parent->of_node, 1);
- if (!wcn->rx_irq) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx");
+ if (!res) {
wcn36xx_err("failed to get rx_irq\n");
return -ENOENT;
}
+ wcn->rx_irq = res->start;
- /* Map the memory */
- ret = of_property_read_u32_array(pdev->dev.parent->of_node, "qcom,wcnss-mmio", mmio, 2);
- if (ret) {
- wcn36xx_err("failed to get qcom,wcnss-mmio\n");
+ /* Acquire SMSM tx enable handle */
+ wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev,
+ "tx-enable", &wcn->tx_enable_state_bit);
+ if (IS_ERR(wcn->tx_enable_state)) {
+ wcn36xx_err("failed to get tx-enable state\n");
return -ENOENT;
}
- wcn->mmio = ioremap(mmio[0], mmio[1]);
- if (!wcn->mmio) {
- wcn36xx_err("failed to map io memory\n");
- return -ENOMEM;
+ /* Acquire SMSM tx rings empty handle */
+ wcn->tx_rings_empty_state = qcom_smem_state_get(&pdev->dev,
+ "tx-rings-empty", &wcn->tx_rings_empty_state_bit);
+ if (IS_ERR(wcn->tx_rings_empty_state)) {
+ wcn36xx_err("failed to get tx-rings-empty state\n");
+ return -ENOENT;
+ }
+
+ mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
+ if (!mmio_node) {
+ wcn36xx_err("failed to acquire qcom,mmio reference\n");
+ return -EINVAL;
+ }
+
+ wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
+
+ /* Map the CCU memory */
+ index = of_property_match_string(mmio_node, "reg-names", "ccu");
+ wcn->ccu_base = of_iomap(mmio_node, index);
+ if (!wcn->ccu_base) {
+ wcn36xx_err("failed to map ccu memory\n");
+ ret = -ENOMEM;
+ goto put_mmio_node;
+ }
+
+ /* Map the DXE memory */
+ index = of_property_match_string(mmio_node, "reg-names", "dxe");
+ wcn->dxe_base = of_iomap(mmio_node, index);
+ if (!wcn->dxe_base) {
+ wcn36xx_err("failed to map dxe memory\n");
+ ret = -ENOMEM;
+ goto unmap_ccu;
}
+
+ of_node_put(mmio_node);
return 0;
+
+unmap_ccu:
+ iounmap(wcn->ccu_base);
+put_mmio_node:
+ of_node_put(mmio_node);
+ return ret;
}
static int wcn36xx_probe(struct platform_device *pdev)
{
struct ieee80211_hw *hw;
struct wcn36xx *wcn;
+ void *wcnss;
int ret;
- u8 addr[ETH_ALEN];
+ const u8 *addr;
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
+ wcnss = dev_get_drvdata(pdev->dev.parent);
+
hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
if (!hw) {
wcn36xx_err("failed to alloc hw\n");
wcn = hw->priv;
wcn->hw = hw;
wcn->dev = &pdev->dev;
- wcn->dev->dma_mask = kzalloc(sizeof(*wcn->dev->dma_mask), GFP_KERNEL);
- if (!wcn->dev->dma_mask) {
- ret = -ENOMEM;
- goto dma_mask_err;
- }
- dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
- wcn->wcn36xx_data = pdev->dev.platform_data;
- wcn->ctrl_ops = &wcn->wcn36xx_data->ctrl_ops;
- wcn->wcn36xx_data->wcn = wcn;
- if (!wcn->ctrl_ops->get_chip_type) {
- dev_err(&pdev->dev, "Missing ops->get_chip_type\n");
- ret = -EINVAL;
+ mutex_init(&wcn->hal_mutex);
+ mutex_init(&wcn->scan_lock);
+
+ INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker);
+
+ wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process);
+ if (IS_ERR(wcn->smd_channel)) {
+ wcn36xx_err("failed to open WLAN_CTRL channel\n");
+ ret = PTR_ERR(wcn->smd_channel);
goto out_wq;
}
- wcn->chip_version = wcn->ctrl_ops->get_chip_type(wcn);
- mutex_init(&wcn->hal_mutex);
+ qcom_smd_set_drvdata(wcn->smd_channel, hw);
- if (!wcn->ctrl_ops->get_hw_mac(wcn, addr)) {
+ addr = of_get_property(pdev->dev.of_node, "local-mac-address", &ret);
+ if (addr && ret != ETH_ALEN) {
+ wcn36xx_err("invalid local-mac-address\n");
+ ret = -EINVAL;
+ goto out_wq;
+ } else if (addr) {
wcn36xx_info("mac address: %pM\n", addr);
SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
}
return 0;
out_unmap:
- iounmap(wcn->mmio);
+ iounmap(wcn->ccu_base);
+ iounmap(wcn->dxe_base);
out_wq:
- kfree(wcn->dev->dma_mask);
-dma_mask_err:
ieee80211_free_hw(hw);
out_err:
return ret;
}
+
static int wcn36xx_remove(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw);
- iounmap(wcn->mmio);
+
+ qcom_smem_state_put(wcn->tx_enable_state);
+ qcom_smem_state_put(wcn->tx_rings_empty_state);
+
+ iounmap(wcn->dxe_base);
+ iounmap(wcn->ccu_base);
ieee80211_free_hw(hw);
return 0;
}
-static const struct platform_device_id wcn36xx_platform_id_table[] = {
- {
- .name = "wcn36xx",
- .driver_data = 0
- },
+
+static const struct of_device_id wcn36xx_of_match[] = {
+ { .compatible = "qcom,wcnss-wlan" },
{}
};
-MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
static struct platform_driver wcn36xx_driver = {
.probe = wcn36xx_probe,
.remove = wcn36xx_remove,
.driver = {
.name = "wcn36xx",
+ .of_match_table = wcn36xx_of_match,
},
- .id_table = wcn36xx_platform_id_table,
};
-static int __init wcn36xx_init(void)
-{
- platform_driver_register(&wcn36xx_driver);
- return 0;
-}
-module_init(wcn36xx_init);
-
-static void __exit wcn36xx_exit(void)
-{
- platform_driver_unregister(&wcn36xx_driver);
-}
-module_exit(wcn36xx_exit);
+module_platform_driver(wcn36xx_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/bitops.h>
+#include <linux/soc/qcom/smd.h>
#include "smd.h"
struct wcn36xx_cfg_val {
struct ieee80211_sta *sta,
struct wcn36xx_hal_config_bss_params *bss_params)
{
- if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn))
+ if (NL80211_BAND_5GHZ == WCN36XX_BAND(wcn))
bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE;
else if (sta && sta->ht_cap.ht_supported)
bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE;
- else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f))
+ else if (sta && (sta->supp_rates[NL80211_BAND_2GHZ] & 0x7f))
bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE;
else
bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE;
init_completion(&wcn->hal_rsp_compl);
start = jiffies;
- ret = wcn->ctrl_ops->tx(wcn, wcn->hal_buf, len);
+ ret = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
if (ret) {
wcn36xx_err("HAL TX failed\n");
goto out;
return ret;
}
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel)
{
struct wcn36xx_hal_start_scan_req_msg msg_body;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
- msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ msg_body.scan_channel = scan_channel;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
return ret;
}
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel)
{
struct wcn36xx_hal_end_scan_req_msg msg_body;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
- msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ msg_body.scan_channel = scan_channel;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
return 0;
}
-int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn)
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn,
+ u8 *channels, size_t channel_count)
{
- struct wcn36xx_hal_update_scan_params_req msg_body;
+ struct wcn36xx_hal_update_scan_params_req_ex msg_body;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
- msg_body.dot11d_enabled = 0;
- msg_body.dot11d_resolved = 0;
- msg_body.channel_count = 26;
+ msg_body.dot11d_enabled = false;
+ msg_body.dot11d_resolved = true;
+
+ msg_body.channel_count = channel_count;
+ memcpy(msg_body.channels, channels, channel_count);
msg_body.active_min_ch_time = 60;
msg_body.active_max_ch_time = 120;
msg_body.passive_min_ch_time = 60;
msg_body.passive_max_ch_time = 110;
- msg_body.state = 0;
+ msg_body.state = PHY_SINGLE_CHANNEL_CENTERED;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
{
struct wcn36xx_hal_send_beacon_req_msg msg_body;
int ret = 0, pad, pvm_len;
- u32 beacon_length;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);
if (vif->type == NL80211_IFTYPE_MESH_POINT)
pad = 0;
- beacon_length = skb_beacon->len + pad;
- msg_body.template_length = beacon_length + sizeof(beacon_length);
+ msg_body.beacon_length = skb_beacon->len + pad;
+ /* TODO need to find out why + 6 is needed */
+ msg_body.beacon_length6 = msg_body.beacon_length + 6;
- if (msg_body.template_length > BEACON_TEMPLATE_SIZE) {
+ if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) {
wcn36xx_err("Beacon is to big: beacon size=%d\n",
- msg_body.template_length);
+ msg_body.beacon_length);
ret = -ENOMEM;
goto out;
}
- msg_body.beacon_length = beacon_length;
memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len);
memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
return ret;
}
-static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+ const void *buf, size_t len)
{
- struct wcn36xx_hal_msg_header *msg_header = buf;
+ struct wcn36xx_hal_msg_header msg_header;
+ struct ieee80211_hw *hw = qcom_smd_get_drvdata(channel);
+ struct wcn36xx *wcn = hw->priv;
struct wcn36xx_hal_ind_msg *msg_ind;
wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
- switch (msg_header->msg_type) {
+ memcpy_fromio(&msg_header, buf, sizeof(struct wcn36xx_hal_msg_header));
+
+ switch (msg_header.msg_type) {
case WCN36XX_HAL_START_RSP:
case WCN36XX_HAL_CONFIG_STA_RSP:
case WCN36XX_HAL_CONFIG_BSS_RSP:
case WCN36XX_HAL_CH_SWITCH_RSP:
case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
- memcpy(wcn->hal_buf, buf, len);
+ memcpy_fromio(wcn->hal_buf, buf, len);
wcn->hal_rsp_len = len;
complete(&wcn->hal_rsp_compl);
break;
- case WCN36XX_HAL_DEL_BA_IND:
- case WCN36XX_HAL_PRINT_REG_INFO_IND:
case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
- msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
- if (!msg_ind)
- goto nomem;
- msg_ind->msg_len = len;
- msg_ind->msg = kmemdup(buf, len, GFP_KERNEL);
- if (!msg_ind->msg) {
- kfree(msg_ind);
-nomem:
+ msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
+ if (!msg_ind) {
/*
* FIXME: Do something smarter then just
* printing an error.
*/
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
- msg_header->msg_type);
+ msg_header.msg_type);
break;
}
- mutex_lock(&wcn->hal_ind_mutex);
+
+ msg_ind->msg_len = len;
+ memcpy_fromio(msg_ind->msg, buf, len);
+
+ spin_lock(&wcn->hal_ind_lock);
list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
- mutex_unlock(&wcn->hal_ind_mutex);
+ spin_unlock(&wcn->hal_ind_lock);
wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
break;
default:
wcn36xx_err("SMD_EVENT (%d) not supported\n",
- msg_header->msg_type);
+ msg_header.msg_type);
}
+
+ return 0;
}
static void wcn36xx_ind_smd_work(struct work_struct *work)
{
container_of(work, struct wcn36xx, hal_ind_work);
struct wcn36xx_hal_msg_header *msg_header;
struct wcn36xx_hal_ind_msg *hal_ind_msg;
+ unsigned long flags;
- mutex_lock(&wcn->hal_ind_mutex);
+ spin_lock_irqsave(&wcn->hal_ind_lock, flags);
hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
struct wcn36xx_hal_ind_msg,
msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
switch (msg_header->msg_type) {
- case WCN36XX_HAL_DEL_BA_IND:
- case WCN36XX_HAL_PRINT_REG_INFO_IND:
case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
break;
msg_header->msg_type);
}
list_del(wcn->hal_ind_queue.next);
- kfree(hal_ind_msg->msg);
+ spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
kfree(hal_ind_msg);
- mutex_unlock(&wcn->hal_ind_mutex);
}
int wcn36xx_smd_open(struct wcn36xx *wcn)
{
}
INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
INIT_LIST_HEAD(&wcn->hal_ind_queue);
- mutex_init(&wcn->hal_ind_mutex);
-
- ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
- if (ret) {
- wcn36xx_err("failed to open control channel\n");
- goto free_wq;
- }
+ spin_lock_init(&wcn->hal_ind_lock);
- return ret;
+ return 0;
-free_wq:
- destroy_workqueue(wcn->hal_ind_wq);
out:
return ret;
}
void wcn36xx_smd_close(struct wcn36xx *wcn)
{
- wcn->ctrl_ops->close(wcn);
destroy_workqueue(wcn->hal_ind_wq);
- mutex_destroy(&wcn->hal_ind_mutex);
}
struct wcn36xx_hal_ind_msg {
struct list_head list;
- u8 *msg;
size_t msg_len;
+ u8 msg[];
};
struct wcn36xx;
+struct qcom_smd_channel;
int wcn36xx_smd_open(struct wcn36xx *wcn);
void wcn36xx_smd_close(struct wcn36xx *wcn);
int wcn36xx_smd_start(struct wcn36xx *wcn);
int wcn36xx_smd_stop(struct wcn36xx *wcn);
int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel);
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel);
int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+ const void *buf, size_t len);
+
int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len);
skb_pull(skb, bd->pdu.mpdu_header_off);
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = __le16_to_cpu(hdr->frame_control);
+ sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
+
+ /* When scanning associate beacons to this */
+ if (ieee80211_is_beacon(hdr->frame_control) && wcn->scan_freq) {
+ status.freq = wcn->scan_freq;
+ status.band = wcn->scan_band;
+ } else {
+ status.freq = WCN36XX_CENTER_FREQ(wcn);
+ status.band = WCN36XX_BAND(wcn);
+ }
+
status.mactime = 10;
- status.freq = WCN36XX_CENTER_FREQ(wcn);
- status.band = WCN36XX_BAND(wcn);
status.signal = -get_rssi0(bd);
status.antenna = 1;
status.rate_idx = 1;
RX_FLAG_MMIC_STRIPPED |
RX_FLAG_DECRYPTED;
- wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
+ wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%llx\n", status.flag);
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = __le16_to_cpu(hdr->frame_control);
- sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
-
if (ieee80211_is_beacon(hdr->frame_control)) {
wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n",
skb, skb->len, fc, sn);
/* default rate for unicast */
if (ieee80211_is_mgmt(hdr->frame_control))
- bd->bd_rate = (WCN36XX_BAND(wcn) == IEEE80211_BAND_5GHZ) ?
+ bd->bd_rate = (WCN36XX_BAND(wcn) == NL80211_BAND_5GHZ) ?
WCN36XX_BD_RATE_CTRL :
WCN36XX_BD_RATE_MGMT;
else if (ieee80211_is_ctl(hdr->frame_control))
+++ /dev/null
-/*
- * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
- * Copyright (c) 2013 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/completion.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/remoteproc.h>
-#include <linux/soc/qcom/smd.h>
-#include "wcn36xx.h"
-
-#define MAC_ADDR_0 "wlan/macaddr0"
-
-struct smd_packet_item {
- struct list_head list;
- void *buf;
- size_t count;
-};
-
-static int wcn36xx_msm_smsm_change_state(u32 clear_mask, u32 set_mask)
-{
- return 0;
-}
-
-static int wcn36xx_msm_get_hw_mac(struct wcn36xx *wcn, u8 *addr)
-{
- const struct firmware *addr_file = NULL;
- int status;
- u8 tmp[18];
- static const u8 qcom_oui[3] = {0x00, 0x0A, 0xF5};
- static const char *files = {MAC_ADDR_0};
- struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
- status = request_firmware(&addr_file, files, &pdata->core->dev);
-
- if (status < 0) {
- /* Assign a random mac with Qualcomm oui */
- dev_err(&pdata->core->dev, "Failed (%d) to read macaddress"
- "file %s, using a random address instead", status, files);
- memcpy(addr, qcom_oui, 3);
- get_random_bytes(addr + 3, 3);
- } else {
- memset(tmp, 0, sizeof(tmp));
- memcpy(tmp, addr_file->data, sizeof(tmp) - 1);
- sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
- &addr[0],
- &addr[1],
- &addr[2],
- &addr[3],
- &addr[4],
- &addr[5]);
-
- release_firmware(addr_file);
- }
-
- return 0;
-}
-
-static int wcn36xx_msm_smd_send_and_wait(struct wcn36xx *wcn, char *buf, size_t len)
-{
- int ret = 0;
- struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
- mutex_lock(&pdata->wlan_ctrl_lock);
- ret = qcom_smd_send(pdata->wlan_ctrl_channel, buf, len);
- if (ret) {
- dev_err(wcn->dev, "wlan ctrl channel tx failed\n");
- }
- mutex_unlock(&pdata->wlan_ctrl_lock);
-
- return ret;
-}
-
-static int wcn36xx_msm_smd_open(struct wcn36xx *wcn, void *rsp_cb)
-{
- struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
- pdata->cb = rsp_cb;
- return 0;
-}
-
-static void wcn36xx_msm_smd_close(struct wcn36xx *wcn)
-{
- return;
-}
-
-static int wcn36xx_msm_get_chip_type(struct wcn36xx *wcn)
-{
- struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
- return pdata->chip_type;
-}
-
-static struct wcn36xx_platform_data wcn36xx_data = {
- .ctrl_ops = {
- .open = wcn36xx_msm_smd_open,
- .close = wcn36xx_msm_smd_close,
- .tx = wcn36xx_msm_smd_send_and_wait,
- .get_hw_mac = wcn36xx_msm_get_hw_mac,
- .smsm_change_state = wcn36xx_msm_smsm_change_state,
- .get_chip_type = wcn36xx_msm_get_chip_type,
- },
-};
-
-static void wlan_ctrl_smd_process(struct work_struct *worker)
-{
- unsigned long flags;
- struct wcn36xx_platform_data *pdata =
- container_of(worker,
- struct wcn36xx_platform_data, packet_process_work);
-
- spin_lock_irqsave(&pdata->packet_lock, flags);
- while (!list_empty(&pdata->packet_list)) {
- struct smd_packet_item *packet;
-
- packet = list_first_entry(&pdata->packet_list,
- struct smd_packet_item, list);
- list_del(&packet->list);
- spin_unlock_irqrestore(&pdata->packet_lock, flags);
- pdata->cb(pdata->wcn, packet->buf, packet->count);
- kfree(packet->buf);
- spin_lock_irqsave(&pdata->packet_lock, flags);
- }
- spin_unlock_irqrestore(&pdata->packet_lock, flags);
-}
-
-static int qcom_smd_wlan_ctrl_probe(struct qcom_smd_device *sdev)
-{
- pr_info("%s: enter\n", __func__);
- mutex_init(&wcn36xx_data.wlan_ctrl_lock);
- init_completion(&wcn36xx_data.wlan_ctrl_ack);
-
- wcn36xx_data.sdev = sdev;
- spin_lock_init(&wcn36xx_data.packet_lock);
- INIT_LIST_HEAD(&wcn36xx_data.packet_list);
- INIT_WORK(&wcn36xx_data.packet_process_work, wlan_ctrl_smd_process);
-
- dev_set_drvdata(&sdev->dev, &wcn36xx_data);
- wcn36xx_data.wlan_ctrl_channel = sdev->channel;
-
- wcn36xx_data.chip_type = (enum wcn36xx_chip_type)of_device_get_match_data(&sdev->dev);
- wcn36xx_data.core = platform_device_alloc("wcn36xx", -1);
- wcn36xx_data.core->dev.parent = &sdev->dev;
- wcn36xx_data.core->dev.platform_data = &wcn36xx_data;
-
- platform_device_add(wcn36xx_data.core);
-
- of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
-
- return 0;
-}
-
-static void qcom_smd_wlan_ctrl_remove(struct qcom_smd_device *sdev)
-{
- of_platform_depopulate(&sdev->dev);
- platform_device_del(wcn36xx_data.core);
- platform_device_put(wcn36xx_data.core);
-}
-
-static int qcom_smd_wlan_ctrl_callback(struct qcom_smd_device *qsdev,
- const void *data,
- size_t count)
-{
- unsigned long flags;
- struct smd_packet_item *packet = NULL;
- struct wcn36xx_platform_data *pdata = dev_get_drvdata(&qsdev->dev);
- void *buf = kzalloc(count + sizeof(struct smd_packet_item),
- GFP_ATOMIC);
- if (!buf) {
- dev_err(&pdata->core->dev, "can't allocate buffer\n");
- return -ENOMEM;
- }
-
- memcpy_fromio(buf, data, count);
- packet = buf + count;
- packet->buf = buf;
- packet->count = count;
-
- spin_lock_irqsave(&pdata->packet_lock, flags);
- list_add_tail(&packet->list, &pdata->packet_list);
- spin_unlock_irqrestore(&pdata->packet_lock, flags);
- schedule_work(&pdata->packet_process_work);
-
- /* buf will be freed in workqueue */
-
- return 0;
-}
-
-static const struct of_device_id wcn36xx_msm_match_table[] = {
- { .compatible = "qcom,wcn3660-wlan", .data = (void *)WCN36XX_CHIP_3660 },
- { .compatible = "qcom,wcn3680-wlan", .data = (void *)WCN36XX_CHIP_3680 },
- { .compatible = "qcom,wcn3620-wlan", .data = (void *)WCN36XX_CHIP_3620 },
- { }
-};
-MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table);
-
-static struct qcom_smd_driver qcom_smd_wlan_ctrl_driver = {
- .probe = qcom_smd_wlan_ctrl_probe,
- .remove = qcom_smd_wlan_ctrl_remove,
- .callback = qcom_smd_wlan_ctrl_callback,
- .driver = {
- .name = "qcom_smd_wlan_ctrl",
- .owner = THIS_MODULE,
- .of_match_table = wcn36xx_msm_match_table,
- },
-};
-
-static int __init wcn36xx_msm_init(void)
-{
- return qcom_smd_driver_register(&qcom_smd_wlan_ctrl_driver);
-}
-module_init(wcn36xx_msm_init);
-
-static void __exit wcn36xx_msm_exit(void)
-{
-}
-module_exit(wcn36xx_msm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
-MODULE_FIRMWARE(MAC_ADDR_0);
-
/* How many frames until we start a-mpdu TX session */
#define WCN36XX_AMPDU_START_THRESH 20
+#define WCN36XX_MAX_SCAN_SSIDS 9
+#define WCN36XX_MAX_SCAN_IE_LEN 500
+
extern unsigned int wcn36xx_dbg_mask;
enum wcn36xx_debug_mask {
u8 table;
};
-enum wcn36xx_chip_type {
- WCN36XX_CHIP_UNKNOWN,
- WCN36XX_CHIP_3660,
- WCN36XX_CHIP_3680,
- WCN36XX_CHIP_3620,
-};
-
-/* Interface for platform control path
- *
- * @open: hook must be called when wcn36xx wants to open control channel.
- * @tx: sends a buffer.
- */
-struct wcn36xx_platform_ctrl_ops {
- int (*open)(struct wcn36xx *wcn, void *rsp_cb);
- void (*close)(struct wcn36xx *wcn);
- int (*tx)(struct wcn36xx *wcn, char *buf, size_t len);
- int (*get_hw_mac)(struct wcn36xx *wcn, u8 *addr);
- int (*get_chip_type)(struct wcn36xx *wcn);
- int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
-};
-
-struct wcn36xx_platform_data {
- enum wcn36xx_chip_type chip_type;
-
- struct platform_device *core;
-
- struct qcom_smd_device *sdev;
- struct qcom_smd_channel *wlan_ctrl_channel;
- struct completion wlan_ctrl_ack;
- struct mutex wlan_ctrl_lock;
-
- struct pinctrl *pinctrl;
-
- struct wcn36xx *wcn;
-
- void (*cb)(struct wcn36xx *wcn, void *buf, size_t len);
- struct wcn36xx_platform_ctrl_ops ctrl_ops;
-
- struct work_struct packet_process_work;
- spinlock_t packet_lock;
- struct list_head packet_list;
-};
-
/**
* struct wcn36xx_vif - holds VIF related fields
*
u8 fw_minor;
u8 fw_major;
u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE];
- enum wcn36xx_chip_type chip_version;
+ bool is_pronto;
/* extra byte for the NULL termination */
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
/* IRQs */
int tx_irq;
int rx_irq;
- void __iomem *mmio;
+ void __iomem *ccu_base;
+ void __iomem *dxe_base;
+
+ struct qcom_smd_channel *smd_channel;
+
+ struct qcom_smem_state *tx_enable_state;
+ unsigned tx_enable_state_bit;
+ struct qcom_smem_state *tx_rings_empty_state;
+ unsigned tx_rings_empty_state_bit;
- struct wcn36xx_platform_data *wcn36xx_data;
- struct wcn36xx_platform_ctrl_ops *ctrl_ops;
/*
* smd_buf must be protected with smd_mutex to garantee
* that all messages are sent one after another
struct completion hal_rsp_compl;
struct workqueue_struct *hal_ind_wq;
struct work_struct hal_ind_work;
- struct mutex hal_ind_mutex;
+ spinlock_t hal_ind_lock;
struct list_head hal_ind_queue;
+ struct work_struct scan_work;
+ struct cfg80211_scan_request *scan_req;
+ int scan_freq;
+ int scan_band;
+ struct mutex scan_lock;
+
/* DXE channels */
struct wcn36xx_dxe_ch dxe_tx_l_ch; /* TX low */
struct wcn36xx_dxe_ch dxe_tx_h_ch; /* TX high */