| /* |
| * 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: Define API's for wow pattern addition and deletion in fwr |
| */ |
| |
| #include "wlan_pmo_wow.h" |
| #include "wlan_pmo_tgt_api.h" |
| #include "wlan_pmo_main.h" |
| #include "wlan_pmo_obj_mgmt_public_struct.h" |
| #include <wlan_scan_ucfg_api.h> |
| #include "wlan_pmo_static_config.h" |
| #include "wlan_reg_services_api.h" |
| |
| static inline int pmo_find_wow_ptrn_len(const char *ptrn) |
| { |
| int len = 0; |
| |
| while (*ptrn != '\0' && *ptrn != PMO_WOW_INTER_PTRN_TOKENIZER) { |
| len++; |
| ptrn++; |
| } |
| |
| return len; |
| } |
| |
| QDF_STATUS pmo_core_add_wow_pattern(struct wlan_objmgr_vdev *vdev, |
| const char *ptrn) |
| { |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS pmo_core_del_wow_pattern(struct wlan_objmgr_vdev *vdev, |
| const char *ptrn) |
| { |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS pmo_core_wow_enter(struct wlan_objmgr_vdev *vdev, |
| struct pmo_wow_enter_params *wow_enter_param) |
| { |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS pmo_core_wow_exit(struct wlan_objmgr_vdev *vdev) |
| { |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| void pmo_core_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, |
| uint32_t vdev_id, uint32_t *bitmap) |
| { |
| QDF_STATUS status; |
| struct wlan_objmgr_vdev *vdev; |
| |
| PMO_ENTER(); |
| if (!psoc) { |
| pmo_err("psoc is null"); |
| goto out; |
| } |
| |
| vdev = pmo_psoc_get_vdev(psoc, vdev_id); |
| if (!vdev) { |
| pmo_err("vdev is NULL"); |
| goto out; |
| } |
| |
| status = pmo_vdev_get_ref(vdev); |
| if (QDF_IS_STATUS_ERROR(status)) |
| goto out; |
| |
| pmo_info("enable wakeup event vdev_id %d wake up event 0x%x%x%x%x", |
| vdev_id, bitmap[0], bitmap[1], bitmap[2], bitmap[3]); |
| pmo_tgt_enable_wow_wakeup_event(vdev, bitmap); |
| |
| pmo_vdev_put_ref(vdev); |
| |
| out: |
| PMO_EXIT(); |
| } |
| |
| void pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, |
| uint32_t vdev_id, uint32_t *bitmap) |
| { |
| QDF_STATUS status; |
| struct wlan_objmgr_vdev *vdev; |
| |
| PMO_ENTER(); |
| if (!psoc) { |
| pmo_err("psoc is null"); |
| goto out; |
| } |
| |
| vdev = pmo_psoc_get_vdev(psoc, vdev_id); |
| if (!vdev) { |
| pmo_err("vdev is NULL"); |
| goto out; |
| } |
| |
| status = pmo_vdev_get_ref(vdev); |
| if (QDF_IS_STATUS_ERROR(status)) |
| goto out; |
| |
| pmo_info("Disable wakeup event vdev_id %d wake up event 0x%x%x%x%x", |
| vdev_id, bitmap[0], bitmap[1], bitmap[2], bitmap[3]); |
| pmo_tgt_disable_wow_wakeup_event(vdev, bitmap); |
| |
| pmo_vdev_put_ref(vdev); |
| |
| out: |
| PMO_EXIT(); |
| } |
| |
| /** |
| * pmo_is_beaconing_vdev_up(): check if a beaconning vdev is up |
| * @psoc: objmgr psoc handle |
| * |
| * Return TRUE if beaconning vdev is up |
| */ |
| static |
| bool pmo_is_beaconing_vdev_up(struct wlan_objmgr_psoc *psoc) |
| { |
| int vdev_id; |
| struct wlan_objmgr_vdev *vdev; |
| enum tQDF_ADAPTER_MODE vdev_opmode; |
| bool is_beaconing; |
| QDF_STATUS status; |
| |
| /* Iterate through VDEV list */ |
| for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { |
| vdev = pmo_psoc_get_vdev(psoc, vdev_id); |
| if (!vdev) |
| continue; |
| |
| status = pmo_vdev_get_ref(vdev); |
| if (QDF_IS_STATUS_ERROR(status)) |
| continue; |
| |
| vdev_opmode = pmo_get_vdev_opmode(vdev); |
| is_beaconing = pmo_is_vdev_in_beaconning_mode(vdev_opmode) && |
| pmo_is_vdev_up(vdev); |
| |
| pmo_vdev_put_ref(vdev); |
| |
| if (is_beaconing) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * pmo_support_wow_for_beaconing: wow query for beaconning |
| * @psoc: objmgr psoc handle |
| * |
| * Need to configure wow to enable beaconning offload when |
| * a beaconing vdev is up and beaonning offload is configured. |
| * |
| * Return: true if we need to enable wow for beaconning offload |
| */ |
| static |
| bool pmo_support_wow_for_beaconing(struct wlan_objmgr_psoc *psoc) |
| { |
| /* |
| * if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, |
| * WMI_SERVICE_BEACON_OFFLOAD)) |
| */ |
| return pmo_is_beaconing_vdev_up(psoc); |
| } |
| |
| bool pmo_core_is_wow_applicable(struct wlan_objmgr_psoc *psoc) |
| { |
| int vdev_id; |
| struct wlan_objmgr_vdev *vdev; |
| bool is_wow_applicable; |
| QDF_STATUS status; |
| |
| if (!psoc) { |
| pmo_err("psoc is null"); |
| return false; |
| } |
| |
| if (pmo_support_wow_for_beaconing(psoc)) { |
| pmo_debug("one of vdev is in beaconning mode, enabling wow"); |
| return true; |
| } |
| |
| if (wlan_reg_is_11d_scan_inprogress(psoc)) { |
| pmo_debug("11d scan is in progress, enabling wow"); |
| return true; |
| } |
| |
| /* Iterate through VDEV list */ |
| for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { |
| vdev = pmo_psoc_get_vdev(psoc, vdev_id); |
| if (!vdev) |
| continue; |
| |
| status = pmo_vdev_get_ref(vdev); |
| if (QDF_IS_STATUS_ERROR(status)) |
| continue; |
| |
| if (pmo_core_is_vdev_connected(vdev)) { |
| pmo_debug("STA is connected, enabling wow"); |
| is_wow_applicable = true; |
| } else if (ucfg_scan_get_pno_in_progress(vdev)) { |
| pmo_debug("NLO is in progress, enabling wow"); |
| is_wow_applicable = true; |
| } else if (pmo_core_is_extscan_in_progress(vdev)) { |
| pmo_debug("EXT is in progress, enabling wow"); |
| is_wow_applicable = true; |
| } else if (pmo_core_is_p2plo_in_progress(vdev)) { |
| pmo_debug("P2P LO is in progress, enabling wow"); |
| is_wow_applicable = true; |
| } else if (pmo_core_is_lpass_enabled(vdev)) { |
| pmo_debug("LPASS is enabled, enabling WoW"); |
| is_wow_applicable = true; |
| } else if (pmo_core_is_nan_enabled(vdev)) { |
| pmo_debug("NAN is enabled, enabling WoW"); |
| is_wow_applicable = true; |
| } else if (pmo_core_get_vdev_op_mode(vdev) == QDF_NDI_MODE) { |
| pmo_debug("vdev %d is in NAN data mode, enabling wow", |
| vdev_id); |
| is_wow_applicable = true; |
| } |
| |
| pmo_vdev_put_ref(vdev); |
| |
| if (is_wow_applicable) |
| return true; |
| } |
| |
| pmo_debug("All vdev are in disconnected state\n" |
| "and pno/extscan is not in progress, skipping wow"); |
| |
| return false; |
| } |
| |
| void pmo_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event, |
| uint32_t wow_bitmap_size, |
| uint32_t *bitmask) |
| { |
| uint32_t bit_idx = 0, idx = 0; |
| |
| if (!bitmask || wow_bitmap_size < PMO_WOW_MAX_EVENT_BM_LEN) { |
| pmo_err("wow bitmask length shorter than %d", |
| PMO_WOW_MAX_EVENT_BM_LEN); |
| return; |
| } |
| pmo_get_event_bitmap_idx(event, wow_bitmap_size, &bit_idx, &idx); |
| bitmask[idx] |= 1 << bit_idx; |
| |
| pmo_debug("%s: bitmask updated %x%x%x%x", |
| __func__, bitmask[0], bitmask[1], bitmask[2], bitmask[3]); |
| } |
| |
| void pmo_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) |
| { |
| |
| pmo_set_wow_event_bitmap(WOW_CSA_IE_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_MAGIC_PKT_RECVD_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_BMISS_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_GTK_ERR_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_BETTER_AP_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_HTT_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_RA_MATCH_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_NLO_DETECTED_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_EXTSCAN_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_OEM_RESPONSE_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_TDLS_CONN_TRACKER_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_11D_SCAN_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| |
| } |
| |
| void pmo_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) |
| { |
| |
| pmo_set_wow_event_bitmap(WOW_PROBE_REQ_WPS_IE_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_AUTH_REQ_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_ASSOC_REQ_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| pmo_set_wow_event_bitmap(WOW_HTT_EVENT, |
| wow_bitmap_size, |
| bitmask); |
| } |