The mainline kernel now has the necessary implementations for SMD, SMSM and
WCNSS_CTRL. This series provides the changes necessary for the wcn36xx driver
to utilize this infrastructure and make this driver work in mainline.
A driver for loading the WCNSS firmware, through remoteproc, has been posted
here [1]. Upon starting this the necessary SMD channels will be registered,
which triggers the probe of the wcn36xx driver.
With this, the only missing piece for having fully working Qualcomm WiFi in
mainline is the RPM clock-controller, needed by the remoteproc driver for doing
XO calibration during boot of the WCNSS core. This is being worked on
separately.
[1] https://lkml.org/lkml/2015/12/27/185
Bjorn Andersson (4):
wcn36xx: Fold indication payload into message header
wcn36xx: Change indication list lock to spinlock
wcn36xx: Transition driver to SMD client
dt: binding: Add Qualcomm wcn36xx WiFi binding
.../bindings/net/wireless/qcom,wcn36xx-wifi.txt | 76 ++++++++++++++
drivers/net/wireless/ath/wcn36xx/Kconfig | 2 +-
drivers/net/wireless/ath/wcn36xx/dxe.c | 16 +--
drivers/net/wireless/ath/wcn36xx/main.c | 111 ++++++++++++---------
drivers/net/wireless/ath/wcn36xx/smd.c | 51 +++++-----
drivers/net/wireless/ath/wcn36xx/smd.h | 6 +-
drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 23 ++---
7 files changed, 188 insertions(+), 97 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
--
2.5.0
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 <[email protected]>
---
drivers/net/wireless/ath/wcn36xx/Kconfig | 2 +-
drivers/net/wireless/ath/wcn36xx/dxe.c | 16 +++--
drivers/net/wireless/ath/wcn36xx/main.c | 111 +++++++++++++++++------------
drivers/net/wireless/ath/wcn36xx/smd.c | 26 ++++---
drivers/net/wireless/ath/wcn36xx/smd.h | 4 ++
drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 21 ++----
6 files changed, 99 insertions(+), 81 deletions(-)
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/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index f8dfa05b290a..47f3937a7ab9 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 <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
#include "wcn36xx.h"
#include "txrx.h"
@@ -150,9 +151,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;
@@ -676,9 +680,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.
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 7c169abdbafe..8659e3f997d2 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -19,6 +19,9 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/smem_state.h>
#include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask;
@@ -981,48 +984,63 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
}
static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
- struct platform_device *pdev)
+ struct device *dev)
{
- struct resource *res;
+ u32 mmio[2];
+ int ret;
+
/* Set TX IRQ */
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "wcnss_wlantx_irq");
- if (!res) {
+ wcn->tx_irq = irq_of_parse_and_map(dev->of_node, 0);
+ if (!wcn->tx_irq) {
wcn36xx_err("failed to get tx_irq\n");
return -ENOENT;
}
- wcn->tx_irq = res->start;
/* Set RX IRQ */
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "wcnss_wlanrx_irq");
- if (!res) {
+ wcn->rx_irq = irq_of_parse_and_map(dev->of_node, 1);
+ if (!wcn->rx_irq) {
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(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;
+ }
+
+ /* Acquire SMSM tx rings empty handle */
+ wcn->tx_rings_empty_state = qcom_smem_state_get(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;
+ }
/* Map the memory */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "wcnss_mmio");
- if (!res) {
- wcn36xx_err("failed to get mmio\n");
+ ret = of_property_read_u32_array(dev->of_node, "qcom,wcnss-mmio", mmio, 2);
+ if (ret) {
+ wcn36xx_err("failed to get qcom,wcnss-mmio\n");
return -ENOENT;
}
- wcn->mmio = ioremap(res->start, resource_size(res));
+
+ wcn->mmio = ioremap(mmio[0], mmio[1]);
if (!wcn->mmio) {
wcn36xx_err("failed to map io memory\n");
return -ENOMEM;
}
+
return 0;
}
-static int wcn36xx_probe(struct platform_device *pdev)
+static int wcn36xx_probe(struct qcom_smd_device *sdev)
{
struct ieee80211_hw *hw;
struct wcn36xx *wcn;
int ret;
- u8 addr[ETH_ALEN];
+ const u8 *addr;
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
@@ -1032,20 +1050,27 @@ static int wcn36xx_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto out_err;
}
- platform_set_drvdata(pdev, hw);
+ dev_set_drvdata(&sdev->dev, hw);
wcn = hw->priv;
wcn->hw = hw;
- wcn->dev = &pdev->dev;
- wcn->ctrl_ops = pdev->dev.platform_data;
+ wcn->dev = &sdev->dev;
+ wcn->smd_channel = sdev->channel;
mutex_init(&wcn->hal_mutex);
- if (!wcn->ctrl_ops->get_hw_mac(addr)) {
+ sdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ addr = of_get_property(sdev->dev.of_node, "local-mac-address", &ret);
+ if (addr && ret != ETH_ALEN) {
+ wcn36xx_err("invalid local-mac-address\n");
+ ret = -EINVAL;
+ goto out_err;
+ } else if (addr) {
wcn36xx_info("mac address: %pM\n", addr);
SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
}
- ret = wcn36xx_platform_get_resources(wcn, pdev);
+ ret = wcn36xx_platform_get_resources(wcn, &sdev->dev);
if (ret)
goto out_wq;
@@ -1063,9 +1088,10 @@ out_wq:
out_err:
return ret;
}
-static int wcn36xx_remove(struct platform_device *pdev)
+
+static void wcn36xx_remove(struct qcom_smd_device *sdev)
{
- struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
struct wcn36xx *wcn = hw->priv;
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
@@ -1073,41 +1099,34 @@ 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->mmio);
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,wcn3620-wlan" },
+ { .compatible = "qcom,wcn3660-wlan" },
+ { .compatible = "qcom,wcn3680-wlan" },
{}
};
-MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
-static struct platform_driver wcn36xx_driver = {
+static struct qcom_smd_driver wcn36xx_driver = {
.probe = wcn36xx_probe,
.remove = wcn36xx_remove,
+ .callback = wcn36xx_smd_rsp_process,
.driver = {
.name = "wcn36xx",
+ .of_match_table = wcn36xx_of_match,
+ .owner = THIS_MODULE,
},
- .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_qcom_smd_driver(wcn36xx_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Eugene Krasnikov [email protected]");
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 4307429740a9..2bf42787a4af 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -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;
@@ -2100,9 +2101,13 @@ out:
mutex_unlock(&wcn->hal_mutex);
return ret;
}
-static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
+ 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 = dev_get_drvdata(&sdev->dev);
+ struct wcn36xx *wcn = hw->priv;
struct wcn36xx_hal_ind_msg *msg_ind;
wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
@@ -2151,7 +2156,7 @@ 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
@@ -2175,6 +2180,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)
{
@@ -2232,22 +2239,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);
}
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 21cc4ac7b5ca..4d96d56d266f 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -60,6 +60,7 @@ struct wcn36xx_hal_ind_msg {
};
struct wcn36xx;
+struct qcom_smd_device;
int wcn36xx_smd_open(struct wcn36xx *wcn);
void wcn36xx_smd_close(struct wcn36xx *wcn);
@@ -136,4 +137,7 @@ 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_device *sdev,
+ const void *buf, size_t len);
#endif /* _SMD_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 7997cc1312ee..4be81f66e167 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -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
*
@@ -204,7 +191,13 @@ struct wcn36xx {
int rx_irq;
void __iomem *mmio;
- 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
--
2.5.0
On Tue 29 Dec 10:34 PST 2015, Rob Herring wrote:
> On Sun, Dec 27, 2015 at 05:34:27PM -0800, Bjorn Andersson wrote:
> > Add binding representing the Qualcomm wcn3620/60/80 WiFi block.
> > Signed-off-by: Bjorn Andersson <[email protected]>
> > ---
> > .../bindings/net/wireless/qcom,wcn36xx-wifi.txt | 76 ++++++++++++++++++++++
> > 1 file changed, 76 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> >
> > diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> > new file mode 100644
> > index 000000000000..7b314b9f30af
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> > @@ -0,0 +1,76 @@
> > +Qualcomm WCN36xx WiFi Binding
> > +
> > +This binding describes the Qualcomm WCN36xx WiFi hardware. The hardware block
> > +is part of the Qualcomm WCNSS core, a WiFi/BT/FM combo chip, found in a variety
> > +of Qualcomm platforms.
>
> Are BT/FM functions completely separate? If so, separate bindings are
> okay. If not, then we need to describe the full chip.
>
It's three different hardware blocks (WiFi, BT and FM-radio) with shared
RF-hardware and an ARM core for control logic.
There seems to be some control commands going towards the BT part that
controls coexistence properties of the RF-hardware, but other than that
I see it as logically separate blocks.
So I think it's fine to model this as separate pieces in DT.
Regards,
Bjorn
Add binding representing the Qualcomm wcn3620/60/80 WiFi block.
Signed-off-by: Bjorn Andersson <[email protected]>
---
.../bindings/net/wireless/qcom,wcn36xx-wifi.txt | 76 ++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
new file mode 100644
index 000000000000..7b314b9f30af
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
@@ -0,0 +1,76 @@
+Qualcomm WCN36xx WiFi Binding
+
+This binding describes the Qualcomm WCN36xx WiFi hardware. The hardware block
+is part of the Qualcomm WCNSS core, a WiFi/BT/FM combo chip, found in a variety
+of Qualcomm platforms.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,wcn3620-wlan",
+ "qcom,wcn3660-wlan",
+ "qcom,wcn3680-wlan"
+
+- qcom,smd-channel:
+ Usage: required
+ Value type: <string>
+ Definition: standard SMD property specifying the SMD channel used for
+ communication with the WiFi firmware
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the two IRQs for tx and rx respectively
+
+- qcom,wcnss-mmio:
+ Usage: required
+ Value type: <prop-encoed-array>
+ Definition: should specify base address and size of the WiFi related
+ registers of WCNSS
+
+- qcom,state:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the tx-enable and tx-ring-empty state
+ references
+
+- qcom,state-names:
+ Usage: required
+ Value type: <stringlist>
+ Definition: name of the states, must be "tx-enable", "tx-rings-empty";
+
+- local-mac-address:
+ Usage: optional
+ Value type: <prop-encoded-array> encoded as array of hex numbers
+ Definition: specifies MAC address that was assigned to the network
+ device described by the node containing this property.
+
+= EXAMPLE
+The following example represents a SMD node, with one edge representing the
+"pronto" subsystem, with the wcn3680 WiFi device described; as found on the
+8974 platform.
+
+smd {
+ compatible = "qcom,smd";
+
+ pronto {
+ interrupts = <0 142 1>;
+
+ qcom,ipc = <&apcs 8 17>;
+ qcom,smd-edge = <6>;
+
+ wifi {
+ compatible = "qcom,wcn3680-wlan";
+ qcom,smd-channels = "WLAN_CTRL";
+
+ interrupts = <0 145 0>, <0 146 0>;
+ interrupt-names = "tx", "rx";
+
+ qcom,wcnss-mmio = <0xfb000000 0x21b000>;
+
+ qcom,state = <&apps_smsm 10>, <&apps_smsm 9>;
+ qcom,state-names = "tx-enable", "tx-rings-empty";
+ };
+ };
+};
--
2.5.0
On Sun, 27 Dec 2015 17:34:25 -0800
Bjorn Andersson <[email protected]> wrote:
> In preparation for handling incoming messages from IRQ context, change
> the indication list lock to a spinlock
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/net/wireless/ath/wcn36xx/smd.c | 12 ++++++------
> drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 +-
> 2 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
> index 6b5dbe6f0d0a..4307429740a9 100644
> --- a/drivers/net/wireless/ath/wcn36xx/smd.c
> +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
> @@ -2165,10 +2165,10 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
> msg_ind->msg_len = len;
> memcpy(msg_ind->msg, buf, len);
>
> - mutex_lock(&wcn->hal_ind_mutex);
> + spin_lock(&wcn->hal_ind_lock);
If you are going to handle messages in IRQ context, that better be a spin_lock_irq() or spin_lock_bh().
On Sun, Dec 27, 2015 at 05:34:27PM -0800, Bjorn Andersson wrote:
> Add binding representing the Qualcomm wcn3620/60/80 WiFi block.
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> .../bindings/net/wireless/qcom,wcn36xx-wifi.txt | 76 ++++++++++++++++++++++
> 1 file changed, 76 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
>
> diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> new file mode 100644
> index 000000000000..7b314b9f30af
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> @@ -0,0 +1,76 @@
> +Qualcomm WCN36xx WiFi Binding
> +
> +This binding describes the Qualcomm WCN36xx WiFi hardware. The hardware block
> +is part of the Qualcomm WCNSS core, a WiFi/BT/FM combo chip, found in a variety
> +of Qualcomm platforms.
Are BT/FM functions completely separate? If so, separate bindings are
okay. If not, then we need to describe the full chip.
Rob
On Mon 28 Dec 15:06 PST 2015, Stephen Hemminger wrote:
> On Sun, 27 Dec 2015 17:34:25 -0800
> Bjorn Andersson <[email protected]> wrote:
>
> > In preparation for handling incoming messages from IRQ context, change
> > the indication list lock to a spinlock
> >
> > Signed-off-by: Bjorn Andersson <[email protected]>
> > ---
> > drivers/net/wireless/ath/wcn36xx/smd.c | 12 ++++++------
> > drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 +-
> > 2 files changed, 7 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
> > index 6b5dbe6f0d0a..4307429740a9 100644
> > --- a/drivers/net/wireless/ath/wcn36xx/smd.c
> > +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
> > @@ -2165,10 +2165,10 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
> > msg_ind->msg_len = len;
> > memcpy(msg_ind->msg, buf, len);
> >
> > - mutex_lock(&wcn->hal_ind_mutex);
> > + spin_lock(&wcn->hal_ind_lock);
>
> If you are going to handle messages in IRQ context, that better be a
> spin_lock_irq() or spin_lock_bh().
This function is executed in IRQ context after the next patch, as such I
use spin_lock() here and spin_lock_irqsave() in the worker thread
(wcn36xx_ind_smd_work()).
Is this not how the spin_lock API should be used?
Regards,
Bjorn
On Sun, Dec 27, 2015 at 05:34:27PM -0800, Bjorn Andersson wrote:
> Add binding representing the Qualcomm wcn3620/60/80 WiFi block.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
<snip>
> +
> +- qcom,wcnss-mmio:
> + Usage: required
> + Value type: <prop-encoed-array>
nit: encoded
> + Definition: should specify base address and size of the WiFi related
> + registers of WCNSS
> +
> +- qcom,state:
> + Usage: required
> + Value type: <prop-encoded-array>
> + Definition: should specify the tx-enable and tx-ring-empty state
> + references
> +
<snip>
Otherwise looks good.
Reviewed-by: Andy Gross <[email protected]>
In preparation for handling incoming messages from IRQ context, change
the indication list lock to a spinlock
Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/net/wireless/ath/wcn36xx/smd.c | 12 ++++++------
drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 6b5dbe6f0d0a..4307429740a9 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -2165,10 +2165,10 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
msg_ind->msg_len = len;
memcpy(msg_ind->msg, buf, len);
- mutex_lock(&wcn->hal_ind_mutex);
+ 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:
@@ -2182,8 +2182,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,
@@ -2215,8 +2216,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
msg_header->msg_type);
}
list_del(wcn->hal_ind_queue.next);
+ 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)
{
@@ -2229,7 +2230,7 @@ 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);
+ spin_lock_init(&wcn->hal_ind_lock);
ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
if (ret) {
@@ -2249,5 +2250,4 @@ void wcn36xx_smd_close(struct wcn36xx *wcn)
{
wcn->ctrl_ops->close();
destroy_workqueue(wcn->hal_ind_wq);
- mutex_destroy(&wcn->hal_ind_mutex);
}
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 7b41e833e18c..7997cc1312ee 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -215,7 +215,7 @@ 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;
/* DXE channels */
--
2.5.0
On Tue, Dec 29, 2015 at 11:03:57AM -0800, Bjorn Andersson wrote:
> On Tue 29 Dec 10:34 PST 2015, Rob Herring wrote:
>
> > On Sun, Dec 27, 2015 at 05:34:27PM -0800, Bjorn Andersson wrote:
> > > Add binding representing the Qualcomm wcn3620/60/80 WiFi block.
> > > Signed-off-by: Bjorn Andersson <[email protected]>
> > > ---
> > > .../bindings/net/wireless/qcom,wcn36xx-wifi.txt | 76 ++++++++++++++++++++++
> > > 1 file changed, 76 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> > > new file mode 100644
> > > index 000000000000..7b314b9f30af
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
> > > @@ -0,0 +1,76 @@
> > > +Qualcomm WCN36xx WiFi Binding
> > > +
> > > +This binding describes the Qualcomm WCN36xx WiFi hardware. The hardware block
> > > +is part of the Qualcomm WCNSS core, a WiFi/BT/FM combo chip, found in a variety
> > > +of Qualcomm platforms.
> >
> > Are BT/FM functions completely separate? If so, separate bindings are
> > okay. If not, then we need to describe the full chip.
> >
>
> It's three different hardware blocks (WiFi, BT and FM-radio) with shared
> RF-hardware and an ARM core for control logic.
>
> There seems to be some control commands going towards the BT part that
> controls coexistence properties of the RF-hardware, but other than that
> I see it as logically separate blocks.
>
>
> So I think it's fine to model this as separate pieces in DT.
Okay.
Acked-by: Rob Herring <[email protected]>
Merge the two allocation instead of separately allocating room for the
indication payload.
Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/net/wireless/ath/wcn36xx/smd.c | 15 ++++++---------
drivers/net/wireless/ath/wcn36xx/smd.h | 2 +-
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 74f56a81ad9a..6b5dbe6f0d0a 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -2151,14 +2151,8 @@ 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), 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_KERNEL);
+ if (!msg_ind) {
/*
* FIXME: Do something smarter then just
* printing an error.
@@ -2167,6 +2161,10 @@ nomem:
msg_header->msg_type);
break;
}
+
+ msg_ind->msg_len = len;
+ memcpy(msg_ind->msg, buf, len);
+
mutex_lock(&wcn->hal_ind_mutex);
list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
@@ -2217,7 +2215,6 @@ 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);
kfree(hal_ind_msg);
mutex_unlock(&wcn->hal_ind_mutex);
}
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 8361f9e3995b..21cc4ac7b5ca 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -55,8 +55,8 @@ struct wcn36xx_fw_msg_status_rsp_v2 {
struct wcn36xx_hal_ind_msg {
struct list_head list;
- u8 *msg;
size_t msg_len;
+ u8 msg[];
};
struct wcn36xx;
--
2.5.0
On Tue, Dec 29, 2015 at 11:03 AM, Bjorn Andersson <[email protected]> wrote:
> On Tue 29 Dec 10:34 PST 2015, Rob Herring wrote:
>
>> On Sun, Dec 27, 2015 at 05:34:27PM -0800, Bjorn Andersson wrote:
>> > Add binding representing the Qualcomm wcn3620/60/80 WiFi block.
>> > Signed-off-by: Bjorn Andersson <[email protected]>
>> > ---
>> > .../bindings/net/wireless/qcom,wcn36xx-wifi.txt | 76 ++++++++++++++++++++++
>> > 1 file changed, 76 insertions(+)
>> > create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
>> > new file mode 100644
>> > index 000000000000..7b314b9f30af
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/net/wireless/qcom,wcn36xx-wifi.txt
>> > @@ -0,0 +1,76 @@
>> > +Qualcomm WCN36xx WiFi Binding
>> > +
>> > +This binding describes the Qualcomm WCN36xx WiFi hardware. The hardware block
>> > +is part of the Qualcomm WCNSS core, a WiFi/BT/FM combo chip, found in a variety
>> > +of Qualcomm platforms.
>>
>> Are BT/FM functions completely separate? If so, separate bindings are
>> okay. If not, then we need to describe the full chip.
>>
>
> It's three different hardware blocks (WiFi, BT and FM-radio) with shared
> RF-hardware and an ARM core for control logic.
>
> There seems to be some control commands going towards the BT part that
> controls coexistence properties of the RF-hardware, but other than that
> I see it as logically separate blocks.
>
>
> So I think it's fine to model this as separate pieces in DT.
>
After more testing I've concluded that there is a timing dependency
between the WiFi driver and the wcnss_ctrl driver. If the WiFi driver
starts communicating with the WLAN subsystem in the WCNSS block before
we have finished uploading the NV data to the WCNSS core further
communication will fail.
So looks like I need to remodel this slightly to take this into account :/
Regards,
Bjorn
Better late than never! Looks good to me.
2015-12-28 1:34 GMT+00:00 Bjorn Andersson <[email protected]>:
> 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 <[email protected]>
> ---
> drivers/net/wireless/ath/wcn36xx/Kconfig | 2 +-
> drivers/net/wireless/ath/wcn36xx/dxe.c | 16 +++--
> drivers/net/wireless/ath/wcn36xx/main.c | 111 +++++++++++++++++------------
> drivers/net/wireless/ath/wcn36xx/smd.c | 26 ++++---
> drivers/net/wireless/ath/wcn36xx/smd.h | 4 ++
> drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 21 ++----
> 6 files changed, 99 insertions(+), 81 deletions(-)
>
> 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/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
> index f8dfa05b290a..47f3937a7ab9 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 <linux/interrupt.h>
> +#include <linux/soc/qcom/smem_state.h>
> #include "wcn36xx.h"
> #include "txrx.h"
>
> @@ -150,9 +151,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;
>
> @@ -676,9 +680,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.
> diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
> index 7c169abdbafe..8659e3f997d2 100644
> --- a/drivers/net/wireless/ath/wcn36xx/main.c
> +++ b/drivers/net/wireless/ath/wcn36xx/main.c
> @@ -19,6 +19,9 @@
> #include <linux/module.h>
> #include <linux/firmware.h>
> #include <linux/platform_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/soc/qcom/smd.h>
> +#include <linux/soc/qcom/smem_state.h>
> #include "wcn36xx.h"
>
> unsigned int wcn36xx_dbg_mask;
> @@ -981,48 +984,63 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
> }
>
> static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
> - struct platform_device *pdev)
> + struct device *dev)
> {
> - struct resource *res;
> + u32 mmio[2];
> + int ret;
> +
> /* Set TX IRQ */
> - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
> - "wcnss_wlantx_irq");
> - if (!res) {
> + wcn->tx_irq = irq_of_parse_and_map(dev->of_node, 0);
> + if (!wcn->tx_irq) {
> wcn36xx_err("failed to get tx_irq\n");
> return -ENOENT;
> }
> - wcn->tx_irq = res->start;
>
> /* Set RX IRQ */
> - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
> - "wcnss_wlanrx_irq");
> - if (!res) {
> + wcn->rx_irq = irq_of_parse_and_map(dev->of_node, 1);
> + if (!wcn->rx_irq) {
> 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(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;
> + }
> +
> + /* Acquire SMSM tx rings empty handle */
> + wcn->tx_rings_empty_state = qcom_smem_state_get(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;
> + }
>
> /* Map the memory */
> - res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> - "wcnss_mmio");
> - if (!res) {
> - wcn36xx_err("failed to get mmio\n");
> + ret = of_property_read_u32_array(dev->of_node, "qcom,wcnss-mmio", mmio, 2);
> + if (ret) {
> + wcn36xx_err("failed to get qcom,wcnss-mmio\n");
> return -ENOENT;
> }
> - wcn->mmio = ioremap(res->start, resource_size(res));
> +
> + wcn->mmio = ioremap(mmio[0], mmio[1]);
> if (!wcn->mmio) {
> wcn36xx_err("failed to map io memory\n");
> return -ENOMEM;
> }
> +
> return 0;
> }
>
> -static int wcn36xx_probe(struct platform_device *pdev)
> +static int wcn36xx_probe(struct qcom_smd_device *sdev)
> {
> struct ieee80211_hw *hw;
> struct wcn36xx *wcn;
> int ret;
> - u8 addr[ETH_ALEN];
> + const u8 *addr;
>
> wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
>
> @@ -1032,20 +1050,27 @@ static int wcn36xx_probe(struct platform_device *pdev)
> ret = -ENOMEM;
> goto out_err;
> }
> - platform_set_drvdata(pdev, hw);
> + dev_set_drvdata(&sdev->dev, hw);
> wcn = hw->priv;
> wcn->hw = hw;
> - wcn->dev = &pdev->dev;
> - wcn->ctrl_ops = pdev->dev.platform_data;
> + wcn->dev = &sdev->dev;
> + wcn->smd_channel = sdev->channel;
>
> mutex_init(&wcn->hal_mutex);
>
> - if (!wcn->ctrl_ops->get_hw_mac(addr)) {
> + sdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> + addr = of_get_property(sdev->dev.of_node, "local-mac-address", &ret);
> + if (addr && ret != ETH_ALEN) {
> + wcn36xx_err("invalid local-mac-address\n");
> + ret = -EINVAL;
> + goto out_err;
> + } else if (addr) {
> wcn36xx_info("mac address: %pM\n", addr);
> SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
> }
>
> - ret = wcn36xx_platform_get_resources(wcn, pdev);
> + ret = wcn36xx_platform_get_resources(wcn, &sdev->dev);
> if (ret)
> goto out_wq;
>
> @@ -1063,9 +1088,10 @@ out_wq:
> out_err:
> return ret;
> }
> -static int wcn36xx_remove(struct platform_device *pdev)
> +
> +static void wcn36xx_remove(struct qcom_smd_device *sdev)
> {
> - struct ieee80211_hw *hw = platform_get_drvdata(pdev);
> + struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
> struct wcn36xx *wcn = hw->priv;
> wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
>
> @@ -1073,41 +1099,34 @@ 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->mmio);
> 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,wcn3620-wlan" },
> + { .compatible = "qcom,wcn3660-wlan" },
> + { .compatible = "qcom,wcn3680-wlan" },
> {}
> };
> -MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
> +MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
>
> -static struct platform_driver wcn36xx_driver = {
> +static struct qcom_smd_driver wcn36xx_driver = {
> .probe = wcn36xx_probe,
> .remove = wcn36xx_remove,
> + .callback = wcn36xx_smd_rsp_process,
> .driver = {
> .name = "wcn36xx",
> + .of_match_table = wcn36xx_of_match,
> + .owner = THIS_MODULE,
> },
> - .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_qcom_smd_driver(wcn36xx_driver);
>
> MODULE_LICENSE("Dual BSD/GPL");
> MODULE_AUTHOR("Eugene Krasnikov [email protected]");
> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
> index 4307429740a9..2bf42787a4af 100644
> --- a/drivers/net/wireless/ath/wcn36xx/smd.c
> +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
> @@ -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;
> @@ -2100,9 +2101,13 @@ out:
> mutex_unlock(&wcn->hal_mutex);
> return ret;
> }
> -static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
> +
> +int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
> + 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 = dev_get_drvdata(&sdev->dev);
> + struct wcn36xx *wcn = hw->priv;
> struct wcn36xx_hal_ind_msg *msg_ind;
> wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
>
> @@ -2151,7 +2156,7 @@ 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
> @@ -2175,6 +2180,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)
> {
> @@ -2232,22 +2239,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);
> }
> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
> index 21cc4ac7b5ca..4d96d56d266f 100644
> --- a/drivers/net/wireless/ath/wcn36xx/smd.h
> +++ b/drivers/net/wireless/ath/wcn36xx/smd.h
> @@ -60,6 +60,7 @@ struct wcn36xx_hal_ind_msg {
> };
>
> struct wcn36xx;
> +struct qcom_smd_device;
>
> int wcn36xx_smd_open(struct wcn36xx *wcn);
> void wcn36xx_smd_close(struct wcn36xx *wcn);
> @@ -136,4 +137,7 @@ 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_device *sdev,
> + const void *buf, size_t len);
> #endif /* _SMD_H_ */
> diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
> index 7997cc1312ee..4be81f66e167 100644
> --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
> +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
> @@ -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
> *
> @@ -204,7 +191,13 @@ struct wcn36xx {
> int rx_irq;
> void __iomem *mmio;
>
> - 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
> --
> 2.5.0
>
--
Best regards,
Eugene
On Mon, Jan 11, 2016 at 1:02 AM, Eugene Krasnikov <[email protected]> wrote:
> Better late than never! Looks good to me.
>
Unfortunately I ran into an issue with ordering of operations between
the WiFi driver and the wcnss_ctrl driver. So an updated series is on
the way, but this depends on changes to the wcnss_ctrl driver, which
are being reviewed right now.
Regards,
Bjorn
> 2015-12-28 1:34 GMT+00:00 Bjorn Andersson <[email protected]>:
>> 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 <[email protected]>
>> ---
>> drivers/net/wireless/ath/wcn36xx/Kconfig | 2 +-
>> drivers/net/wireless/ath/wcn36xx/dxe.c | 16 +++--
>> drivers/net/wireless/ath/wcn36xx/main.c | 111 +++++++++++++++++------------
>> drivers/net/wireless/ath/wcn36xx/smd.c | 26 ++++---
>> drivers/net/wireless/ath/wcn36xx/smd.h | 4 ++
>> drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 21 ++----
>> 6 files changed, 99 insertions(+), 81 deletions(-)
>>
>> 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/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
>> index f8dfa05b290a..47f3937a7ab9 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 <linux/interrupt.h>
>> +#include <linux/soc/qcom/smem_state.h>
>> #include "wcn36xx.h"
>> #include "txrx.h"
>>
>> @@ -150,9 +151,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;
>>
>> @@ -676,9 +680,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.
>> diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
>> index 7c169abdbafe..8659e3f997d2 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/main.c
>> +++ b/drivers/net/wireless/ath/wcn36xx/main.c
>> @@ -19,6 +19,9 @@
>> #include <linux/module.h>
>> #include <linux/firmware.h>
>> #include <linux/platform_device.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/soc/qcom/smd.h>
>> +#include <linux/soc/qcom/smem_state.h>
>> #include "wcn36xx.h"
>>
>> unsigned int wcn36xx_dbg_mask;
>> @@ -981,48 +984,63 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
>> }
>>
>> static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
>> - struct platform_device *pdev)
>> + struct device *dev)
>> {
>> - struct resource *res;
>> + u32 mmio[2];
>> + int ret;
>> +
>> /* Set TX IRQ */
>> - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> - "wcnss_wlantx_irq");
>> - if (!res) {
>> + wcn->tx_irq = irq_of_parse_and_map(dev->of_node, 0);
>> + if (!wcn->tx_irq) {
>> wcn36xx_err("failed to get tx_irq\n");
>> return -ENOENT;
>> }
>> - wcn->tx_irq = res->start;
>>
>> /* Set RX IRQ */
>> - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> - "wcnss_wlanrx_irq");
>> - if (!res) {
>> + wcn->rx_irq = irq_of_parse_and_map(dev->of_node, 1);
>> + if (!wcn->rx_irq) {
>> 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(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;
>> + }
>> +
>> + /* Acquire SMSM tx rings empty handle */
>> + wcn->tx_rings_empty_state = qcom_smem_state_get(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;
>> + }
>>
>> /* Map the memory */
>> - res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>> - "wcnss_mmio");
>> - if (!res) {
>> - wcn36xx_err("failed to get mmio\n");
>> + ret = of_property_read_u32_array(dev->of_node, "qcom,wcnss-mmio", mmio, 2);
>> + if (ret) {
>> + wcn36xx_err("failed to get qcom,wcnss-mmio\n");
>> return -ENOENT;
>> }
>> - wcn->mmio = ioremap(res->start, resource_size(res));
>> +
>> + wcn->mmio = ioremap(mmio[0], mmio[1]);
>> if (!wcn->mmio) {
>> wcn36xx_err("failed to map io memory\n");
>> return -ENOMEM;
>> }
>> +
>> return 0;
>> }
>>
>> -static int wcn36xx_probe(struct platform_device *pdev)
>> +static int wcn36xx_probe(struct qcom_smd_device *sdev)
>> {
>> struct ieee80211_hw *hw;
>> struct wcn36xx *wcn;
>> int ret;
>> - u8 addr[ETH_ALEN];
>> + const u8 *addr;
>>
>> wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
>>
>> @@ -1032,20 +1050,27 @@ static int wcn36xx_probe(struct platform_device *pdev)
>> ret = -ENOMEM;
>> goto out_err;
>> }
>> - platform_set_drvdata(pdev, hw);
>> + dev_set_drvdata(&sdev->dev, hw);
>> wcn = hw->priv;
>> wcn->hw = hw;
>> - wcn->dev = &pdev->dev;
>> - wcn->ctrl_ops = pdev->dev.platform_data;
>> + wcn->dev = &sdev->dev;
>> + wcn->smd_channel = sdev->channel;
>>
>> mutex_init(&wcn->hal_mutex);
>>
>> - if (!wcn->ctrl_ops->get_hw_mac(addr)) {
>> + sdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
>> +
>> + addr = of_get_property(sdev->dev.of_node, "local-mac-address", &ret);
>> + if (addr && ret != ETH_ALEN) {
>> + wcn36xx_err("invalid local-mac-address\n");
>> + ret = -EINVAL;
>> + goto out_err;
>> + } else if (addr) {
>> wcn36xx_info("mac address: %pM\n", addr);
>> SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
>> }
>>
>> - ret = wcn36xx_platform_get_resources(wcn, pdev);
>> + ret = wcn36xx_platform_get_resources(wcn, &sdev->dev);
>> if (ret)
>> goto out_wq;
>>
>> @@ -1063,9 +1088,10 @@ out_wq:
>> out_err:
>> return ret;
>> }
>> -static int wcn36xx_remove(struct platform_device *pdev)
>> +
>> +static void wcn36xx_remove(struct qcom_smd_device *sdev)
>> {
>> - struct ieee80211_hw *hw = platform_get_drvdata(pdev);
>> + struct ieee80211_hw *hw = dev_get_drvdata(&sdev->dev);
>> struct wcn36xx *wcn = hw->priv;
>> wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
>>
>> @@ -1073,41 +1099,34 @@ 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->mmio);
>> 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,wcn3620-wlan" },
>> + { .compatible = "qcom,wcn3660-wlan" },
>> + { .compatible = "qcom,wcn3680-wlan" },
>> {}
>> };
>> -MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
>> +MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
>>
>> -static struct platform_driver wcn36xx_driver = {
>> +static struct qcom_smd_driver wcn36xx_driver = {
>> .probe = wcn36xx_probe,
>> .remove = wcn36xx_remove,
>> + .callback = wcn36xx_smd_rsp_process,
>> .driver = {
>> .name = "wcn36xx",
>> + .of_match_table = wcn36xx_of_match,
>> + .owner = THIS_MODULE,
>> },
>> - .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_qcom_smd_driver(wcn36xx_driver);
>>
>> MODULE_LICENSE("Dual BSD/GPL");
>> MODULE_AUTHOR("Eugene Krasnikov [email protected]");
>> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
>> index 4307429740a9..2bf42787a4af 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/smd.c
>> +++ b/drivers/net/wireless/ath/wcn36xx/smd.c
>> @@ -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;
>> @@ -2100,9 +2101,13 @@ out:
>> mutex_unlock(&wcn->hal_mutex);
>> return ret;
>> }
>> -static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
>> +
>> +int wcn36xx_smd_rsp_process(struct qcom_smd_device *sdev,
>> + 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 = dev_get_drvdata(&sdev->dev);
>> + struct wcn36xx *wcn = hw->priv;
>> struct wcn36xx_hal_ind_msg *msg_ind;
>> wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
>>
>> @@ -2151,7 +2156,7 @@ 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
>> @@ -2175,6 +2180,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)
>> {
>> @@ -2232,22 +2239,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);
>> }
>> diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
>> index 21cc4ac7b5ca..4d96d56d266f 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/smd.h
>> +++ b/drivers/net/wireless/ath/wcn36xx/smd.h
>> @@ -60,6 +60,7 @@ struct wcn36xx_hal_ind_msg {
>> };
>>
>> struct wcn36xx;
>> +struct qcom_smd_device;
>>
>> int wcn36xx_smd_open(struct wcn36xx *wcn);
>> void wcn36xx_smd_close(struct wcn36xx *wcn);
>> @@ -136,4 +137,7 @@ 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_device *sdev,
>> + const void *buf, size_t len);
>> #endif /* _SMD_H_ */
>> diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
>> index 7997cc1312ee..4be81f66e167 100644
>> --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
>> +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
>> @@ -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
>> *
>> @@ -204,7 +191,13 @@ struct wcn36xx {
>> int rx_irq;
>> void __iomem *mmio;
>>
>> - 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
>> --
>> 2.5.0
>>
>
>
>
> --
> Best regards,
> Eugene