From 22f95dcc59eecfdad9cce34cb42e434554ad9d5b Mon Sep 17 00:00:00 2001 From: Om Prakash Tripathi Date: Mon, 19 Dec 2016 10:45:59 +0530 Subject: [PATCH] qcacmn: scan convergence - interface definition Add north interface, south interface and offload interface API definitions Change-Id: Iccae20d266e7248088241416730d9ea317c3f77b CRs-Fixed: 1095299 --- target_if/scan/inc/target_if_scan.h | 75 +++ target_if/scan/src/target_if_scan.c | 115 ++++ .../obj_mgr/inc/wlan_objmgr_cmn.h | 2 + .../lmac_if/inc/wlan_lmac_if_def.h | 55 +- umac/scan/core/src/wlan_scan_main.h | 2 + umac/scan/core/src/wlan_scan_manager.c | 489 +++++++++++++++ umac/scan/dispatcher/inc/wlan_scan_tgt_api.h | 2 +- umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h | 2 +- .../scan/dispatcher/inc/wlan_scan_utils_api.h | 3 + umac/scan/dispatcher/src/wlan_scan_tgt_api.c | 156 +++++ umac/scan/dispatcher/src/wlan_scan_ucfg_api.c | 561 +++++++++++++++++- .../scan/dispatcher/src/wlan_scan_utils_api.c | 84 +++ 12 files changed, 1514 insertions(+), 32 deletions(-) create mode 100644 target_if/scan/inc/target_if_scan.h create mode 100644 target_if/scan/src/target_if_scan.c diff --git a/target_if/scan/inc/target_if_scan.h b/target_if/scan/inc/target_if_scan.h new file mode 100644 index 000000000000..176d64d4cacc --- /dev/null +++ b/target_if/scan/inc/target_if_scan.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017 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 scan + */ +#ifndef __TARGET_SCAN_IF_H__ +#define __TARGET_SCAN_IF_H__ + +struct scan_req_params; +struct scan_cancel_param; +struct wlan_objmgr_psoc; + +/** + * target_if_scan_register_event_handler() - lmac handler API + * to register for scan events + * @psoc: psoc object + * @arg: argument to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_scan_unregister_event_handler() - lmac handler API + * to unregister for scan events + * @psoc: psoc object + * @arg: argument to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_scan_start() - lmac handler API to start scan + * @psoc: psoc object + * @req: scan_req_params object + * + * Return: QDF_STATUS + */ + +QDF_STATUS +target_if_scan_start(struct wlan_objmgr_psoc *psoc, + struct scan_start_request *req); + +/** + * target_if_scan_cancel() - lmac handler API to cancel a previous active scan + * @psoc: psoc object + * @req: scan_cancel_param object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_scan_cancel(struct wlan_objmgr_psoc *psoc, + struct scan_cancel_param *req); +#endif diff --git a/target_if/scan/src/target_if_scan.c b/target_if/scan/src/target_if_scan.c new file mode 100644 index 000000000000..0921bd310559 --- /dev/null +++ b/target_if/scan/src/target_if_scan.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017 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 definitions for scan + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline struct wlan_lmac_if_scan_rx_ops * +target_if_scan_get_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.rx_ops.scan; +} + +static int +target_if_scan_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + struct scan_event_info *event_info; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_scan_rx_ops *scan_rx_ops; + QDF_STATUS status; + + if (!scn || !data) { + target_if_err("scn: 0x%p, data: 0x%p\n", scn, data); + return -EINVAL; + } + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc\n"); + return -EINVAL; + } + wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc); + + event_info = qdf_mem_malloc(sizeof(*event_info)); + + if (!event_info) { + target_if_err("%s: unable to allocate scan_event\n", __func__); + return -ENOMEM; + } + + if (wmi_extract_vdev_scan_ev_param(wmi_handle, data, + &(event_info->event))) { + target_if_err("%s: Failed to extract wmi scan event\n", + __func__); + qdf_mem_free(event_info); + return -EINVAL; + } + + scan_rx_ops = target_if_scan_get_rx_ops(psoc); + if (scan_rx_ops->scan_ev_handler) { + status = scan_rx_ops->scan_ev_handler(psoc, event_info); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(event_info); + return -EINVAL; + } + } + + return 0; +} + +QDF_STATUS +target_if_scan_register_event_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + return wmi_unified_register_event_handler(psoc->tgt_if_handle, + wmi_scan_event_id, target_if_scan_event_handler, + WMI_RX_UMAC_CTX); +} + +QDF_STATUS +target_if_scan_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + return wmi_unified_unregister_event_handler(psoc->tgt_if_handle, + wmi_scan_event_id); +} + +QDF_STATUS +target_if_scan_start(struct wlan_objmgr_psoc *psoc, + struct scan_start_request *req) +{ + return wmi_unified_scan_start_cmd_send(psoc->tgt_if_handle, + &req->scan_req); +} + + +QDF_STATUS +target_if_scan_cancel(struct wlan_objmgr_psoc *psoc, + struct scan_cancel_param *req) +{ + return wmi_unified_scan_stop_cmd_send(psoc->tgt_if_handle, req); +} diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h index 63316d57f4ce..7e3599646bc3 100644 --- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h +++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h @@ -164,6 +164,7 @@ typedef void (*wlan_objmgr_peer_status_handler)( * @WLAN_SERIALIZATION_ID: Serialization operations * @WLAN_PMO_ID: power manager offload (PMO) ID * @WLAN_LEGACY_SME_ID: Legacy SME operations + * @WLAN_SCAN_ID: scan operations * @WLAN_REF_ID_MAX: Max id used to generate ref count tracking array */ typedef enum { @@ -179,6 +180,7 @@ typedef enum { WLAN_SERIALIZATION_ID = 9, WLAN_PMO_ID = 10, WLAN_LEGACY_SME_ID = 11, + WLAN_SCAN_ID = 12, WLAN_REF_ID_MAX, } wlan_objmgr_ref_dbgid; diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 43dbb23d3b91..c92b6bf7d932 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -23,6 +23,7 @@ #include "qdf_status.h" #include "wlan_objmgr_cmn.h" #include "wlan_mgmt_txrx_utils_api.h" +#include "wlan_scan_public_structs.h" /* Number of dev type: Direct attach and Offload */ #define MAX_DEV_TYPE 2 @@ -42,10 +43,46 @@ struct wlan_lmac_if_mgmt_txrx_tx_ops { qdf_nbuf_t nbuf); }; + +/** + * struct wlan_lmac_if_scan_tx_ops - south bound tx function pointers for scan + * @scan_start: function to start scan + * @scan_cancel: function to cancel scan + * @scan_reg_ev_handler: function to register for scan events + * @scan_unreg_ev_handler: function to unregister for scan events + * + * scan module uses these functions to avail ol/da lmac services + */ +struct wlan_lmac_if_scan_tx_ops { + QDF_STATUS (*scan_start)(struct wlan_objmgr_psoc *psoc, + struct scan_start_request *req); + QDF_STATUS (*scan_cancel)(struct wlan_objmgr_psoc *psoc, + struct scan_cancel_param *req); + QDF_STATUS (*scan_reg_ev_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); + QDF_STATUS (*scan_unreg_ev_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); + QDF_STATUS (*set_chan_list)(struct wlan_objmgr_pdev *pdev, void *arg); +}; + + +/** + * struct wlan_lmac_if_scan_rx_ops - south bound rx function pointers for scan + * @scan_ev_handler: scan event handler + * + * lmac modules uses this API to post scan events to scan module + */ +struct wlan_lmac_if_scan_rx_ops { + QDF_STATUS (*scan_ev_handler)(struct wlan_objmgr_psoc *psoc, + struct scan_event_info *event_info); +}; + + /** * struct wlan_lmac_if_tx_ops - south bound tx function pointers - * @arg1 - * @arg2 + * @mgmt_txrx_tx_ops: mgmt txrx tx ops + * @scan: scan tx ops + * @set_chan_list: tx func for configuring scan channel * * Callback function tabled to be registered with umac. * umac will use the functional table to send events/frames to lmac/wmi @@ -54,16 +91,11 @@ struct wlan_lmac_if_mgmt_txrx_tx_ops { struct wlan_lmac_if_tx_ops { /* Components to declare function pointers required by the module * in component specific structure. - * Ex : scan module - * struct wlan_lmac_if_scan_tx_ops scan_tx_ops; * The component specific ops structure can be declared in this file * only - * struct wlan_lmac_if_scan_tx_ops { - * int (*fp1)(); - * void (*fp2)(); - * } */ struct wlan_lmac_if_mgmt_txrx_tx_ops mgmt_txrx_tx_ops; + struct wlan_lmac_if_scan_tx_ops scan; }; /** @@ -107,16 +139,11 @@ struct wlan_lmac_if_mgmt_txrx_rx_ops { struct wlan_lmac_if_rx_ops { /* Components to declare function pointers required by the module * in component specific structure. - * Ex : scan module - * struct wlan_lmac_if_scan_rx_ops scan_rx_ops; * The component specific ops structure can be declared in this file * only - * struct wlan_lmac_if_scan_rx_ops { - * int (*fp1)(); - * void (*fp2)(); - * } */ struct wlan_lmac_if_mgmt_txrx_rx_ops mgmt_txrx_rx_ops; + struct wlan_lmac_if_scan_rx_ops scan; }; /* Function pointer to call legacy tx_ops registration in OL/WMA. diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h index e9701c0bdd9a..a3f564e865cf 100644 --- a/umac/scan/core/src/wlan_scan_main.h +++ b/umac/scan/core/src/wlan_scan_main.h @@ -24,6 +24,8 @@ #define _WLAN_SCAN_MAIN_API_H_ #include +#include +#include #include #include #include "wlan_scan_cache_db.h" diff --git a/umac/scan/core/src/wlan_scan_manager.c b/umac/scan/core/src/wlan_scan_manager.c index 9aa01bda5f47..2614fa0777d6 100644 --- a/umac/scan/core/src/wlan_scan_manager.c +++ b/umac/scan/core/src/wlan_scan_manager.c @@ -19,3 +19,492 @@ /* * DOC: contains scan manager functionality */ + +#include +#include +#include +#include "wlan_scan_main.h" +#include "wlan_scan_manager.h" + +static QDF_STATUS +scm_free_scan_request_mem(struct scan_start_request *req) +{ + void *ie; + + if (!req) { + scm_err("null request"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + scm_info("freed scan request: 0x%p, scan_id: %d, requester: %d", + req, req->scan_req.scan_id, req->scan_req.scan_req_id); + /* Free vendor(extra) ie */ + ie = req->scan_req.extraie.ptr; + if (ie) { + req->scan_req.extraie.ptr = NULL; + req->scan_req.extraie.len = 0; + qdf_mem_free(ie); + } + + /* Free htcap ie */ + ie = req->scan_req.htcap.ptr; + if (ie) { + req->scan_req.htcap.len = 0; + req->scan_req.htcap.ptr = NULL; + qdf_mem_free(ie); + } + + /* Free vhtcap ie */ + ie = req->scan_req.vhtcap.ptr; + if (ie) { + req->scan_req.vhtcap.len = 0; + req->scan_req.vhtcap.ptr = NULL; + qdf_mem_free(ie); + } + /* free scan_start_request memory */ + qdf_mem_free(req); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +scm_scan_get_pdev_global_event_handlers(struct scan_event_listeners *listeners, + struct pdev_scan_ev_handler *pdev_ev_handler) +{ + uint32_t i; + struct cb_handler *cb_handlers = &(pdev_ev_handler->cb_handlers[0]); + + for (i = 0; i < MAX_SCAN_EVENT_HANDLERS_PER_PDEV; i++, cb_handlers++) { + if ((cb_handlers->func) && + (listeners->count < MAX_SCAN_EVENT_LISTENERS)) { + listeners->cb[listeners->count].func = + cb_handlers->func; + listeners->cb[listeners->count].arg = + cb_handlers->arg; + listeners->count++; + } + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +scm_scan_get_requester_event_handler(struct scan_event_listeners *listeners, + struct scan_requester_info *requesters, + wlan_scan_requester requester_id) +{ + uint32_t idx = requester_id & ~WLAN_SCAN_REQUESTER_ID_PREFIX; + struct cb_handler *ev_handler = &(requesters[idx].ev_handler); + + if (ev_handler->func) { + if (listeners->count < MAX_SCAN_EVENT_LISTENERS) { + listeners->cb[listeners->count].func = ev_handler->func; + listeners->cb[listeners->count].arg = ev_handler->arg; + listeners->count++; + } + } + + return QDF_STATUS_SUCCESS; +} + +static void scm_scan_post_event(struct wlan_objmgr_vdev *vdev, + struct scan_event *event) +{ + uint32_t i = 0; + struct wlan_scan_obj *scan; + struct pdev_scan_ev_handler *pdev_ev_handler; + struct cb_handler *cb_handlers; + struct scan_requester_info *requesters; + struct scan_event_listeners *listeners; + + if (!vdev || !event) { + scm_err("vdev: 0x%p, event: 0x%p", vdev, event); + return; + } + if (!event->requester) { + scm_err("invalid requester id"); + QDF_ASSERT(0); + } + scm_info("vdev: 0x%p, event: 0x%p", vdev, event); + + scan = wlan_vdev_get_scan_obj(vdev); + pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev); + cb_handlers = &(pdev_ev_handler->cb_handlers[0]); + requesters = scan->requesters; + + scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d", + event->vdev_id, event->type, event->reason, event->chan_freq, + event->requester, event->scan_id); + + listeners = qdf_mem_malloc(sizeof(*listeners)); + if (!listeners) { + scm_warn("couldn't allocate listeners list"); + return; + } + + /* initialize number of listeners */ + listeners->count = 0; + + /* + * Initiator of scan request decides which all scan events + * he is interested in and FW will send only those scan events + * to host driver. + * All the events received by scan module will be notified + * to all registered handlers. + */ + + qdf_spin_lock_bh(&scan->lock); + /* find all global scan event handlers on this pdev */ + scm_scan_get_pdev_global_event_handlers(listeners, pdev_ev_handler); + /* find owner who triggered this scan request */ + scm_scan_get_requester_event_handler(listeners, requesters, + event->requester); + qdf_spin_unlock_bh(&scan->lock); + + /* notify all interested handlers */ + for (i = 0; i < listeners->count; i++) { + scm_debug("func: 0x%p, arg: 0x%p", + listeners->cb[i].func, listeners->cb[i].arg); + listeners->cb[i].func(vdev, event, listeners->cb[i].arg); + } + qdf_mem_free(listeners); +} + +static QDF_STATUS +scm_release_serialization_command(struct wlan_objmgr_vdev *vdev, + uint32_t scan_id) +{ + struct wlan_serialization_queued_cmd_info cmd = {0}; + + cmd.requestor = WLAN_UMAC_COMP_SCAN; + cmd.cmd_type = WLAN_SER_CMD_SCAN; + cmd.cmd_id = scan_id; + cmd.req_type = WLAN_SER_CANCEL_SINGLE_SCAN; + cmd.vdev = vdev; + cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; + + /* Inform serialization for command completion */ + wlan_serialization_remove_cmd(&cmd); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +scm_post_internal_scan_complete_event(struct scan_start_request *req, + enum scan_completion_reason reason) +{ + struct scan_event event = {0, }; + + /* prepare internal scan complete event */ + event.type = SCAN_EVENT_TYPE_COMPLETED; + event.reason = reason; + event.chan_freq = 0; /* Invalid frequency */ + event.vdev_id = req->scan_req.vdev_id; + event.requester = req->scan_req.scan_req_id; + event.scan_id = req->scan_req.scan_id; + + /* post scan event to registered handlers */ + scm_scan_post_event(req->vdev, &event); + + return QDF_STATUS_SUCCESS; +} + +static inline struct pdev_scan_info * +scm_scan_get_pdev_priv_info(uint8_t pdev_id, struct wlan_scan_obj *scan_obj) +{ + return &scan_obj->pdev_info[pdev_id]; +} + +static QDF_STATUS +scm_update_last_scan_time(struct scan_start_request *req) +{ + uint8_t pdev_id; + struct wlan_scan_obj *scan_obj; + struct pdev_scan_info *pdev_scan_info; + + scan_obj = wlan_vdev_get_scan_obj(req->vdev); + pdev_id = wlan_scan_vdev_get_pdev_id(req->vdev); + pdev_scan_info = scm_scan_get_pdev_priv_info(pdev_id, scan_obj); + /* update last scan start time */ + pdev_scan_info->last_scan_time = qdf_system_ticks(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +scm_activate_scan_request(struct scan_start_request *req) +{ + QDF_STATUS status; + + status = tgt_scan_start(req); + if (status != QDF_STATUS_SUCCESS) { + scm_info("tgt_scan_start failed, status: %d", status); + /* scan could not be started and hence + * we will not receive any completions. + * post scan cancelled + */ + scm_post_internal_scan_complete_event(req, + SCAN_REASON_CANCELLED); + return status; + } + /* save last scan start time */ + status = scm_update_last_scan_time(req); + + return status; +} + +static QDF_STATUS +scm_cancel_scan_request(struct scan_start_request *req) +{ + struct scan_cancel_request cancel_req = {0, }; + QDF_STATUS status; + + cancel_req.vdev = req->vdev; + cancel_req.cancel_req.scan_id = req->scan_req.scan_id; + cancel_req.cancel_req.requester = req->scan_req.scan_req_id; + cancel_req.cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE; + cancel_req.cancel_req.vdev_id = req->scan_req.vdev_id; + /* send scan cancel to fw */ + status = tgt_scan_cancel(&cancel_req); + if (status != QDF_STATUS_SUCCESS) + scm_err("tgt_scan_cancel failed: status: %d, scanid: %d", + status, req->scan_req.scan_id); + /* notify event handler about scan cancellation */ + scm_post_internal_scan_complete_event(req, SCAN_REASON_CANCELLED); + + return status; +} + +static QDF_STATUS +scm_scan_serialize_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + struct scan_start_request *req; + QDF_STATUS status; + + if (!cmd || !cmd->umac_cmd) { + scm_err("cmd: %p, umac_cmd: %p, reason: %d", + cmd, cmd->umac_cmd, reason); + return QDF_STATUS_E_NULL_VALUE; + } + req = cmd->umac_cmd; + scm_info("reason: %d, reqid:%d, scanid: %d, vdev_id: %d", + reason, req->scan_req.scan_req_id, + req->scan_req.scan_id, req->scan_req.vdev_id); + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + /* command moved to active list + * modify the params if required for concurency case. + */ + status = scm_activate_scan_request(req); + break; + + case WLAN_SER_CB_CANCEL_CMD: + /* command removed from pending list. + * notify registered scan event handlers with + * status completed and reason cancelled. + */ + status = scm_post_internal_scan_complete_event(req, + SCAN_REASON_CANCELLED); + break; + + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + /* active command timed out. + * prepare internal scan cancel request + */ + status = scm_cancel_scan_request(req); + break; + + case WLAN_SER_CB_RELEASE_MEM_CMD: + /* command successfully completed. + * release scan_start_request memory + */ + status = scm_free_scan_request_mem(req); + break; + + default: + /* Do nothing but logging */ + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +QDF_STATUS +scm_scan_start_req(struct scheduler_msg *msg) +{ + struct wlan_serialization_command cmd = {0, }; + enum wlan_serialization_status ser_cmd_status; + struct scan_start_request *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!msg || !msg->bodyptr) { + scm_err("msg: 0x%p, bodyptr: 0x%p", msg, msg->bodyptr); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + req = msg->bodyptr; + cmd.cmd_type = WLAN_SER_CMD_SCAN; + cmd.cmd_id = req->scan_req.scan_id; + cmd.cmd_cb = (wlan_serialization_cmd_callback) + scm_scan_serialize_callback; + cmd.umac_cmd = req; + cmd.source = WLAN_UMAC_COMP_SCAN; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = req->scan_req.max_scan_time + + SCAN_TIMEOUT_GRACE_PERIOD; + cmd.vdev = req->vdev; + + scm_info("req: 0x%p, reqid: %d, scanid: %d, vdevid: %d", + req, req->scan_req.scan_req_id, req->scan_req.scan_id, + req->scan_req.vdev_id); + + ser_cmd_status = wlan_serialization_request(&cmd); + scm_info("wlan_serialization_request status:%d", ser_cmd_status); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list.Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + case WLAN_SER_CMD_DENIED_LIST_FULL: + case WLAN_SER_CMD_DENIED_RULES_FAILED: + case WLAN_SER_CMD_DENIED_UNSPECIFIED: + /* notify registered scan event handlers + * about internal error + */ + scm_post_internal_scan_complete_event(req, + SCAN_REASON_INTERNAL_FAILURE); + /* cmd can't be serviced. + * release scan_start_request memory. + */ + scm_free_scan_request_mem(req); + break; + default: + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +static inline enum wlan_serialization_cancel_type +get_serialization_cancel_type(enum scan_cancel_req_type type) +{ + enum wlan_serialization_cancel_type serialization_type; + + switch (type) { + case WLAN_SCAN_CANCEL_SINGLE: + serialization_type = WLAN_SER_CANCEL_SINGLE_SCAN; + break; + case WLAN_SCAN_CANCEL_VDEV_ALL: + serialization_type = WLAN_SER_CANCEL_VDEV_SCANS; + break; + case WLAN_SCAN_CANCEL_PDEV_ALL: + serialization_type = WLAN_SER_CANCEL_PDEV_SCANS; + break; + default: + QDF_ASSERT(0); + scm_warn("invalid scan_cancel_req_type: %d", type); + serialization_type = WLAN_SER_CANCEL_PDEV_SCANS; + break; + } + + return serialization_type; +} + +QDF_STATUS +scm_scan_cancel_req(struct scheduler_msg *msg) +{ + struct wlan_serialization_queued_cmd_info cmd = {0,}; + enum wlan_serialization_cmd_status ser_cmd_status; + struct scan_cancel_request *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!msg || !msg->bodyptr) { + scm_err("msg: 0x%p, bodyptr: 0x%p", msg, msg->bodyptr); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + req = msg->bodyptr; + cmd.requestor = 0; + cmd.cmd_type = WLAN_SER_CMD_SCAN; + cmd.cmd_id = req->cancel_req.scan_id; + cmd.vdev = req->vdev; + cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE | + WLAN_SERIALIZATION_PENDING_QUEUE; + cmd.req_type = get_serialization_cancel_type(req->cancel_req.req_type); + + ser_cmd_status = wlan_serialization_cancel_request(&cmd); + + scm_info("status: %d, reqid: %d, scanid: %d, vdevid: %d, type: %d", + ser_cmd_status, req->cancel_req.requester, + req->cancel_req.scan_id, req->cancel_req.vdev_id, + req->cancel_req.req_type); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_IN_PENDING_LIST: + /* do nothing */ + break; + case WLAN_SER_CMD_IN_ACTIVE_LIST: + case WLAN_SER_CMDS_IN_ALL_LISTS: + /* send wmi scan cancel to fw */ + status = tgt_scan_cancel(req); + break; + case WLAN_SER_CMD_NOT_FOUND: + /* do nothing */ + break; + default: + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + /* Free cancel request memory */ + qdf_mem_free(req); + + return status; +} + +QDF_STATUS +scm_scan_event_handler(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev; + struct scan_event *event; + struct scan_event_info *event_info; + + if (!msg || !msg->bodyptr) { + scm_err("msg: %p, bodyptr: %p", msg, msg->bodyptr); + return QDF_STATUS_E_NULL_VALUE; + } + event_info = msg->bodyptr; + vdev = event_info->vdev; + event = &(event_info->event); + + scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d", + event->vdev_id, event->type, event->reason, event->chan_freq, + event->requester, event->scan_id); + + switch (event->type) { + case SCAN_EVENT_TYPE_COMPLETED: + case SCAN_EVENT_TYPE_START_FAILED: + case SCAN_EVENT_TYPE_DEQUEUED: + scm_release_serialization_command(vdev, event->scan_id); + break; + default: + break; + } + + /* Notify all interested parties */ + scm_scan_post_event(vdev, event); + /* free event info memory */ + qdf_mem_free(event_info); + wlan_objmgr_vdev_release_ref(vdev, WLAN_SCAN_ID); + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/scan/dispatcher/inc/wlan_scan_tgt_api.h b/umac/scan/dispatcher/inc/wlan_scan_tgt_api.h index fffd1fc0085f..a1ab1dd1694f 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_tgt_api.h +++ b/umac/scan/dispatcher/inc/wlan_scan_tgt_api.h @@ -23,11 +23,11 @@ #ifndef _WLAN_SCAN_TGT_API_H_ #define _WLAN_SCAN_TGT_API_H_ -#include #include #include #include #include +#include #include /** diff --git a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h index 644be7e83bc9..e4da600eee9e 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h +++ b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h @@ -24,10 +24,10 @@ #define _WLAN_SCAN_UCFG_API_H_ #include -#include #include #include #include +#include /** * ucfg_scan_register_requester() - assigns requester ID to caller and diff --git a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h index 610cb13af6c6..9e1e894b3c7e 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h +++ b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h @@ -25,6 +25,9 @@ #include #include +#include +#include +#include #include #include diff --git a/umac/scan/dispatcher/src/wlan_scan_tgt_api.c b/umac/scan/dispatcher/src/wlan_scan_tgt_api.c index 70b339af6b7a..77710d182c3c 100644 --- a/umac/scan/dispatcher/src/wlan_scan_tgt_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_tgt_api.c @@ -19,3 +19,159 @@ /* * DOC: contains scan south bound interface definitions */ + +#include +#include +#include +#include +#include +#include +#include +#include <../../core/src/wlan_scan_manager.h> + +static inline struct wlan_lmac_if_scan_tx_ops * +wlan_psoc_get_scan_txops(struct wlan_objmgr_psoc *psoc) +{ + return &((psoc->soc_cb.tx_ops.scan)); +} + +static inline struct wlan_lmac_if_scan_tx_ops * +wlan_vdev_get_scan_txops(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = NULL; + + psoc = wlan_vdev_get_psoc(vdev); + + return wlan_psoc_get_scan_txops(psoc); +} + +static inline struct wlan_lmac_if_scan_rx_ops * +wlan_vdev_get_scan_rxops(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = NULL; + + psoc = wlan_vdev_get_psoc(vdev); + + return &((psoc->soc_cb.rx_ops.scan)); +} + +QDF_STATUS +tgt_scan_nlo_complete_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + /* + * Convert the tlv/non tlv data to struct scan_event + * (SCM_EVENT_NLO_COMPLETE) (same as WIN does by calling a win API) and + * Post msg to target_if queue + */ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_nlo_match_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + /* + * Convert the tlv/non tlv data to comman data + * and set the pno match received flag in vdev scan info + */ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_scan_start(struct scan_start_request *req) +{ + struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(req->vdev); + + scan_ops = wlan_vdev_get_scan_txops(req->vdev); + /* invoke wmi_unified_scan_start_cmd_send() */ + QDF_ASSERT(scan_ops->scan_start); + if (scan_ops->scan_start) + return scan_ops->scan_start(psoc, req); + else + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS +tgt_scan_cancel(struct scan_cancel_request *req) +{ + struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(req->vdev); + + scan_ops = wlan_vdev_get_scan_txops(req->vdev); + /* invoke wmi_unified_scan_stop_cmd_send() */ + QDF_ASSERT(scan_ops->scan_cancel); + if (scan_ops->scan_cancel) + return scan_ops->scan_cancel(psoc, &(req->cancel_req)); + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_scan_register_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; + + scan_ops = wlan_psoc_get_scan_txops(psoc); + /* invoke wmi_unified_register_event_handler() + * since event id, handler function and context is + * already known to offload lmac, passing NULL as argument. + * DA can pass necessary arguments by clubing then into + * some structure. + */ + QDF_ASSERT(scan_ops->scan_reg_ev_handler); + if (scan_ops->scan_reg_ev_handler) + return scan_ops->scan_reg_ev_handler(psoc, NULL); + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; + + scan_ops = wlan_psoc_get_scan_txops(psoc); + /* invoke wmi_unified_register_event_handler() + * since event id, handler function and context is + * already known to offload lmac, passing NULL as argument. + * DA can pass necessary arguments by clubing then into + * some structure. + */ + QDF_ASSERT(scan_ops->scan_unreg_ev_handler); + if (scan_ops->scan_unreg_ev_handler) + return scan_ops->scan_unreg_ev_handler(psoc, NULL); + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_scan_event_handler(struct wlan_objmgr_psoc *psoc, + struct scan_event_info *event_info) +{ + struct scheduler_msg msg = {0,}; + struct scan_event *event = &event_info->event; + uint8_t vdev_id = event->vdev_id; + + if (!psoc || !event_info) { + scm_err("psoc: 0x%p, event_info: 0x%p", psoc, event_info); + return QDF_STATUS_E_NULL_VALUE; + } + scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d", + vdev_id, event->type, event->reason, event->chan_freq, + event->requester, event->scan_id); + + event_info->vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, WLAN_SCAN_ID); + if (!event_info->vdev) { + scm_err("null vdev, vdev_id: %d, psoc: 0x%p", vdev_id, psoc); + return QDF_STATUS_E_INVAL; + } + msg.bodyptr = event_info; + msg.callback = scm_scan_event_handler; + + return scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg); +} diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c index 5877a08af9b9..f38489ecbde0 100644 --- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c @@ -20,11 +20,15 @@ * DOC: contains scan north bound interface definitions */ -#include -#include +#include #include -#include "../../core/src/wlan_scan_main.h" #include +#include +#include +#include +#include "../../core/src/wlan_scan_main.h" +#include "../../core/src/wlan_scan_manager.h" +#include "../../core/src/wlan_scan_cache_db.h" QDF_STATUS ucfg_scan_init(void) { @@ -53,7 +57,7 @@ fail_create_psoc: QDF_STATUS ucfg_scan_deinit(void) { - QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS status; status = wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_SCAN, wlan_scan_psoc_created_notification, NULL); @@ -69,9 +73,222 @@ QDF_STATUS ucfg_scan_deinit(void) return status; } -static QDF_STATUS wlan_scan_global_init(struct wlan_scan_obj *scan_obj) +QDF_STATUS +ucfg_scan_start(struct scan_start_request *req) { + struct scheduler_msg msg = {0, }; + if (!req || !req->vdev) { + scm_err("vdev: %p, req: %p", req->vdev, req); + return QDF_STATUS_E_NULL_VALUE; + } + scm_info("reqid: %d, scanid: %d, vdevid: %d", + req->scan_req.scan_req_id, req->scan_req.scan_id, + req->scan_req.vdev_id); + msg.bodyptr = req; + msg.callback = scm_scan_start_req; + + return scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg); +} + +QDF_STATUS +ucfg_scan_cancel(struct scan_cancel_request *req) +{ + struct scheduler_msg msg = {0, }; + + if (!req || !req->vdev) { + scm_err("vdev: %p, req: %p", req->vdev, req); + return QDF_STATUS_E_NULL_VALUE; + } + scm_info("reqid: %d, scanid: %d, vdevid: %d, type: %d", + req->cancel_req.requester, req->cancel_req.scan_id, + req->cancel_req.vdev_id, req->cancel_req.req_type); + msg.bodyptr = req; + msg.callback = scm_scan_cancel_req; + + return scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg); +} + +wlan_scan_requester +ucfg_scan_register_requester(struct wlan_objmgr_psoc *psoc, + uint8_t *name, scan_event_handler event_cb, void *arg) +{ + int i, j; + struct wlan_scan_obj *scan; + struct scan_requester_info *requesters; + wlan_scan_requester requester = {0}; + + if (!psoc) { + scm_err("null psoc"); + return 0; + } + scan = wlan_psoc_get_scan_obj(psoc); + requesters = scan->requesters; + qdf_spin_lock_bh(&scan->lock); + for (i = 0; i < WLAN_MAX_REQUESTORS; ++i) { + if (requesters[i].requester == 0) { + requesters[i].requester = + WLAN_SCAN_REQUESTER_ID_PREFIX | i; + j = 0; + while (name[j] && (j < (WLAN_MAX_MODULE_NAME - 1))) { + requesters[i].module[j] = name[j]; + ++j; + } + requesters[i].module[j] = 0; + requesters[i].ev_handler.func = event_cb; + requesters[i].ev_handler.arg = arg; + requester = requesters[i].requester; + break; + } + } + qdf_spin_unlock_bh(&scan->lock); + scm_info("module: %s, event_cb: 0x%p, arg: 0x%p, reqid: %d", + name, event_cb, arg, requester); + + return requester; +} + +void +ucfg_scan_unregister_requester(struct wlan_objmgr_psoc *psoc, + wlan_scan_requester requester) +{ + int idx = requester & ~WLAN_SCAN_REQUESTER_ID_PREFIX; + struct wlan_scan_obj *scan; + struct scan_requester_info *requesters; + + if (!psoc) { + scm_err("null psoc"); + return; + } + scan = wlan_psoc_get_scan_obj(psoc); + requesters = scan->requesters; + scm_info("reqid: %d", requester); + + qdf_spin_lock_bh(&scan->lock); + requesters[idx].requester = 0; + requesters[idx].module[0] = 0; + requesters[idx].ev_handler.func = NULL; + requesters[idx].ev_handler.arg = NULL; + qdf_spin_unlock_bh(&scan->lock); +} + +uint8_t* +ucfg_get_scan_requester_name(struct wlan_objmgr_psoc *psoc, + wlan_scan_requester requester) +{ + int idx = requester & ~WLAN_SCAN_REQUESTER_ID_PREFIX; + struct wlan_scan_obj *scan; + struct scan_requester_info *requesters; + + if (!psoc) { + scm_err("null psoc"); + return "null"; + } + scan = wlan_psoc_get_scan_obj(psoc); + requesters = scan->requesters; + + if ((idx < WLAN_MAX_REQUESTORS) && + (requesters[idx].requester == requester)) { + return requesters[idx].module; + } + + return (uint8_t *)"unknown"; +} + +wlan_scan_id +ucfg_scan_get_scan_id(struct wlan_objmgr_psoc *psoc) +{ + wlan_scan_id id; + struct wlan_scan_obj *scan; + + if (!psoc) { + QDF_ASSERT(0); + scm_err("null psoc"); + return 0; + } + scan = wlan_psoc_get_scan_obj(psoc); + + id = qdf_atomic_inc_return(&scan->scan_ids); + id = id & WLAN_SCAN_ID_MASK; + /* Mark this scan request as triggered by host + * by setting WLAN_HOST_SCAN_REQ_ID_PREFIX flag. + */ + id = id | WLAN_HOST_SCAN_REQ_ID_PREFIX; + scm_info("scan_id: 0x%x", id); + + return id; +} + +static QDF_STATUS +scm_add_scan_event_handler(struct pdev_scan_ev_handler *pdev_ev_handler, + scan_event_handler event_cb, void *arg) +{ + struct cb_handler *cb_handler; + uint32_t handler_cnt = pdev_ev_handler->handler_cnt; + + /* Assign next available slot to this registration request */ + cb_handler = &(pdev_ev_handler->cb_handlers[handler_cnt]); + cb_handler->func = event_cb; + cb_handler->arg = arg; + pdev_ev_handler->handler_cnt++; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_scan_register_event_handler(struct wlan_objmgr_vdev *vdev, + scan_event_handler event_cb, void *arg) +{ + uint32_t idx; + struct wlan_scan_obj *scan; + struct pdev_scan_ev_handler *pdev_ev_handler; + struct cb_handler *cb_handler; + + /* scan event handler call back can't be NULL */ + if (!vdev || !event_cb) { + scm_err("vdev: %p, event_cb: %p", vdev, event_cb); + return QDF_STATUS_E_NULL_VALUE; + } + + scm_info("vdev: %p, event_cb: %p, arg: %p\n", vdev, event_cb, arg); + + scan = wlan_vdev_get_scan_obj(vdev); + pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev); + cb_handler = &(pdev_ev_handler->cb_handlers[0]); + + qdf_spin_lock_bh(&scan->lock); + /* Ensure its not a duplicate registration request */ + for (idx = 0; idx < MAX_SCAN_EVENT_HANDLERS_PER_PDEV; + idx++, cb_handler++) { + if ((cb_handler->func == event_cb) && + (cb_handler->arg == arg)) { + qdf_spin_unlock_bh(&scan->lock); + scm_warn("func: %p, arg: %p already exists", + event_cb, arg); + return QDF_STATUS_SUCCESS; + } + } + + QDF_ASSERT(pdev_ev_handler->handler_cnt < + MAX_SCAN_EVENT_HANDLERS_PER_PDEV); + + if (pdev_ev_handler->handler_cnt >= MAX_SCAN_EVENT_HANDLERS_PER_PDEV) { + qdf_spin_unlock_bh(&scan->lock); + scm_warn("No more registrations possible"); + return QDF_STATUS_E_NOMEM; + } + + scm_add_scan_event_handler(pdev_ev_handler, event_cb, arg); + qdf_spin_unlock_bh(&scan->lock); + + scm_info("event_cb: 0x%p, arg: 0x%p", event_cb, arg); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +wlan_scan_global_init(struct wlan_scan_obj *scan_obj) +{ scan_obj->scan_def.active_dwell = SCAN_ACTIVE_DWELL_TIME; scan_obj->scan_def.passive_dwell = SCAN_PASSIVE_DWELL_TIME; scan_obj->scan_def.max_rest_time = SCAN_MAX_REST_TIME; @@ -102,28 +319,301 @@ static QDF_STATUS wlan_scan_global_init(struct wlan_scan_obj *scan_obj) scan_obj->scan_def.scan_ev_bss_chan = true; scan_obj->scan_def.scan_ev_foreign_chan = true; scan_obj->scan_def.scan_ev_dequeued = true; - + /* init scan id seed */ qdf_atomic_init(&scan_obj->scan_ids); return QDF_STATUS_SUCCESS; } -QDF_STATUS ucfg_scan_psoc_enable(struct wlan_objmgr_psoc *psoc) +static QDF_STATUS +scm_remove_scan_event_handler(struct pdev_scan_ev_handler *pdev_ev_handler, + struct cb_handler *entry) { + struct cb_handler *last_entry; + uint32_t handler_cnt = pdev_ev_handler->handler_cnt; + + /* Replace event handler being deleted + * with the last one in the list. + */ + last_entry = &(pdev_ev_handler->cb_handlers[handler_cnt - 1]); + entry->func = last_entry->func; + entry->arg = last_entry->arg; + + /* Clear our last entry */ + last_entry->func = NULL; + last_entry->arg = NULL; + pdev_ev_handler->handler_cnt--; + return QDF_STATUS_SUCCESS; } -QDF_STATUS ucfg_scan_psoc_disable(struct wlan_objmgr_psoc *psoc) +void +ucfg_scan_unregister_event_handler(struct wlan_objmgr_vdev *vdev, + scan_event_handler event_cb, void *arg) { + uint8_t found = false; + uint32_t idx; + uint32_t handler_cnt; + struct wlan_scan_obj *scan; + struct cb_handler *cb_handler; + struct pdev_scan_ev_handler *pdev_ev_handler; + + scm_info("vdev: %p, event_cb: 0x%p, arg: 0x%p", vdev, event_cb, arg); + if (!vdev) { + scm_err("null vdev"); + return; + } + scan = wlan_vdev_get_scan_obj(vdev); + pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev); + cb_handler = &(pdev_ev_handler->cb_handlers[0]); + + qdf_spin_lock_bh(&scan->lock); + handler_cnt = pdev_ev_handler->handler_cnt; + if (!handler_cnt) { + qdf_spin_unlock_bh(&scan->lock); + scm_info("No event handlers registered"); + } + + for (idx = 0; idx < MAX_SCAN_EVENT_HANDLERS_PER_PDEV; + idx++, cb_handler++) { + if ((cb_handler->func == event_cb) && + (cb_handler->arg == arg)) { + /* Event handler found, remove it + * from event handler list. + */ + found = true; + scm_remove_scan_event_handler(pdev_ev_handler, + cb_handler); + handler_cnt--; + break; + } + } + qdf_spin_unlock_bh(&scan->lock); + + scm_info("event handler %s, remaining handlers: %d", + (found ? "removed" : "not found"), handler_cnt); +} + +QDF_STATUS +ucfg_scan_init_default_params(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + struct scan_default_params *def; + + if (!vdev | !req) { + scm_err("vdev: 0x%p, req: 0x%p", vdev, req); + return QDF_STATUS_E_INVAL; + } + def = wlan_vdev_get_def_scan_params(vdev); + + /* Zero out everything and explicitly set fields as required */ + qdf_mem_zero(req, sizeof(*req)); + + req->vdev = vdev; + req->scan_req.vdev_id = wlan_vdev_get_id(vdev); + req->scan_req.scan_priority = def->scan_priority; + req->scan_req.dwell_time_active = def->active_dwell; + req->scan_req.dwell_time_passive = def->passive_dwell; + req->scan_req.min_rest_time = def->min_rest_time; + req->scan_req.max_rest_time = def->max_rest_time; + req->scan_req.repeat_probe_time = def->repeat_probe_time; + req->scan_req.probe_spacing_time = def->probe_spacing_time; + req->scan_req.idle_time = def->idle_time; + req->scan_req.max_scan_time = def->max_scan_time; + req->scan_req.probe_delay = def->probe_delay; + req->scan_req.burst_duration = def->burst_duration; + req->scan_req.n_probes = def->num_probes; + req->scan_req.scan_flags = def->scan_flags; + req->scan_req.scan_events = def->scan_events; + return QDF_STATUS_SUCCESS; } - -QDF_STATUS ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc) +QDF_STATUS +ucfg_scan_init_ssid_params(struct scan_start_request *req, + uint32_t num_ssid, struct wlan_ssid *ssid_list) +{ + uint32_t max_ssid = sizeof(req->scan_req.ssid) / + sizeof(req->scan_req.ssid[0]); + + if (!req) { + scm_err("null request"); + return QDF_STATUS_E_NULL_VALUE; + } + if (!num_ssid) { + /* empty channel list provided */ + req->scan_req.num_ssids = 0; + qdf_mem_zero(&req->scan_req.ssid[0], + sizeof(req->scan_req.ssid)); + return QDF_STATUS_SUCCESS; + } + if (!ssid_list) { + scm_err("null ssid_list while num_ssid: %d", num_ssid); + return QDF_STATUS_E_NULL_VALUE; + } + if (num_ssid > max_ssid) { + /* got a big list. alert and continue */ + scm_warn("overflow: received %d, max supported : %d", + num_ssid, max_ssid); + return QDF_STATUS_E_E2BIG; + } + + if (max_ssid > num_ssid) + max_ssid = num_ssid; + + req->scan_req.num_ssids = max_ssid; + qdf_mem_copy(&req->scan_req.ssid[0], ssid_list, + (req->scan_req.num_ssids * sizeof(req->scan_req.ssid[0]))); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_scan_init_bssid_params(struct scan_start_request *req, + uint32_t num_bssid, struct qdf_mac_addr *bssid_list) +{ + uint32_t max_bssid = sizeof(req->scan_req.bssid_list) / + sizeof(req->scan_req.bssid_list[0]); + + if (!req) { + scm_err("null request"); + return QDF_STATUS_E_NULL_VALUE; + } + if (!num_bssid) { + /* empty channel list provided */ + req->scan_req.num_bssid = 0; + qdf_mem_zero(&req->scan_req.bssid_list[0], + sizeof(req->scan_req.bssid_list)); + return QDF_STATUS_SUCCESS; + } + if (!bssid_list) { + scm_err("null bssid_list while num_bssid: %d", num_bssid); + return QDF_STATUS_E_NULL_VALUE; + } + if (num_bssid > max_bssid) { + /* got a big list. alert and continue */ + scm_warn("overflow: received %d, max supported : %d", + num_bssid, max_bssid); + return QDF_STATUS_E_E2BIG; + } + + if (max_bssid > num_bssid) + max_bssid = num_bssid; + + req->scan_req.num_bssid = max_bssid; + qdf_mem_copy(&req->scan_req.bssid_list[0], bssid_list, + req->scan_req.num_bssid * sizeof(req->scan_req.bssid_list[0])); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_scan_init_chanlist_params(struct scan_start_request *req, + uint32_t num_chans, uint32_t *chan_list) +{ + + uint32_t max_chans = sizeof(req->scan_req.chan_list) / + sizeof(req->scan_req.chan_list[0]); + if (!req) { + scm_err("null request"); + return QDF_STATUS_E_NULL_VALUE; + } + if (!num_chans) { + /* empty channel list provided */ + req->scan_req.num_chan = 0; + qdf_mem_zero(&req->scan_req.chan_list[0], + sizeof(req->scan_req.chan_list)); + return QDF_STATUS_SUCCESS; + } + if (!chan_list) { + scm_err("null chan_list while num_chans: %d", num_chans); + return QDF_STATUS_E_NULL_VALUE; + } + + if (num_chans > max_chans) { + /* got a big list. alert and continue */ + scm_warn("overflow: received %d, max supported : %d", + num_chans, max_chans); + return QDF_STATUS_E_E2BIG; + } + + if (max_chans > num_chans) + max_chans = num_chans; + + req->scan_req.num_chan = max_chans; + qdf_mem_copy(&req->scan_req.chan_list[0], chan_list, + req->scan_req.num_chan * sizeof(req->scan_req.chan_list[0])); + + return QDF_STATUS_SUCCESS; +} + +static inline enum scm_scan_status +get_scan_status_from_serialization_status( + enum wlan_serialization_cmd_status status) +{ + enum scm_scan_status scan_status; + + switch (status) { + case WLAN_SER_CMD_IN_PENDING_LIST: + scan_status = SCAN_IS_PENDING; + break; + case WLAN_SER_CMD_IN_ACTIVE_LIST: + scan_status = SCAN_IS_ACTIVE; + break; + case WLAN_SER_CMDS_IN_ALL_LISTS: + scan_status = SCAN_IS_ACTIVE_AND_PENDING; + break; + case WLAN_SER_CMD_NOT_FOUND: + scan_status = SCAN_NOT_IN_PROGRESS; + break; + default: + scm_warn("invalid serialization status %d", status); + QDF_ASSERT(0); + scan_status = SCAN_NOT_IN_PROGRESS; + break; + } + + return scan_status; +} + +enum scm_scan_status +ucfg_scan_get_vdev_status(struct wlan_objmgr_vdev *vdev) +{ + enum wlan_serialization_cmd_status status; + + if (!vdev) { + scm_err("null vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + status = wlan_serialization_vdev_scan_status(vdev); + + return get_scan_status_from_serialization_status(status); +} + +enum scm_scan_status +ucfg_scan_get_pdev_status(struct wlan_objmgr_pdev *pdev) +{ + enum wlan_serialization_cmd_status status; + + if (!pdev) { + scm_err("null pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + status = wlan_serialization_pdev_scan_status(pdev); + + return get_scan_status_from_serialization_status(status); +} + +QDF_STATUS +ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc) { - QDF_STATUS status = QDF_STATUS_SUCCESS; struct wlan_scan_obj *scan_obj; + scm_info("psoc open: 0x%p", psoc); + if (!psoc) { + scm_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } scan_obj = wlan_psoc_get_scan_obj(psoc); if (scan_obj == NULL) { scm_err("Failed to get scan object"); @@ -131,24 +621,63 @@ QDF_STATUS ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc) } /* Initialize the scan Globals */ wlan_scan_global_init(scan_obj); - + qdf_spinlock_create(&scan_obj->lock); scm_db_init(psoc); - return status; + return QDF_STATUS_SUCCESS; } -QDF_STATUS ucfg_scan_psoc_close(struct wlan_objmgr_psoc *psoc) +QDF_STATUS +ucfg_scan_psoc_close(struct wlan_objmgr_psoc *psoc) { - QDF_STATUS status = QDF_STATUS_SUCCESS; struct wlan_scan_obj *scan_obj; + scm_info("psoc close: 0x%p", psoc); + if (!psoc) { + scm_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } scan_obj = wlan_psoc_get_scan_obj(psoc); if (scan_obj == NULL) { scm_err("Failed to get scan object"); return QDF_STATUS_E_FAILURE; } - + qdf_spinlock_destroy(&scan_obj->lock); scm_db_deinit(psoc); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_scan_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + scm_info("psoc enable: 0x%p", psoc); + if (!psoc) { + scm_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + /* Subscribe for scan events from lmac layesr */ + status = tgt_scan_register_ev_handler(psoc); + QDF_ASSERT(status == QDF_STATUS_SUCCESS); + + return status; +} + +QDF_STATUS +ucfg_scan_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + scm_info("psoc disable: 0x%p", psoc); + if (!psoc) { + scm_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + /* Unsubscribe for scan events from lmac layesr */ + status = tgt_scan_unregister_ev_handler(psoc); + QDF_ASSERT(status == QDF_STATUS_SUCCESS); + return status; } diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c index 13a309c3d321..ec32f8295aec 100644 --- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c @@ -19,3 +19,87 @@ /* * DOC: Defines scan utility functions */ + +#include +#include +#include <../../core/src/wlan_scan_cache_db.h> +#include <../../core/src/wlan_scan_main.h> + +const char* +util_scan_get_ev_type_name(enum scan_event_type type) +{ + static const char * const event_name[] = { + [SCAN_EVENT_TYPE_STARTED] = "STARTED", + [SCAN_EVENT_TYPE_COMPLETED] = "COMPLETED", + [SCAN_EVENT_TYPE_BSS_CHANNEL] = "HOME_CHANNEL", + [SCAN_EVENT_TYPE_FOREIGN_CHANNEL] = "FOREIGN_CHANNEL", + [SCAN_EVENT_TYPE_DEQUEUED] = "DEQUEUED", + [SCAN_EVENT_TYPE_PREEMPTED] = "PREEMPTED", + [SCAN_EVENT_TYPE_START_FAILED] = "START_FAILED", + [SCAN_EVENT_TYPE_RESTARTED] = "RESTARTED", + [SCAN_EVENT_TYPE_FOREIGN_CHANNEL_EXIT] = "FOREIGN_CHANNEL_EXIT", + [SCAN_EVENT_TYPE_SUSPENDED] = "SUSPENDED", + [SCAN_EVENT_TYPE_RESUMED] = "RESUMED", + [SCAN_EVENT_TYPE_NLO_COMPLETE] = "NLO_COMPLETE", + [SCAN_EVENT_TYPE_INVALID] = "INVALID", + [SCAN_EVENT_TYPE_GPIO_TIMEOUT] = "GPIO_TIMEOUT", + [SCAN_EVENT_TYPE_RADIO_MEASUREMENT_START] = + "RADIO_MEASUREMENT_START", + [SCAN_EVENT_TYPE_RADIO_MEASUREMENT_END] = + "RADIO_MEASUREMENT_END", + [SCAN_EVENT_TYPE_BSSID_MATCH] = "BSSID_MATCH", + [SCAN_EVENT_TYPE_FOREIGN_CHANNEL_GET_NF] = + "FOREIGN_CHANNEL_GET_NF", + }; + + if (type >= SCAN_EVENT_TYPE_MAX) { + scm_err("unknown type : %d", type); + QDF_ASSERT(0); + return "UNKNOWN"; + } + + return event_name[type]; +} + + +const char* +util_scan_get_ev_reason_name(enum scan_completion_reason reason) +{ + static const char * const reason_name[] = { + [SCAN_REASON_NONE] = "NONE", + [SCAN_REASON_COMPLETED] = "COMPLETED", + [SCAN_REASON_CANCELLED] = "CANCELLED", + [SCAN_REASON_PREEMPTED] = "PREEMPTED", + [SCAN_REASON_TIMEDOUT] = "TIMEDOUT", + [SCAN_REASON_INTERNAL_FAILURE] = "INTERNAL_FAILURE", + [SCAN_REASON_SUSPENDED] = "SUSPENDED", + [SCAN_REASON_RUN_FAILED] = "RUN_FAILED", + [SCAN_REASON_TERMINATION_FUNCTION] = "TERMINATION_FUNCTION", + [SCAN_REASON_MAX_OFFCHAN_RETRIES] = "MAX_OFFCHAN_RETRIES", + }; + + if (reason >= SCAN_REASON_MAX) { + scm_err("unknown reason : %d", reason); + QDF_ASSERT(0); + return "UNKNOWN"; + } + + return reason_name[reason]; +} + +qdf_time_t +util_get_last_scan_time(struct wlan_objmgr_vdev *vdev) +{ + uint8_t pdev_id; + struct wlan_scan_obj *scan_obj; + + if (!vdev) { + scm_warn("null vdev"); + QDF_ASSERT(0); + return 0; + } + pdev_id = wlan_scan_vdev_get_pdev_id(vdev); + scan_obj = wlan_vdev_get_scan_obj(vdev); + + return scan_obj->pdev_info[pdev_id].last_scan_time; +}