diff --git a/core/hdd/inc/wlan_hdd_dsc.h b/core/hdd/inc/wlan_hdd_dsc.h index 05b64165f2a9..7b496db90bc4 100644 --- a/core/hdd/inc/wlan_hdd_dsc.h +++ b/core/hdd/inc/wlan_hdd_dsc.h @@ -19,7 +19,22 @@ #ifndef __WLAN_HDD_DSC_H__ #define __WLAN_HDD_DSC_H__ -#include +#include "wlan_dsc.h" +#include "wlan_hdd_main.h" + +/** + * hdd_dsc_init() - global initializer for HDD DSC + * + * Return: None + */ +void hdd_dsc_init(void); + +/** + * hdd_dsc_deinit() - global deinitializer for HDD DSC + * + * Return: None + */ +void hdd_dsc_deinit(void); /** * hdd_dsc_psoc_from_wiphy() - get dsc psoc from wiphy @@ -28,4 +43,58 @@ * Return: dsc_psoc on success, NULL on failure */ struct dsc_psoc *hdd_dsc_psoc_from_wiphy(struct wiphy *wiphy); + +/** + * hdd_vdev_ops_register() - register a dsc_vdev to accept new operations + * @net_dev: the net_device which will be used for lookup during op start + * @dsc_vdev: the dsc_vdev to use to protect operations on @net_dev + * + * Return: None + */ +void hdd_vdev_ops_register(struct net_device *net_dev, + struct dsc_vdev *dsc_vdev); + +/** + * hdd_vdev_ops_unregister() - unregister a dsc_vdev to reject future operations + * @net_dev: the net_device to use for lookup + * + * Return: None + */ +void hdd_vdev_ops_unregister(struct net_device *net_dev); + +/** + * struct hdd_vdev_op - opaque handle used to identify a specific vdev operation + */ +struct hdd_vdev_op; + +/** + * hdd_vdev_op_start() - attempt to start a vdev-level driver operation + * @net_dev: the net_device to start the operation on + * + * Return: an operation handle on success, NULL on failure + */ +#define hdd_vdev_op_start(net_dev) __hdd_vdev_op_start(net_dev, __func__) + +/** + * hdd_vdev_op_start_with_wdev() - attempt to start a vdev-level driver + * operation using a wireless_dev instance + * @wdev: the wireless_dev to start the operation on + * + * Return: an operation handle on success, NULL on failure + */ +#define hdd_vdev_op_start_with_wdev(wdev) hdd_vdev_op_start((wdev)->netdev) + +struct hdd_vdev_op *__hdd_vdev_op_start(struct net_device *net_dev, + const char *func); + +/** + * hdd_vdev_op_stop() - stop a given vdev-level operation + * @op: an operation handle identifying the operation to stop + * + * Return: None + */ +#define hdd_vdev_op_stop(op) __hdd_vdev_op_stop(op, __func__) + +void __hdd_vdev_op_stop(struct hdd_vdev_op *op, const char *func); + #endif diff --git a/core/hdd/src/wlan_hdd_dsc.c b/core/hdd/src/wlan_hdd_dsc.c index 88c3941c984f..6a523abf00fc 100644 --- a/core/hdd/src/wlan_hdd_dsc.c +++ b/core/hdd/src/wlan_hdd_dsc.c @@ -15,6 +15,12 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ + +#include "sme_api.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_types.h" +#include "wlan_dsc.h" #include "wlan_hdd_dsc.h" struct dsc_psoc *hdd_dsc_psoc_from_wiphy(struct wiphy *wiphy) @@ -29,3 +35,132 @@ struct dsc_psoc *hdd_dsc_psoc_from_wiphy(struct wiphy *wiphy) return hdd_ctx->hdd_psoc->dsc_psoc; } + +/** + * struct hdd_vdev_kvp - net_device/dsc_vdev key-value-pair for mapping a + * net_device to a dsc_vdev + * @net_dev: the net_device key + * @dsc_vdev: the dsc_vdev value + */ +struct hdd_vdev_kvp { + struct net_device *net_dev; + struct dsc_vdev *dsc_vdev; +}; + +static struct hdd_vdev_kvp __hdd_vdev_map[CSR_ROAM_SESSION_MAX]; +static qdf_spinlock_t __hdd_vdev_lock; + +#define hdd_vdev_map_lock() qdf_spin_lock_bh(&__hdd_vdev_lock) +#define hdd_vdev_map_unlock() qdf_spin_unlock_bh(&__hdd_vdev_lock) +#define hdd_vdev_map_lock_assert() QDF_BUG(qdf_spin_is_locked(&__hdd_vdev_lock)) + +static struct hdd_vdev_kvp *hdd_vdev_kvp_get(struct net_device *net_dev) +{ + int i; + + hdd_vdev_map_lock_assert(); + + for (i = 0; i < QDF_ARRAY_SIZE(__hdd_vdev_map); i++) { + struct hdd_vdev_kvp *kvp = __hdd_vdev_map + i; + + if (kvp->net_dev == net_dev) + return kvp; + } + + return NULL; +} + +void hdd_vdev_ops_register(struct net_device *net_dev, + struct dsc_vdev *dsc_vdev) +{ + struct hdd_vdev_kvp *kvp; + + QDF_BUG(net_dev); + if (!net_dev) + return; + + QDF_BUG(dsc_vdev); + if (!dsc_vdev) + return; + + hdd_vdev_map_lock(); + + kvp = hdd_vdev_kvp_get(NULL); + QDF_BUG(kvp); + if (kvp) { + kvp->net_dev = net_dev; + kvp->dsc_vdev = dsc_vdev; + } + + hdd_vdev_map_unlock(); +} + +void hdd_vdev_ops_unregister(struct net_device *net_dev) +{ + struct hdd_vdev_kvp *kvp; + + QDF_BUG(net_dev); + if (!net_dev) + return; + + hdd_vdev_map_lock(); + + kvp = hdd_vdev_kvp_get(net_dev); + QDF_BUG(kvp); + if (kvp) { + kvp->net_dev = NULL; + kvp->dsc_vdev = NULL; + } + + hdd_vdev_map_unlock(); +} + +static struct hdd_vdev_op *hdd_vdev_to_op(struct dsc_vdev *dsc_vdev) +{ + return (struct hdd_vdev_op *)dsc_vdev; +} + +static struct dsc_vdev *hdd_op_to_vdev(struct hdd_vdev_op *op) +{ + return (struct dsc_vdev *)op; +} + +struct hdd_vdev_op *__hdd_vdev_op_start(struct net_device *net_dev, + const char *func) +{ + QDF_STATUS status = QDF_STATUS_E_NULL_VALUE; + struct hdd_vdev_kvp *kvp; + + QDF_BUG(net_dev); + if (!net_dev) + return NULL; + + hdd_vdev_map_lock(); + + kvp = hdd_vdev_kvp_get(net_dev); + if (kvp) + status = _dsc_vdev_op_start(kvp->dsc_vdev, func); + + hdd_vdev_map_unlock(); + + if (QDF_IS_STATUS_ERROR(status)) + return NULL; + + return hdd_vdev_to_op(kvp->dsc_vdev); +} + +void __hdd_vdev_op_stop(struct hdd_vdev_op *op, const char *func) +{ + _dsc_vdev_op_stop(hdd_op_to_vdev(op), func); +} + +void hdd_dsc_init(void) +{ + qdf_spinlock_create(&__hdd_vdev_lock); +} + +void hdd_dsc_deinit(void) +{ + qdf_spinlock_destroy(&__hdd_vdev_lock); +} + diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 8c9033605608..b2dc790dd026 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -40,6 +40,7 @@ #include #include #include +#include "wlan_hdd_dsc.h" #include #include #include @@ -12917,13 +12918,15 @@ static inline int hdd_state_query_cb(void) int hdd_init(void) { QDF_STATUS status; - int ret = 0; + int ret; + + hdd_dsc_init(); status = cds_init(); if (QDF_IS_STATUS_ERROR(status)) { hdd_err("Failed to allocate CDS context"); ret = -ENOMEM; - goto err_out; + goto deinit_dsc; } qdf_register_module_state_query_callback(hdd_state_query_cb); @@ -12941,7 +12944,11 @@ int hdd_init(void) hdd_register_debug_callback(); wlan_roam_debug_init(); -err_out: + return 0; + +deinit_dsc: + hdd_dsc_deinit(); + return ret; } @@ -12963,6 +12970,8 @@ void hdd_deinit(void) wlan_destroy_bug_report_lock(); cds_deinit(); + + hdd_dsc_deinit(); } #ifdef QCA_WIFI_NAPIER_EMULATION