Commit f303a931 authored by Bjorn Andersson's avatar Bjorn Andersson Committed by Kalle Valo

wcn36xx: Transition driver to SMD client

The wcn36xx wifi driver follows the life cycle of the WLAN_CTRL SMD
channel, as such it should be a SMD client. This patch makes this
transition, now that we have the necessary frameworks available.
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 6c0b2e83
config WCN36XX config WCN36XX
tristate "Qualcomm Atheros WCN3660/3680 support" tristate "Qualcomm Atheros WCN3660/3680 support"
depends on MAC80211 && HAS_DMA depends on MAC80211 && HAS_DMA
depends on QCOM_WCNSS_CTRL || QCOM_WCNSS_CTRL=n
depends on QCOM_SMD || QCOM_SMD=n
---help--- ---help---
This module adds support for wireless adapters based on This module adds support for wireless adapters based on
Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets. Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/soc/qcom/smem_state.h>
#include "wcn36xx.h" #include "wcn36xx.h"
#include "txrx.h" #include "txrx.h"
...@@ -151,9 +152,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn) ...@@ -151,9 +152,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
goto out_err; goto out_err;
/* Initialize SMSM state Clear TX Enable RING EMPTY STATE */ /* Initialize SMSM state Clear TX Enable RING EMPTY STATE */
ret = wcn->ctrl_ops->smsm_change_state( ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
WCN36XX_SMSM_WLAN_TX_ENABLE, WCN36XX_SMSM_WLAN_TX_ENABLE |
WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY); WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
if (ret)
goto out_err;
return 0; return 0;
...@@ -678,8 +682,8 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, ...@@ -678,8 +682,8 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
* notify chip about new frame through SMSM bus. * notify chip about new frame through SMSM bus.
*/ */
if (is_low && vif_priv->pw_state == WCN36XX_BMPS) { if (is_low && vif_priv->pw_state == WCN36XX_BMPS) {
wcn->ctrl_ops->smsm_change_state( qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
0, WCN36XX_SMSM_WLAN_TX_ENABLE,
WCN36XX_SMSM_WLAN_TX_ENABLE); WCN36XX_SMSM_WLAN_TX_ENABLE);
} else { } else {
/* indicate End Of Packet and generate interrupt on descriptor /* indicate End Of Packet and generate interrupt on descriptor
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.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" #include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask; unsigned int wcn36xx_dbg_mask;
...@@ -1058,8 +1062,7 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, ...@@ -1058,8 +1062,7 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
int ret; int ret;
/* Set TX IRQ */ /* Set TX IRQ */
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
"wcnss_wlantx_irq");
if (!res) { if (!res) {
wcn36xx_err("failed to get tx_irq\n"); wcn36xx_err("failed to get tx_irq\n");
return -ENOENT; return -ENOENT;
...@@ -1067,14 +1070,29 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, ...@@ -1067,14 +1070,29 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
wcn->tx_irq = res->start; wcn->tx_irq = res->start;
/* Set RX IRQ */ /* Set RX IRQ */
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx");
"wcnss_wlanrx_irq");
if (!res) { if (!res) {
wcn36xx_err("failed to get rx_irq\n"); wcn36xx_err("failed to get rx_irq\n");
return -ENOENT; return -ENOENT;
} }
wcn->rx_irq = res->start; wcn->rx_irq = res->start;
/* 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 PTR_ERR(wcn->tx_enable_state);
}
/* 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 PTR_ERR(wcn->tx_rings_empty_state);
}
mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0); mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
if (!mmio_node) { if (!mmio_node) {
wcn36xx_err("failed to acquire qcom,mmio reference\n"); wcn36xx_err("failed to acquire qcom,mmio reference\n");
...@@ -1115,11 +1133,14 @@ static int wcn36xx_probe(struct platform_device *pdev) ...@@ -1115,11 +1133,14 @@ static int wcn36xx_probe(struct platform_device *pdev)
{ {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct wcn36xx *wcn; struct wcn36xx *wcn;
void *wcnss;
int ret; int ret;
u8 addr[ETH_ALEN]; const u8 *addr;
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n"); wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
wcnss = dev_get_drvdata(pdev->dev.parent);
hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops); hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
if (!hw) { if (!hw) {
wcn36xx_err("failed to alloc hw\n"); wcn36xx_err("failed to alloc hw\n");
...@@ -1130,11 +1151,23 @@ static int wcn36xx_probe(struct platform_device *pdev) ...@@ -1130,11 +1151,23 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn = hw->priv; wcn = hw->priv;
wcn->hw = hw; wcn->hw = hw;
wcn->dev = &pdev->dev; wcn->dev = &pdev->dev;
wcn->ctrl_ops = pdev->dev.platform_data;
mutex_init(&wcn->hal_mutex); mutex_init(&wcn->hal_mutex);
if (!wcn->ctrl_ops->get_hw_mac(addr)) { 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;
}
qcom_smd_set_drvdata(wcn->smd_channel, hw);
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); wcn36xx_info("mac address: %pM\n", addr);
SET_IEEE80211_PERM_ADDR(wcn->hw, addr); SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
} }
...@@ -1158,6 +1191,7 @@ static int wcn36xx_probe(struct platform_device *pdev) ...@@ -1158,6 +1191,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
out_err: out_err:
return ret; return ret;
} }
static int wcn36xx_remove(struct platform_device *pdev) static int wcn36xx_remove(struct platform_device *pdev)
{ {
struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct ieee80211_hw *hw = platform_get_drvdata(pdev);
...@@ -1168,42 +1202,33 @@ static int wcn36xx_remove(struct platform_device *pdev) ...@@ -1168,42 +1202,33 @@ static int wcn36xx_remove(struct platform_device *pdev)
mutex_destroy(&wcn->hal_mutex); mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
qcom_smem_state_put(wcn->tx_enable_state);
qcom_smem_state_put(wcn->tx_rings_empty_state);
iounmap(wcn->dxe_base); iounmap(wcn->dxe_base);
iounmap(wcn->ccu_base); iounmap(wcn->ccu_base);
ieee80211_free_hw(hw); ieee80211_free_hw(hw);
return 0; return 0;
} }
static const struct platform_device_id wcn36xx_platform_id_table[] = {
{ static const struct of_device_id wcn36xx_of_match[] = {
.name = "wcn36xx", { .compatible = "qcom,wcnss-wlan" },
.driver_data = 0
},
{} {}
}; };
MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table); MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
static struct platform_driver wcn36xx_driver = { static struct platform_driver wcn36xx_driver = {
.probe = wcn36xx_probe, .probe = wcn36xx_probe,
.remove = wcn36xx_remove, .remove = wcn36xx_remove,
.driver = { .driver = {
.name = "wcn36xx", .name = "wcn36xx",
.of_match_table = wcn36xx_of_match,
}, },
.id_table = wcn36xx_platform_id_table,
}; };
static int __init wcn36xx_init(void) module_platform_driver(wcn36xx_driver);
{
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_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com"); MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/soc/qcom/smd.h>
#include "smd.h" #include "smd.h"
struct wcn36xx_cfg_val { struct wcn36xx_cfg_val {
...@@ -253,7 +254,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) ...@@ -253,7 +254,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
init_completion(&wcn->hal_rsp_compl); init_completion(&wcn->hal_rsp_compl);
start = jiffies; start = jiffies;
ret = wcn->ctrl_ops->tx(wcn->hal_buf, len); ret = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
if (ret) { if (ret) {
wcn36xx_err("HAL TX failed\n"); wcn36xx_err("HAL TX failed\n");
goto out; goto out;
...@@ -2180,9 +2181,12 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, ...@@ -2180,9 +2181,12 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
return ret; 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; const struct wcn36xx_hal_msg_header *msg_header = buf;
struct ieee80211_hw *hw = qcom_smd_get_drvdata(channel);
struct wcn36xx *wcn = hw->priv;
struct wcn36xx_hal_ind_msg *msg_ind; struct wcn36xx_hal_ind_msg *msg_ind;
wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len); wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
...@@ -2233,15 +2237,11 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) ...@@ -2233,15 +2237,11 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_OTA_TX_COMPL_IND: case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND: case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL); msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
if (!msg_ind) { if (!msg_ind) {
/*
* FIXME: Do something smarter then just
* printing an error.
*/
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n", wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
msg_header->msg_type); msg_header->msg_type);
break; return -ENOMEM;
} }
msg_ind->msg_len = len; msg_ind->msg_len = len;
...@@ -2257,6 +2257,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) ...@@ -2257,6 +2257,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
wcn36xx_err("SMD_EVENT (%d) not supported\n", 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) static void wcn36xx_ind_smd_work(struct work_struct *work)
{ {
...@@ -2315,22 +2317,13 @@ int wcn36xx_smd_open(struct wcn36xx *wcn) ...@@ -2315,22 +2317,13 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
INIT_LIST_HEAD(&wcn->hal_ind_queue); INIT_LIST_HEAD(&wcn->hal_ind_queue);
spin_lock_init(&wcn->hal_ind_lock); spin_lock_init(&wcn->hal_ind_lock);
ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process); return 0;
if (ret) {
wcn36xx_err("failed to open control channel\n");
goto free_wq;
}
return ret;
free_wq:
destroy_workqueue(wcn->hal_ind_wq);
out: out:
return ret; return ret;
} }
void wcn36xx_smd_close(struct wcn36xx *wcn) void wcn36xx_smd_close(struct wcn36xx *wcn)
{ {
wcn->ctrl_ops->close();
destroy_workqueue(wcn->hal_ind_wq); destroy_workqueue(wcn->hal_ind_wq);
} }
...@@ -51,6 +51,7 @@ struct wcn36xx_hal_ind_msg { ...@@ -51,6 +51,7 @@ struct wcn36xx_hal_ind_msg {
}; };
struct wcn36xx; struct wcn36xx;
struct qcom_smd_channel;
int wcn36xx_smd_open(struct wcn36xx *wcn); int wcn36xx_smd_open(struct wcn36xx *wcn);
void wcn36xx_smd_close(struct wcn36xx *wcn); void wcn36xx_smd_close(struct wcn36xx *wcn);
...@@ -127,6 +128,10 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, 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_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value); 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, int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp); struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
......
...@@ -103,19 +103,6 @@ struct nv_data { ...@@ -103,19 +103,6 @@ struct nv_data {
u8 table; u8 table;
}; };
/* 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)(void *drv_priv, void *rsp_cb);
void (*close)(void);
int (*tx)(char *buf, size_t len);
int (*get_hw_mac)(u8 *addr);
int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
};
/** /**
* struct wcn36xx_vif - holds VIF related fields * struct wcn36xx_vif - holds VIF related fields
* *
...@@ -205,7 +192,13 @@ struct wcn36xx { ...@@ -205,7 +192,13 @@ struct wcn36xx {
void __iomem *ccu_base; void __iomem *ccu_base;
void __iomem *dxe_base; void __iomem *dxe_base;
struct wcn36xx_platform_ctrl_ops *ctrl_ops; 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;
/* /*
* smd_buf must be protected with smd_mutex to garantee * smd_buf must be protected with smd_mutex to garantee
* that all messages are sent one after another * that all messages are sent one after another
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment