diff --git a/os_if/linux/coex/inc/wlan_cfg80211_coex.h b/os_if/linux/coex/inc/wlan_cfg80211_coex.h new file mode 100644 index 000000000000..cd3e6bd43240 --- /dev/null +++ b/os_if/linux/coex/inc/wlan_cfg80211_coex.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * 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. + */ + +/** + * DOC: declares driver functions interfacing with linux kernel + */ + +#ifndef _WLAN_CFG80211_COEX_H_ +#define _WLAN_CFG80211_COEX_H_ +#include +#include + +#ifdef FEATURE_COEX +int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); +#else +static inline int +wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} +#endif +#endif diff --git a/os_if/linux/coex/src/wlan_cfg80211_coex.c b/os_if/linux/coex/src/wlan_cfg80211_coex.c new file mode 100644 index 000000000000..754b16796e48 --- /dev/null +++ b/os_if/linux/coex/src/wlan_cfg80211_coex.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * 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. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ +#include +#include +#include +#include +#include +#include +#include + +static const struct nla_policy +btc_chain_mode_policy[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1] = { + [QCA_VENDOR_ATTR_BTC_CHAIN_MODE] = {.type = NLA_U32}, + [QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART] = {.type = NLA_FLAG}, +}; + +static int +__wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + uint8_t mode, bool do_restart) +{ + QDF_STATUS status; + uint8_t cur_mode; + int err; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev_tmp; + int vdev_id; + struct coex_psoc_obj *coex_obj; + + if (!vdev) { + coex_err("Null vdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return -EINVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return -EINVAL; + + status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &cur_mode); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("failed to get cur BTC chain mode, status %d", status); + return -EFAULT; + } + + if (cur_mode == mode) + return -EALREADY; + + status = ucfg_coex_psoc_set_btc_chain_mode(psoc, mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + coex_err("unable to set BTC chain mode to %d", mode); + return -EFAULT; + } + + wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev_tmp) { + status = ucfg_coex_send_btc_chain_mode(vdev, mode); + err = qdf_status_to_os_return(status); + if (err) { + coex_err("Failed to set btc chain mode to %d for vdev %d", + mode, vdev_id); + return err; + } + coex_debug("Set btc chain mode to %d for vdev %d", + mode, vdev_id); + + if (!do_restart) + continue; + + wlan_coex_config_updated(vdev, COEX_CONFIG_BTC_CHAIN_MODE); + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to btc chain mode command parameters. + * @data_len: the length in byte of btc chain mode command parameters. + * + * Return: An error code or 0 on success. + */ +int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1]; + uint32_t mode; + bool restart; + + if (wlan_cfg80211_nla_parse(tb, QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX, + data, data_len, btc_chain_mode_policy)) { + coex_err("Invalid btc chain mode ATTR"); + return -EINVAL; + } + + if (!tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]) { + coex_err("btc chain mode - no attr mode"); + return -EINVAL; + } + + mode = nla_get_u32(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]); + if (mode < QCA_BTC_CHAIN_SHARED || mode > QCA_BTC_CHAIN_SEPARATED) { + coex_err("Invalid btc chain mode %d", mode); + return -EINVAL; + } + + restart = nla_get_flag(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART]); + + coex_debug("vdev_id %u mode %u restart %u", + wlan_vdev_get_id(vdev), mode, restart); + + return __wlan_cfg80211_coex_set_btc_chain_mode(vdev, mode, restart); +} diff --git a/umac/coex/core/inc/wlan_coex_main.h b/umac/coex/core/inc/wlan_coex_main.h index 23cf0fb3d84f..22cde21af03f 100644 --- a/umac/coex/core/inc/wlan_coex_main.h +++ b/umac/coex/core/inc/wlan_coex_main.h @@ -36,10 +36,12 @@ /** * struct coex_psoc_obj - coex object definition + * @btc_chain_mode: BT Coex chain mode. * @coex_config_updated: callback functions for each config type, which will * be called when config is updated. */ struct coex_psoc_obj { + uint8_t btc_chain_mode; update_coex_cb coex_config_updated[COEX_CONFIG_TYPE_MAX]; }; @@ -132,5 +134,27 @@ QDF_STATUS wlan_coex_psoc_created_notification(struct wlan_objmgr_psoc *psoc, */ QDF_STATUS wlan_coex_psoc_destroyed_notification(struct wlan_objmgr_psoc *psoc, void *arg_list); + +/** + * wlan_coex_psoc_set_btc_chain_mode() - private API to set BT coex chain mode + * for psoc + * @psoc: pointer to psoc object + * @val: BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +wlan_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val); + +/** + * wlan_coex_psoc_get_btc_chain_mode() - private API to get BT coex chain mode + * from psoc + * @psoc: pointer to psoc object + * @val: pointer to BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +wlan_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val); #endif #endif diff --git a/umac/coex/core/src/wlan_coex_main.c b/umac/coex/core/src/wlan_coex_main.c index 39bcb4efe245..d48b6e54eba2 100644 --- a/umac/coex/core/src/wlan_coex_main.c +++ b/umac/coex/core/src/wlan_coex_main.c @@ -71,6 +71,13 @@ QDF_STATUS wlan_coex_psoc_destroyed_notification(struct wlan_objmgr_psoc *psoc, QDF_STATUS wlan_coex_psoc_init(struct wlan_objmgr_psoc *psoc) { + struct coex_psoc_obj *coex_obj; + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + coex_obj->btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; return QDF_STATUS_SUCCESS; } @@ -124,3 +131,35 @@ wlan_coex_config_updated(struct wlan_objmgr_vdev *vdev, uint8_t type) return status; } + +QDF_STATUS +wlan_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val) +{ + struct coex_psoc_obj *coex_obj; + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + coex_obj->btc_chain_mode = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val) +{ + struct coex_psoc_obj *coex_obj; + + if (!val) { + coex_err("invalid param for getting btc chain mode"); + return QDF_STATUS_E_INVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + *val = coex_obj->btc_chain_mode; + return QDF_STATUS_SUCCESS; +} diff --git a/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h b/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h index 498301ffe623..2fd5a24230bf 100644 --- a/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h +++ b/umac/coex/dispatcher/inc/wlan_coex_ucfg_api.h @@ -24,6 +24,11 @@ #include "qdf_status.h" #include #include +#include "qca_vendor.h" + +#define WLAN_COEX_BTC_CHAIN_MODE_SHARED QCA_BTC_CHAIN_SHARED +#define WLAN_COEX_BTC_CHAIN_MODE_SEPARATED QCA_BTC_CHAIN_SEPARATED +#define WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED 0xFF /** * enum coex_config_type - coex config type definitions @@ -58,6 +63,36 @@ QDF_STATUS ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, enum coex_config_type type, update_coex_cb handler); + +/** + * ucfg_coex_psoc_set_btc_chain_mode() - API to set BT coex chain mode for psoc + * @psoc: pointer to psoc object + * @val: BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +ucfg_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val); + +/** + * ucfg_coex_psoc_get_btc_chain_mode() - API to get BT coex chain mode from psoc + * @psoc: pointer to psoc object + * @val: pointer to BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val); + +/** + * ucfg_coex_send_btc_chain_mode() - API to send BT coex config to target if + * @vdev: pointer to vdev object + * @mode: BT coex chain mode + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, uint8_t mode); #else static inline QDF_STATUS ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, @@ -66,5 +101,20 @@ ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, { return QDF_STATUS_SUCCESS; } + +static inline QDF_STATUS +ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val) +{ + if (val) + *val = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, uint8_t mode) +{ + return QDF_STATUS_SUCCESS; +} #endif #endif diff --git a/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c b/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c index fdf1f1564c8f..68321ee4c1f5 100644 --- a/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c +++ b/umac/coex/dispatcher/src/wlan_coex_ucfg_api.c @@ -20,6 +20,7 @@ #include #include +#include "wmi_unified.h" QDF_STATUS ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, @@ -41,3 +42,33 @@ ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } + +QDF_STATUS +ucfg_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t val) +{ + return wlan_coex_psoc_set_btc_chain_mode(psoc, val); +} + +QDF_STATUS +ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, uint8_t *val) +{ + return wlan_coex_psoc_get_btc_chain_mode(psoc, val); +} + +QDF_STATUS +ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, uint8_t mode) +{ + struct coex_config_params param = {0}; + + if (mode != WLAN_COEX_BTC_CHAIN_MODE_SHARED && + mode != WLAN_COEX_BTC_CHAIN_MODE_SEPARATED) + return QDF_STATUS_E_INVAL; + + param.vdev_id = wlan_vdev_get_id(vdev); + param.config_type = WMI_COEX_CONFIG_BTCOEX_SEPARATE_CHAIN_MODE; + param.config_arg1 = mode; + + coex_debug("send btc chain mode %d for vdev %d", mode, param.vdev_id); + + return wlan_coex_config_send(vdev, ¶m); +}