|
@@ -0,0 +1,304 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2018 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: Driver State Management (DSC) APIs for *internal* use
|
|
|
+ */
|
|
|
+
|
|
|
+#ifndef ____WLAN_DSC_H
|
|
|
+#define ____WLAN_DSC_H
|
|
|
+
|
|
|
+#include "qdf_event.h"
|
|
|
+#include "qdf_list.h"
|
|
|
+#include "qdf_trace.h"
|
|
|
+#include "qdf_types.h"
|
|
|
+#include "wlan_dsc.h"
|
|
|
+
|
|
|
+#define dsc_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, params)
|
|
|
+#define dsc_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_QDF, params)
|
|
|
+#define dsc_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_QDF, params)
|
|
|
+
|
|
|
+#define dsc_enter_exit dsc_debug
|
|
|
+#define dsc_enter() dsc_enter_exit("enter")
|
|
|
+#define dsc_enter_str(str) dsc_enter_exit("enter(\"%s\")", str)
|
|
|
+#define dsc_exit() dsc_enter_exit("exit")
|
|
|
+#define dsc_exit_status(status) dsc_enter_exit("exit(status:%u)", status)
|
|
|
+
|
|
|
+static inline bool __dsc_assert(const bool cond, const char *cond_str,
|
|
|
+ const char *func, const uint32_t line)
|
|
|
+{
|
|
|
+ if (cond)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ QDF_DEBUG_PANIC_FL(func, line, "Failed assertion '%s'!", cond_str);
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+#define dsc_assert(cond) __dsc_assert(cond, #cond, __func__, __LINE__)
|
|
|
+#define dsc_assert_success(status) dsc_assert(QDF_IS_STATUS_SUCCESS(status))
|
|
|
+
|
|
|
+#ifdef WLAN_DSC_DEBUG
|
|
|
+#define DSC_TRANS_TIMEOUT 120000 /* 2 minutes */
|
|
|
+#else
|
|
|
+#define DSC_TRANS_TIMEOUT 0 /* no timeout */
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef WLAN_DSC_DEBUG
|
|
|
+/**
|
|
|
+ * struct dsc_op - list node for operation tracking information
|
|
|
+ * @node: list node
|
|
|
+ * @func: name of the function the operation was started from
|
|
|
+ */
|
|
|
+struct dsc_op {
|
|
|
+ qdf_list_node_t node;
|
|
|
+ const char *func;
|
|
|
+};
|
|
|
+#endif /* WLAN_DSC_DEBUG */
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct dsc_ops - operations in flight tracking container
|
|
|
+ * @list: list for tracking debug information
|
|
|
+ * @count: count of current operations in flight
|
|
|
+ * @event: event used to wait in *_wait_for_ops() APIs
|
|
|
+ */
|
|
|
+struct dsc_ops {
|
|
|
+#ifdef WLAN_DSC_DEBUG
|
|
|
+ qdf_list_t list;
|
|
|
+#endif
|
|
|
+ uint32_t count;
|
|
|
+ qdf_event_t event;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct dsc_pending_trans - representation of a pending transition
|
|
|
+ * @abort: used to indicate if the transition stopped waiting due to an abort
|
|
|
+ * @desc: unique description of the transition
|
|
|
+ * @node: list node
|
|
|
+ * @event: event used to wait in *_start_trans_wait() APIs
|
|
|
+ */
|
|
|
+struct dsc_tran {
|
|
|
+ bool abort;
|
|
|
+ const char *desc;
|
|
|
+ qdf_list_node_t node;
|
|
|
+ qdf_event_t event;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct dsc_trans - transition information container
|
|
|
+ * @active_desc: unique description of the current transition in progress
|
|
|
+ * @queue: queue of pending transitions
|
|
|
+ */
|
|
|
+struct dsc_trans {
|
|
|
+ const char *active_desc;
|
|
|
+ qdf_list_t queue;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct dsc_driver - concrete dsc driver context
|
|
|
+ * @lock: lock under which all dsc APIs execute
|
|
|
+ * @psocs: list of children psoc contexts
|
|
|
+ * @trans: transition tracking container for this node
|
|
|
+ * @ops: operations in flight tracking container for this node
|
|
|
+ */
|
|
|
+struct dsc_driver {
|
|
|
+ struct qdf_spinlock lock;
|
|
|
+ qdf_list_t psocs;
|
|
|
+ struct dsc_trans trans;
|
|
|
+ struct dsc_ops ops;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct dsc_psoc - concrete dsc psoc context
|
|
|
+ * @node: list node for membership in @driver->psocs
|
|
|
+ * @driver: parent driver context
|
|
|
+ * @vdevs: list of children vdevs contexts
|
|
|
+ * @trans: transition tracking container for this node
|
|
|
+ * @ops: operations in flight tracking container for this node
|
|
|
+ */
|
|
|
+struct dsc_psoc {
|
|
|
+ qdf_list_node_t node;
|
|
|
+ struct dsc_driver *driver;
|
|
|
+ qdf_list_t vdevs;
|
|
|
+ struct dsc_trans trans;
|
|
|
+ struct dsc_ops ops;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct dsc_vdev - concrete dsc vdev context
|
|
|
+ * @node: list node for membership in @psoc->vdevs
|
|
|
+ * @psoc: parent psoc context
|
|
|
+ * @trans: transition tracking container for this node
|
|
|
+ * @ops: operations in flight tracking container for this node
|
|
|
+ */
|
|
|
+struct dsc_vdev {
|
|
|
+ qdf_list_node_t node;
|
|
|
+ struct dsc_psoc *psoc;
|
|
|
+ struct dsc_trans trans;
|
|
|
+ struct dsc_ops ops;
|
|
|
+};
|
|
|
+
|
|
|
+#define dsc_for_each_driver_psoc(driver_ptr, psoc_cursor) \
|
|
|
+ qdf_list_for_each(&(driver_ptr)->psocs, psoc_cursor, node)
|
|
|
+
|
|
|
+#define dsc_for_each_psoc_vdev(psoc_ptr, vdev_cursor) \
|
|
|
+ qdf_list_for_each(&(psoc_ptr)->vdevs, vdev_cursor, node)
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_lock() - grab the dsc global lock
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_lock(void);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_unlock() - release the dsc global lock
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_unlock(void);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_ops_init() - initialize @ops
|
|
|
+ * @ops: the ops container to initialize
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_ops_init(struct dsc_ops *ops);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_ops_deinit() - de-initialize @ops
|
|
|
+ * @ops: the ops container to de-initialize
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_ops_deinit(struct dsc_ops *ops);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_ops_insert() - insert @func into the trakcing information in @ops
|
|
|
+ * @ops: the ops container to insert into
|
|
|
+ * @func: the debug information to insert
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS
|
|
|
+ */
|
|
|
+QDF_STATUS __dsc_ops_insert(struct dsc_ops *ops, const char *func);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_ops_remove() - remove @func from the tracking information in @ops
|
|
|
+ * @ops: the ops container to remove from
|
|
|
+ * @func: the debug information to remove
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+bool __dsc_ops_remove(struct dsc_ops *ops, const char *func);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_init() - initialize @trans
|
|
|
+ * @trans: the trans container to initialize
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_trans_init(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_deinit() - de-initialize @trans
|
|
|
+ * @trans: the trans container to de-initialize
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_trans_deinit(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_queue() - queue @tran at the back of @trans
|
|
|
+ * @trans: the transitions container to enqueue to
|
|
|
+ * @tran: the transition to enqueue
|
|
|
+ * @desc: unique description of the transition being queued
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+void __dsc_trans_queue(struct dsc_trans *trans, struct dsc_tran *tran,
|
|
|
+ const char *desc);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_tran_wait() - block until @tran completes
|
|
|
+ * @tran: the transition to wait on
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS
|
|
|
+ */
|
|
|
+QDF_STATUS __dsc_tran_wait(struct dsc_tran *tran);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_abort() - abort the next queued transition from @trans
|
|
|
+ * @trans: the transitions container to abort from
|
|
|
+ *
|
|
|
+ * Return: true if a transition was aborted, false if @trans is empty
|
|
|
+ */
|
|
|
+bool __dsc_trans_abort(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_trigger() - trigger the next queued trans in @trans
|
|
|
+ * @trans: the transitions container to trigger from
|
|
|
+ *
|
|
|
+ * Return: true if a transition was triggered
|
|
|
+ */
|
|
|
+bool __dsc_trans_trigger(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_active() - check if a transition is active in @trans
|
|
|
+ * @trans: the transitions container to check
|
|
|
+ *
|
|
|
+ * Return: true if @trans has an active transition
|
|
|
+ */
|
|
|
+bool __dsc_trans_active(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_queued() - check if a transition is queued in @trans
|
|
|
+ * @trans: the transitions container to check
|
|
|
+ *
|
|
|
+ * Return: true if @trans has a queued transition
|
|
|
+ */
|
|
|
+bool __dsc_trans_queued(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_trans_active_or_queued() - check if a transition is active or queued
|
|
|
+ * in @trans
|
|
|
+ * @trans: the transitions container to check
|
|
|
+ *
|
|
|
+ * Return: true if @trans has an active or queued transition
|
|
|
+ */
|
|
|
+bool __dsc_trans_active_or_queued(struct dsc_trans *trans);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_driver_trans_trigger_checked() - trigger any next pending driver
|
|
|
+ * transition, only after passing the "can trans" check
|
|
|
+ *
|
|
|
+ * Return: true if the trigger was "handled." This indicates down-tree nodes
|
|
|
+ * should _not_ attempt to trigger a new transition.
|
|
|
+ */
|
|
|
+bool __dsc_driver_trans_trigger_checked(struct dsc_driver *driver);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dsc_psoc_trans_trigger_checked() - trigger any next pending psoc
|
|
|
+ * transition, only after passing the "can trans" check
|
|
|
+ *
|
|
|
+ * Return: true if the trigger was "handled." This indicates down-tree nodes
|
|
|
+ * should _not_ attempt to trigger a new transition.
|
|
|
+ */
|
|
|
+bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc);
|
|
|
+
|
|
|
+#endif /* ____WLAN_DSC_H */
|