From ee26d661c86ed6a939d9d1de35fc34d31b5e465c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Jun 2016 21:59:29 -0700 Subject: [PATCH] wcn36xx: Replace with latest development version Signed-off-by: Bjorn Andersson --- drivers/net/wireless/ath/wcn36xx/Kconfig | 2 +- drivers/net/wireless/ath/wcn36xx/Makefile | 4 +- drivers/net/wireless/ath/wcn36xx/dxe.c | 47 ++-- drivers/net/wireless/ath/wcn36xx/dxe.h | 7 +- drivers/net/wireless/ath/wcn36xx/hal.h | 16 +- drivers/net/wireless/ath/wcn36xx/main.c | 230 +++++++++++------ drivers/net/wireless/ath/wcn36xx/smd.c | 102 ++++---- drivers/net/wireless/ath/wcn36xx/smd.h | 13 +- drivers/net/wireless/ath/wcn36xx/txrx.c | 23 +- .../net/wireless/ath/wcn36xx/wcn36xx-msm.c | 240 ------------------ drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 68 ++--- 11 files changed, 282 insertions(+), 470 deletions(-) delete mode 100644 drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig index 591ebaea8265..394fe5b77c90 100644 --- a/drivers/net/wireless/ath/wcn36xx/Kconfig +++ b/drivers/net/wireless/ath/wcn36xx/Kconfig @@ -1,6 +1,6 @@ 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. diff --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile index fdf89a53ce75..50c43b4382ba 100644 --- a/drivers/net/wireless/ath/wcn36xx/Makefile +++ b/drivers/net/wireless/ath/wcn36xx/Makefile @@ -1,9 +1,7 @@ -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 diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index af0e515f634d..87dfdaf9044c 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -23,6 +23,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include "wcn36xx.h" #include "txrx.h" @@ -35,26 +36,27 @@ void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low) 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", @@ -150,9 +152,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn) 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; @@ -677,9 +682,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, * 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. @@ -701,9 +706,13 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) 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 */ diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index 3eca4f9594f2..c012e807753b 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2 */ /* 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 diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index dbf1769a9699..4f87ef1e1eb8 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -51,7 +51,7 @@ #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. */ @@ -350,8 +350,6 @@ enum wcn36xx_hal_host_msg_type { 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 }; @@ -2889,11 +2887,13 @@ struct update_beacon_rsp_msg { 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]; @@ -4123,7 +4123,7 @@ struct wcn36xx_hal_update_scan_params_req { /* 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; @@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex { /* Cb State */ enum phy_chan_bond_state state; -}; +} __packed; /* Update scan params - sent from host to PNO to be used during PNO * scanningx */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 5b9c92377924..abc2e4efcf87 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -19,7 +19,12 @@ #include #include #include +#include +#include #include +#include +#include +#include #include "wcn36xx.h" unsigned int wcn36xx_dbg_mask; @@ -27,14 +32,14 @@ module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644); 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, \ @@ -314,8 +319,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw) 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) { @@ -382,8 +385,6 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) 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) @@ -395,7 +396,7 @@ static void wcn36xx_configure_filter(struct ieee80211_hw *hw, 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) { @@ -567,27 +568,61 @@ out: 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; @@ -600,7 +635,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, 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; @@ -994,8 +1029,7 @@ static const struct ieee80211_ops wcn36xx_ops = { .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, @@ -1020,27 +1054,24 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) 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 @@ -1060,47 +1091,91 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) 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"); @@ -1111,25 +1186,26 @@ static int wcn36xx_probe(struct platform_device *pdev) 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); } @@ -1146,14 +1222,14 @@ static int wcn36xx_probe(struct platform_device *pdev) 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); @@ -1164,41 +1240,33 @@ static int wcn36xx_remove(struct platform_device *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"); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 61754967e2ef..87a62eb6228c 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "smd.h" struct wcn36xx_cfg_val { @@ -104,11 +105,11 @@ static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn, 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; @@ -253,7 +254,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) 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; @@ -521,7 +522,7 @@ 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; @@ -529,7 +530,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn) 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); @@ -551,7 +552,7 @@ out: 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; @@ -559,7 +560,7 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn) 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); @@ -674,22 +675,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) 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); @@ -1388,7 +1392,6 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, { 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); @@ -1400,16 +1403,16 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, 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); @@ -2178,13 +2181,18 @@ out: 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: @@ -2220,44 +2228,42 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) 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) { @@ -2265,8 +2271,9 @@ 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, @@ -2275,8 +2282,6 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) 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; @@ -2300,9 +2305,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) 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) { @@ -2315,25 +2319,15 @@ 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); } diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index d93e3fd73831..8892ccd67b14 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -46,11 +46,12 @@ struct wcn36xx_fw_msg_status_rsp { 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); @@ -59,11 +60,11 @@ int wcn36xx_smd_load_nv(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); @@ -127,6 +128,10 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, 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); diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 37f13410e633..8c387a0a3c09 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -45,9 +45,20 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) 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; @@ -57,14 +68,10 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) 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); @@ -221,7 +228,7 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, /* 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)) diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c deleted file mode 100644 index 9e7f8200c0bf..000000000000 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (c) 2013 Eugene Krasnikov - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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); - diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index b17d284a69c9..35a6590c3ee5 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -35,6 +35,9 @@ /* 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 { @@ -103,49 +106,6 @@ struct nv_data { 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 * @@ -223,7 +183,7 @@ struct wcn36xx { 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]; @@ -232,10 +192,16 @@ struct wcn36xx { /* 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 @@ -246,9 +212,15 @@ struct wcn36xx { 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 */ -- 2.39.2