|
@@ -0,0 +1,696 @@
|
|
|
+/*
|
|
|
+ * 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: offload lmac interface APIs for ocb
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#include <qdf_mem.h>
|
|
|
+#include <target_if.h>
|
|
|
+#include <qdf_status.h>
|
|
|
+#include <wmi_unified_api.h>
|
|
|
+#include <wmi_unified_priv.h>
|
|
|
+#include <wmi_unified_param.h>
|
|
|
+#include <wlan_objmgr_psoc_obj.h>
|
|
|
+#include <wlan_utility.h>
|
|
|
+#include <wlan_defs.h>
|
|
|
+#include <wlan_ocb_public_structs.h>
|
|
|
+#include <wlan_ocb_main.h>
|
|
|
+#include <target_if_ocb.h>
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_get_rx_ops() - get target interface RX operations
|
|
|
+ * @pdev: pdev handle
|
|
|
+ *
|
|
|
+ * Return: fp to target interface RX operations
|
|
|
+ */
|
|
|
+static inline struct wlan_ocb_rx_ops *
|
|
|
+target_if_ocb_get_rx_ops(struct wlan_objmgr_pdev *pdev)
|
|
|
+{
|
|
|
+ struct ocb_pdev_obj *ocb_obj;
|
|
|
+
|
|
|
+ ocb_obj = wlan_get_pdev_ocb_obj(pdev);
|
|
|
+
|
|
|
+ return &ocb_obj->ocb_rxops;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_set_config() - send the OCB config to the FW
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @config: OCB channel configuration
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS target_if_ocb_set_config(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_config *config)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = wmi_unified_ocb_set_config(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ config);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to set OCB config %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_set_utc_time() - send the UTC time to the firmware
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @utc: pointer to the UTC time structure
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS target_if_ocb_set_utc_time(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_utc_param *utc)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = wmi_unified_ocb_set_utc_time_cmd(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ utc);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to set OCB UTC time %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_start_timing_advert() - start sending the timing
|
|
|
+ * advertisement frame on a channel
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @ta: pointer to the timing advertisement
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_ocb_start_timing_advert(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_timing_advert_param *ta)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = wmi_unified_ocb_start_timing_advert(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc), ta);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to start OCB timing advert %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_stop_timing_advert() - stop sending the timing
|
|
|
+ * advertisement frame on a channel
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @ta: pointer to the timing advertisement
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_ocb_stop_timing_advert(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_timing_advert_param *ta)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status =
|
|
|
+ wmi_unified_ocb_stop_timing_advert(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ ta);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to stop OCB timing advert %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_get_tsf_timer() - get tsf timer
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @request: pointer to the request
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_ocb_get_tsf_timer(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_get_tsf_timer_param *request)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = wmi_unified_ocb_get_tsf_timer(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ request);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to send get tsf timer cmd: %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_dcc_get_stats() - get the DCC channel stats
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @get_stats_param: pointer to the dcc stats request
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_dcc_get_stats(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_dcc_get_stats_param *get_stats_param)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = wmi_unified_dcc_get_stats_cmd(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ get_stats_param);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to send get DCC stats cmd: %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_dcc_clear_stats() - send command to clear the DCC stats
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @clear_stats_param: parameters to the command
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_dcc_clear_stats(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_dcc_clear_stats_param *clear_stats_param)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ status = wmi_unified_dcc_clear_stats(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ clear_stats_param);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to send clear DCC stats cmd: %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_dcc_update_ndl() - command to update the NDL data
|
|
|
+ * @psoc: pointer to PSOC object
|
|
|
+ * @update_ndl_param: pointer to the request parameters
|
|
|
+ *
|
|
|
+ * Return: QDF_STATUS_SUCCESS on success
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_dcc_update_ndl(struct wlan_objmgr_psoc *psoc,
|
|
|
+ struct ocb_dcc_update_ndl_param *update_ndl_param)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+
|
|
|
+ /* Send the WMI command */
|
|
|
+ status = wmi_unified_dcc_update_ndl(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ update_ndl_param);
|
|
|
+ if (status)
|
|
|
+ target_if_err("Failed to send NDL update cmd: %d", status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_set_config_resp() - handler for channel config response
|
|
|
+ * @scn: scn handle
|
|
|
+ * @event_buf: pointer to the event buffer
|
|
|
+ * @len: length of the buffer
|
|
|
+ *
|
|
|
+ * Return: 0 on success
|
|
|
+ */
|
|
|
+static int
|
|
|
+target_if_ocb_set_config_resp(ol_scn_t scn, uint8_t *event_buf,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ QDF_STATUS status;
|
|
|
+ uint32_t resp;
|
|
|
+ struct wlan_objmgr_pdev *pdev;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ struct wlan_ocb_rx_ops *ocb_rx_ops;
|
|
|
+
|
|
|
+ target_if_debug("scn:%pK, data:%pK, datalen:%d",
|
|
|
+ scn, event_buf, len);
|
|
|
+ if (!scn || !event_buf) {
|
|
|
+ target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ psoc = target_if_get_psoc_from_scn_hdl(scn);
|
|
|
+ if (!psoc) {
|
|
|
+ target_if_err("null psoc");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
|
|
|
+ WLAN_OCB_SB_ID);
|
|
|
+ if (!pdev) {
|
|
|
+ target_if_err("pdev is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocb_rx_ops = target_if_ocb_get_rx_ops(pdev);
|
|
|
+ if (ocb_rx_ops->ocb_set_config_status) {
|
|
|
+ status = wmi_extract_ocb_set_channel_config_resp(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ event_buf, &resp);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("Failed to extract config status");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ status = ocb_rx_ops->ocb_set_config_status(psoc, resp);
|
|
|
+ if (status != QDF_STATUS_SUCCESS) {
|
|
|
+ target_if_err("ocb_set_config_status failed.");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+ } else {
|
|
|
+ target_if_fatal("No ocb_set_config_status callback");
|
|
|
+ rc = -EINVAL;
|
|
|
+ }
|
|
|
+exit:
|
|
|
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_ocb_get_tsf_timer_resp() - handler for TSF timer response
|
|
|
+ * @scn: scn handle
|
|
|
+ * @event_buf: pointer to the event buffer
|
|
|
+ * @len: length of the buffer
|
|
|
+ *
|
|
|
+ * Return: 0 on success
|
|
|
+ */
|
|
|
+static int target_if_ocb_get_tsf_timer_resp(ol_scn_t scn,
|
|
|
+ uint8_t *event_buf,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ QDF_STATUS status;
|
|
|
+ struct wlan_objmgr_pdev *pdev;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ struct ocb_get_tsf_timer_response response;
|
|
|
+ struct wlan_ocb_rx_ops *ocb_rx_ops;
|
|
|
+
|
|
|
+ target_if_debug("scn:%pK, data:%pK, datalen:%d",
|
|
|
+ scn, event_buf, len);
|
|
|
+
|
|
|
+ if (!scn || !event_buf) {
|
|
|
+ target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ psoc = target_if_get_psoc_from_scn_hdl(scn);
|
|
|
+ if (!psoc) {
|
|
|
+ target_if_err("null psoc");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
|
|
|
+ WLAN_OCB_SB_ID);
|
|
|
+ if (!pdev) {
|
|
|
+ target_if_err("pdev is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocb_rx_ops = target_if_ocb_get_rx_ops(pdev);
|
|
|
+ if (ocb_rx_ops->ocb_tsf_timer) {
|
|
|
+ status = wmi_extract_ocb_tsf_timer(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ event_buf, &response);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("Failed to extract tsf timer");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ status = ocb_rx_ops->ocb_tsf_timer(psoc, &response);
|
|
|
+ if (status != QDF_STATUS_SUCCESS) {
|
|
|
+ target_if_err("ocb_tsf_timer failed.");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+ } else {
|
|
|
+ target_if_fatal("No ocb_tsf_timer callback");
|
|
|
+ rc = -EINVAL;
|
|
|
+ }
|
|
|
+exit:
|
|
|
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_dcc_update_ndl_resp() - handler for update NDL response
|
|
|
+ * @scn: scn handle
|
|
|
+ * @event_buf: pointer to the event buffer
|
|
|
+ * @len: length of the buffer
|
|
|
+ *
|
|
|
+ * Return: 0 on success
|
|
|
+ */
|
|
|
+static int target_if_dcc_update_ndl_resp(ol_scn_t scn,
|
|
|
+ uint8_t *event_buf,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ QDF_STATUS status;
|
|
|
+ struct wlan_objmgr_pdev *pdev;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ struct ocb_dcc_update_ndl_response *resp;
|
|
|
+ struct wlan_ocb_rx_ops *ocb_rx_ops;
|
|
|
+
|
|
|
+ target_if_debug("scn:%pK, data:%pK, datalen:%d",
|
|
|
+ scn, event_buf, len);
|
|
|
+
|
|
|
+ if (!scn || !event_buf) {
|
|
|
+ target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ psoc = target_if_get_psoc_from_scn_hdl(scn);
|
|
|
+ if (!psoc) {
|
|
|
+ target_if_err("null psoc");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
|
|
|
+ WLAN_OCB_SB_ID);
|
|
|
+ if (!pdev) {
|
|
|
+ target_if_err("pdev is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Allocate and populate the response */
|
|
|
+ resp = qdf_mem_malloc(sizeof(*resp));
|
|
|
+ if (!resp) {
|
|
|
+ target_if_err("Error allocating memory for the response.");
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocb_rx_ops = target_if_ocb_get_rx_ops(pdev);
|
|
|
+ if (ocb_rx_ops->ocb_dcc_ndl_update) {
|
|
|
+ status = wmi_extract_dcc_update_ndl_resp(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ event_buf, resp);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("Failed to extract ndl status");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ status = ocb_rx_ops->ocb_dcc_ndl_update(psoc, resp);
|
|
|
+ if (status != QDF_STATUS_SUCCESS) {
|
|
|
+ target_if_err("dcc_ndl_update failed.");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+ } else {
|
|
|
+ target_if_fatal("No dcc_ndl_update callback");
|
|
|
+ rc = -EINVAL;
|
|
|
+ }
|
|
|
+exit:
|
|
|
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
|
|
|
+ if (resp)
|
|
|
+ qdf_mem_free(resp);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_dcc_get_stats_resp() - handler for get stats response
|
|
|
+ * @scn: scn handle
|
|
|
+ * @event_buf: pointer to the event buffer
|
|
|
+ * @len: length of the buffer
|
|
|
+ *
|
|
|
+ * Return: 0 on success
|
|
|
+ */
|
|
|
+static int target_if_dcc_get_stats_resp(ol_scn_t scn,
|
|
|
+ uint8_t *event_buf,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ QDF_STATUS status;
|
|
|
+ struct wlan_objmgr_pdev *pdev;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ struct ocb_dcc_get_stats_response *response;
|
|
|
+ struct wlan_ocb_rx_ops *ocb_rx_ops;
|
|
|
+
|
|
|
+ target_if_debug("scn:%pK, data:%pK, datalen:%d",
|
|
|
+ scn, event_buf, len);
|
|
|
+
|
|
|
+ if (!scn || !event_buf) {
|
|
|
+ target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ psoc = target_if_get_psoc_from_scn_hdl(scn);
|
|
|
+ if (!psoc) {
|
|
|
+ target_if_err("null psoc");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
|
|
|
+ WLAN_OCB_SB_ID);
|
|
|
+ if (!pdev) {
|
|
|
+ target_if_err("pdev is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocb_rx_ops = target_if_ocb_get_rx_ops(pdev);
|
|
|
+ if (ocb_rx_ops->ocb_dcc_stats_indicate) {
|
|
|
+ status = wmi_extract_dcc_stats(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ event_buf, &response);
|
|
|
+ if (!response || QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("Cannot get DCC stats");
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = ocb_rx_ops->ocb_dcc_stats_indicate(psoc,
|
|
|
+ response,
|
|
|
+ true);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("dcc_stats_indicate failed.");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+ } else {
|
|
|
+ target_if_fatal("No dcc_stats_indicate callback");
|
|
|
+ rc = -EINVAL;
|
|
|
+ }
|
|
|
+exit:
|
|
|
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
|
|
|
+ if (response)
|
|
|
+ qdf_mem_free(response);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_dcc_stats_resp() - handler for DCC stats indication event
|
|
|
+ * @scn: scn handle
|
|
|
+ * @event_buf: pointer to the event buffer
|
|
|
+ * @len: length of the buffer
|
|
|
+ *
|
|
|
+ * Return: 0 on success
|
|
|
+ */
|
|
|
+static int target_if_dcc_stats_resp(ol_scn_t scn, uint8_t *event_buf,
|
|
|
+ uint32_t len)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+ QDF_STATUS status;
|
|
|
+ struct wlan_objmgr_pdev *pdev;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ struct ocb_dcc_get_stats_response *response;
|
|
|
+ struct wlan_ocb_rx_ops *ocb_rx_ops;
|
|
|
+
|
|
|
+ target_if_debug("scn:%pK, data:%pK, datalen:%d",
|
|
|
+ scn, event_buf, len);
|
|
|
+
|
|
|
+ if (!scn || !event_buf) {
|
|
|
+ target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ psoc = target_if_get_psoc_from_scn_hdl(scn);
|
|
|
+ if (!psoc) {
|
|
|
+ target_if_err("null psoc");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pdev = wlan_objmgr_get_pdev_by_id(psoc, 0,
|
|
|
+ WLAN_OCB_SB_ID);
|
|
|
+ if (!pdev) {
|
|
|
+ target_if_err("pdev is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocb_rx_ops = target_if_ocb_get_rx_ops(pdev);
|
|
|
+ if (ocb_rx_ops->ocb_dcc_stats_indicate) {
|
|
|
+ status = wmi_extract_dcc_stats(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ event_buf, &response);
|
|
|
+ if (!response || QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("Cannot get DCC stats");
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ status = ocb_rx_ops->ocb_dcc_stats_indicate(psoc,
|
|
|
+ response,
|
|
|
+ false);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ target_if_err("dcc_stats_indicate failed.");
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ rc = 0;
|
|
|
+ } else {
|
|
|
+ target_if_fatal("dcc_stats_indicate failed.");
|
|
|
+ response = NULL;
|
|
|
+ rc = -EINVAL;
|
|
|
+ }
|
|
|
+exit:
|
|
|
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
|
|
|
+ if (response)
|
|
|
+ qdf_mem_free(response);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+QDF_STATUS target_if_ocb_register_event_handler(struct wlan_objmgr_psoc *psoc,
|
|
|
+ void *arg)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ /* Initialize the members in WMA used by wma_ocb */
|
|
|
+ rc = wmi_unified_register_event(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_ocb_set_config_resp_event_id,
|
|
|
+ target_if_ocb_set_config_resp);
|
|
|
+ if (rc) {
|
|
|
+ target_if_err("Failed to register OCB config resp event cb");
|
|
|
+ return QDF_STATUS_E_FAILURE;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = wmi_unified_register_event(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_ocb_get_tsf_timer_resp_event_id,
|
|
|
+ target_if_ocb_get_tsf_timer_resp);
|
|
|
+ if (rc) {
|
|
|
+ target_if_err("Failed to register OCB TSF resp event cb");
|
|
|
+ goto unreg_set_config;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = wmi_unified_register_event(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_get_stats_resp_event_id,
|
|
|
+ target_if_dcc_get_stats_resp);
|
|
|
+ if (rc) {
|
|
|
+ target_if_err("Failed to register DCC get stats resp event cb");
|
|
|
+ goto unreg_tsf_timer;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = wmi_unified_register_event(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_update_ndl_resp_event_id,
|
|
|
+ target_if_dcc_update_ndl_resp);
|
|
|
+ if (rc) {
|
|
|
+ target_if_err("Failed to register NDL update event cb");
|
|
|
+ goto unreg_get_stats;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = wmi_unified_register_event(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_stats_event_id,
|
|
|
+ target_if_dcc_stats_resp);
|
|
|
+ if (rc) {
|
|
|
+ target_if_err("Failed to register DCC stats event cb");
|
|
|
+ goto unreg_ndl;
|
|
|
+ }
|
|
|
+
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+
|
|
|
+unreg_ndl:
|
|
|
+ wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_update_ndl_resp_event_id);
|
|
|
+unreg_get_stats:
|
|
|
+ wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_get_stats_resp_event_id);
|
|
|
+unreg_tsf_timer:
|
|
|
+ wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_ocb_get_tsf_timer_resp_event_id);
|
|
|
+unreg_set_config:
|
|
|
+ wmi_unified_unregister_event(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_ocb_set_config_resp_event_id);
|
|
|
+
|
|
|
+ return QDF_STATUS_E_FAILURE;
|
|
|
+}
|
|
|
+
|
|
|
+QDF_STATUS
|
|
|
+target_if_ocb_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
|
|
|
+ void *arg)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rc = wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_stats_event_id);
|
|
|
+ if (rc)
|
|
|
+ target_if_err("Failed to unregister DCC stats event cb");
|
|
|
+
|
|
|
+ rc = wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_update_ndl_resp_event_id);
|
|
|
+ if (rc)
|
|
|
+ target_if_err("Failed to unregister NDL update event cb");
|
|
|
+
|
|
|
+ rc = wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_dcc_get_stats_resp_event_id);
|
|
|
+ if (rc)
|
|
|
+ target_if_err("Failed to unregister DCC get stats resp cb");
|
|
|
+
|
|
|
+ rc = wmi_unified_unregister_event_handler(
|
|
|
+ GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_ocb_get_tsf_timer_resp_event_id);
|
|
|
+ if (rc)
|
|
|
+ target_if_err("Failed to unregister OCB TSF resp event cb");
|
|
|
+
|
|
|
+ rc = wmi_unified_unregister_event(GET_WMI_HDL_FROM_PSOC(psoc),
|
|
|
+ wmi_ocb_set_config_resp_event_id);
|
|
|
+ if (rc)
|
|
|
+ target_if_err("Failed to unregister OCB config resp event cb");
|
|
|
+
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+QDF_STATUS
|
|
|
+target_if_ocb_register_tx_ops(struct wlan_ocb_tx_ops *ocb_txops)
|
|
|
+{
|
|
|
+ ocb_txops->ocb_set_config = target_if_ocb_set_config;
|
|
|
+ ocb_txops->ocb_set_utc_time = target_if_ocb_set_utc_time;
|
|
|
+ ocb_txops->ocb_start_timing_advert = target_if_ocb_start_timing_advert;
|
|
|
+ ocb_txops->ocb_stop_timing_advert = target_if_ocb_stop_timing_advert;
|
|
|
+ ocb_txops->ocb_get_tsf_timer = target_if_ocb_get_tsf_timer;
|
|
|
+ ocb_txops->ocb_dcc_get_stats = target_if_dcc_get_stats;
|
|
|
+ ocb_txops->ocb_dcc_clear_stats = target_if_dcc_clear_stats;
|
|
|
+ ocb_txops->ocb_dcc_update_ndl = target_if_dcc_update_ndl;
|
|
|
+ ocb_txops->ocb_reg_ev_handler = target_if_ocb_register_event_handler;
|
|
|
+ ocb_txops->ocb_unreg_ev_handler =
|
|
|
+ target_if_ocb_unregister_event_handler;
|
|
|
+
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|