wcn36xx: Transition driver to SMD client
authorBjorn Andersson <bjorn.andersson@linaro.org>
Wed, 11 Jan 2017 14:32:18 +0000 (16:32 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 12 Jan 2017 10:43:47 +0000 (12:43 +0200)
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: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/wcn36xx/Kconfig
drivers/net/wireless/ath/wcn36xx/dxe.c
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/smd.h
drivers/net/wireless/ath/wcn36xx/wcn36xx.h

index 591ebaea826564bf339f82b8152394dca022b5e8..4b83e87f0b9450bf431b48a168901371f1cab33c 100644 (file)
@@ -1,6 +1,8 @@
 config WCN36XX
        tristate "Qualcomm Atheros WCN3660/3680 support"
        depends on MAC80211 && HAS_DMA
+       depends on QCOM_WCNSS_CTRL || QCOM_WCNSS_CTRL=n
+       depends on QCOM_SMD || QCOM_SMD=n
        ---help---
          This module adds support for wireless adapters based on
          Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
index 231fd022f0f54e96b58c522061d6441cf650c404..87dfdaf9044cdf8b41aba6b8345e9d2f9dd325a6 100644 (file)
@@ -23,6 +23,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
 #include "wcn36xx.h"
 #include "txrx.h"
 
@@ -151,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;
 
@@ -678,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.
index e1d59da2ad20fca15deea2fb8c01e6830509d7da..3c2522b07c9090fb7c801ea6ef91c13d44c60efd 100644 (file)
 #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;
@@ -1058,8 +1062,7 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
        int ret;
 
        /* Set TX IRQ */
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          "wcnss_wlantx_irq");
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
        if (!res) {
                wcn36xx_err("failed to get tx_irq\n");
                return -ENOENT;
@@ -1067,14 +1070,29 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
        wcn->tx_irq = res->start;
 
        /* Set RX IRQ */
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          "wcnss_wlanrx_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;
 
+       /* 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);
        if (!mmio_node) {
                wcn36xx_err("failed to acquire qcom,mmio reference\n");
@@ -1115,11 +1133,14 @@ 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");
@@ -1130,11 +1151,23 @@ static int wcn36xx_probe(struct platform_device *pdev)
        wcn = hw->priv;
        wcn->hw = hw;
        wcn->dev = &pdev->dev;
-       wcn->ctrl_ops = pdev->dev.platform_data;
-
        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);
                SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
        }
@@ -1158,6 +1191,7 @@ out_wq:
 out_err:
        return ret;
 }
+
 static int wcn36xx_remove(struct platform_device *pdev)
 {
        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
@@ -1168,42 +1202,33 @@ static int wcn36xx_remove(struct platform_device *pdev)
        mutex_destroy(&wcn->hal_mutex);
 
        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->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");
index a443992320f2ed3aa2152b93d2d8ecb1819ec2fb..af0260add8418d1a5494eb624bdab87a8ea32200 100644 (file)
@@ -19,6 +19,7 @@
 #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 {
@@ -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->hal_buf, len);
+       ret = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
        if (ret) {
                wcn36xx_err("HAL TX failed\n");
                goto out;
@@ -2180,9 +2181,12 @@ 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;
+       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;
        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)
        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) + len, GFP_KERNEL);
+               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);
-                       break;
+                       return -ENOMEM;
                }
 
                msg_ind->msg_len = 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",
                              msg_header->msg_type);
        }
+
+       return 0;
 }
 static void wcn36xx_ind_smd_work(struct work_struct *work)
 {
@@ -2315,22 +2317,13 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
        INIT_LIST_HEAD(&wcn->hal_ind_queue);
        spin_lock_init(&wcn->hal_ind_lock);
 
-       ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
-       if (ret) {
-               wcn36xx_err("failed to open control channel\n");
-               goto free_wq;
-       }
-
-       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();
        destroy_workqueue(wcn->hal_ind_wq);
 }
index df80cbbd9d1bed9fea3daca6f65b87b8f053d7d3..40d829563c2b6cfcbd5bec10197f203170e73054 100644 (file)
@@ -51,6 +51,7 @@ struct wcn36xx_hal_ind_msg {
 };
 
 struct wcn36xx;
+struct qcom_smd_channel;
 
 int wcn36xx_smd_open(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);
 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);
index 22242d18e1fe3b44f7e66ff5f30ab914838e35e8..68cc06cf9bc092bdf1ff2ae97df94d5889b74c5f 100644 (file)
@@ -103,19 +103,6 @@ struct nv_data {
        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
  *
@@ -205,7 +192,13 @@ struct wcn36xx {
        void __iomem            *ccu_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
         * that all messages are sent one after another