// SPDX-License-Identifier: GPL-2.0-only #include #include #include "img_mac80211_types.h" #include "gfp.h" #include "img_osal_rculist.h" #include "ieee80211_i.h" #include "core.h" #include "uccrt.h" #include "img_module_iface.h" #include "img_host_rpu_umac_iface.h" #include "wlan_umac_api.h" #include #include #include "nl80211.h" #include "img_host_txrx_buffs.h" RETENTION_MEM_SECTION_UNINITIALIZED struct cfg80211_registered_device *cfg80211_rdev; RETENTION_MEM_SECTION_UNINITIALIZED struct umac_sleep_debugparams sleep_dbg; RETENTION_MEM_SECTION_UNINITIALIZED struct img_cmd_event_dbg img_cmd_event_dbg_params; RETENTION_MEM_SECTION_UNINITIALIZED struct umac_prod_debugparams prod_dbg; #ifdef ENABLE_OTP RETENTION_MEM_SECTION_UNINITIALIZED struct rpu_otp_params otp_params; #endif struct img_ap_dbg img_ap_dbg_params; unsigned char umac_wait_for_get_scan; #define UMAC_RX_TASK_NAME "UMAC RX TASK" task_t umac_rx_task_g; MAILBOX_T umacCmdMbox; MAILBOX_T rxMbox; void hal_module_init(); void img_crypto_init(void); void img_genlmsg_reply(void *msg, unsigned int msg_len); void *umac_event_alloc(enum img_module_iface_port_id port_id, unsigned int *len); int umac_proc_cmd_get_tx_power(struct nrf_wifi_umac_cmd_get_channel *cmd_get_ch, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); int umac_proc_cmd_get_channel(struct nrf_wifi_umac_cmd_get_tx_power *cmd_get_txpwr, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); int img_umac_proc_cmd_config_twt_req(struct nrf_wifi_umac_cmd_config_twt *cmd,struct wireless_dev *wdev); int img_umac_proc_cmd_twt_teardown(struct nrf_wifi_umac_cmd_teardown_twt *cmd,struct wireless_dev *wdev); #ifdef WIN_MLME void send_cmd_assoc(struct nrf_wifi_umac_cmd_assoc *cmd_associate) { struct host_rpu_msg *host_rpu_msg_p; struct nrf_wifi_umac_hdr *cmd_hdr; int err; unsigned int cmd_len = sizeof(struct host_rpu_msg) + sizeof(struct nrf_wifi_umac_cmd_assoc); host_rpu_msg_p = kzalloc(cmd_len, GFP_KERNEL); host_rpu_msg_p->type = IMG_HOST_RPU_MSG_TYPE_UMAC; host_rpu_msg_p->hdr.len = cmd_len; memcpy(host_rpu_msg_p->msg, cmd_associate, sizeof(struct nrf_wifi_umac_cmd_assoc)); umac_task_post(IMG_MODULE_IFACE_WPAS_UMAC_PORT, host_rpu_msg_p, cmd_len); } #endif void umac_task_post(enum img_module_iface_port_id port_id, void *msg, int msg_len) { struct mbox_message *mbox_msg; mbox_msg = kzalloc(sizeof(struct mbox_message), GFP_KERNEL); mbox_msg->port_id = port_id; mbox_msg->msg = msg; mbox_msg->msg_len = msg_len; KRN_putMbox(&umacCmdMbox, mbox_msg); } void send_tasklet_to_mbox(struct tasklet_struct *tasklet) { IMG_RX_DBG_PARAM_INCR(tasklet_mbox_post, 1); umac_task_post(IMG_MODULE_IFACE_TASKLET_PORT, tasklet, sizeof(struct tasklet *)); } int umac_open() { struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local; struct cfg80211_registered_device *rdev; struct wiphy *wiphy; int ret; rdev = cfg80211_rdev; wiphy = &rdev->wiphy; local = wiphy_priv(wiphy); sdata = DQ_first(&local->interfaces); ret = ieee80211_open(sdata->dev); if(ret) { printk("ERROR: %s:%d ieee80211_open failed ret: %d\n", __FUNCTION__, __LINE__, ret); return ret; } return 0; } struct wireless_dev *get_wdev(struct cfg80211_registered_device *rdev, struct nrf_wifi_index_ids ids) { struct wireless_dev *wdev = NULL; int ifindex_valid, wdevid_valid; u64 wdev_id = 0; int wiphy_idx = -1; int ifidx = -1; ifindex_valid = ids.valid_fields & NRF_WIFI_INDEX_IDS_IFINDEX_VALID; wdevid_valid = ids.valid_fields & NRF_WIFI_INDEX_IDS_WDEV_ID_VALID; if(ifindex_valid) ifidx = ids.ifaceindex; if(wdevid_valid) { wdev_id = ids.wdev_id; wiphy_idx = wdev_id >> 32; } if(!(wdevid_valid) && !(ifindex_valid)) { printk("%s:%d either one of wdevid_valid and ifindex_valid should be 1\n", __FUNCTION__, __LINE__); return NULL; } if (wdevid_valid && rdev->wiphy_idx != wiphy_idx) { printk("%s:%d unexpected wiphy_idx %d expected %d\n", __FUNCTION__, __LINE__, rdev->wiphy_idx, wiphy_idx); return NULL; } list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (ifindex_valid && wdev->netdev && wdev->netdev->ifindex == ifidx) { return wdev; } if (wdevid_valid && wdev->identifier == (u32)wdev_id) { return wdev; } } return wdev; } int umac_proc_cmd_new_interface(struct nrf_wifi_umac_cmd_add_vif *cmdbuf) { struct cfg80211_registered_device *rdev; rdev = cfg80211_rdev; rdev->wdev_id = cmdbuf->umac_hdr.ids.wdev_id; return nl80211_new_interface(cmdbuf, rdev); } #ifdef WIN_MLME int umac_proc_cmd_win_sta_connect(struct nrf_wifi_umac_cmd_win_sta_connect *cmdbuf) { struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; struct net_device *netdev; struct nrf_wifi_umac_cmd_auth new_cmdbuf; rdev = cfg80211_rdev; wdev = get_wdev(rdev, cmdbuf->umac_hdr.ids); if(wdev == NULL) { printk("%s:%d invalid index\n", __FUNCTION__, __LINE__); return -ENODEV; } netdev = wdev->netdev; /*Copy the Windows Connect parameters to wdev->win_connect*/ wdev->win_connect.center_freq = cmdbuf->center_frequency; memcpy(wdev->win_connect.bssid, cmdbuf->img_bssid, ETH_ALEN); memcpy(wdev->win_connect.ssid, cmdbuf->ssid.img_ssid, cmdbuf->ssid.img_ssid_len); wdev->win_connect.ssid_len = cmdbuf->ssid.img_ssid_len; memcpy(wdev->win_connect.wpa_ie, cmdbuf->wpa_ie.ie, cmdbuf->wpa_ie.ie_len); wdev->win_connect.wpa_ie_len = cmdbuf->wpa_ie.ie_len; wdev->win_connect.win_sta_auth_sent = 1; new_cmdbuf.umac_hdr.cmd_evnt = NRF_WIFI_UMAC_CMD_AUTHENTICATE; memcpy(new_cmdbuf.info.img_bssid, cmdbuf->img_bssid, ETH_ALEN); new_cmdbuf.valid_fields |= IMG_CMD_AUTHENTICATE_SSID_VALID; new_cmdbuf.info.ssid.img_ssid_len = cmdbuf->ssid.img_ssid_len; memcpy(new_cmdbuf.info.ssid.img_ssid, cmdbuf->ssid.img_ssid, cmdbuf->ssid.img_ssid_len); new_cmdbuf.valid_fields |= IMG_CMD_AUTHENTICATE_FREQ_VALID; new_cmdbuf.info.frequency = cmdbuf->center_frequency; new_cmdbuf.info.auth_type = cmdbuf->auth_type; nl80211_authenticate(&new_cmdbuf, rdev, netdev); return 0; } int umac_proc_cmd_win_sta_connect_extension(struct wireless_dev *wdev) { struct cfg80211_registered_device *rdev; struct net_device *netdev; struct nrf_wifi_umac_cmd_assoc cmd_associate; struct img_connect_common_info *connect_common_info; rdev = cfg80211_rdev; if(wdev == NULL) { printk("%s:%d invalid index\n", __FUNCTION__, __LINE__); return -ENODEV; } netdev = wdev->netdev; memset(&cmd_associate, 0, sizeof(struct nrf_wifi_umac_cmd_assoc)); connect_common_info = &cmd_associate.connect_common_info; cmd_associate.umac_hdr.cmd_evnt = NRF_WIFI_UMAC_CMD_ASSOCIATE; cmd_associate.umac_hdr.ids.wdev_id = wdev->identifier; cmd_associate.umac_hdr.ids.valid_fields |= IMG_INDEX_IDS_WDEV_ID_VALID; /*MAC Address*/ connect_common_info->valid_fields |= IMG_CONNECT_COMMON_INFO_MAC_ADDR_VALID; memcpy(connect_common_info->mac_addr, wdev->win_connect.bssid, ETH_ALEN); connect_common_info->valid_fields |= IMG_CONNECT_COMMON_INFO_SSID_VALID; connect_common_info->ssid.img_ssid_len = wdev->win_connect.ssid_len; memcpy(connect_common_info->ssid.img_ssid, wdev->win_connect.ssid, wdev->win_connect.ssid_len); /*Frequency*/ connect_common_info->valid_fields |= IMG_CONNECT_COMMON_INFO_FREQ_VALID; connect_common_info->frequency = wdev->win_connect.center_freq; /*WPA-IE*/ connect_common_info->valid_fields |= IMG_CONNECT_COMMON_INFO_WPA_IE_VALID; connect_common_info->wpa_ie.ie_len = wdev->win_connect.wpa_ie_len; memcpy (connect_common_info->wpa_ie.ie, wdev->win_connect.wpa_ie, wdev->win_connect.wpa_ie_len); send_cmd_assoc(&cmd_associate); return 0; } #endif int umac_proc_config_uapsd(struct nrf_wifi_umac_cmd_config_uapsd *cmd, struct net_device *netdev) { struct ieee80211_sub_if_data *sdata=IEEE80211_DEV_TO_SUB_IF(netdev); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; if(sdata->vif.type == NL80211_IFTYPE_STATION) { ifmgd->uapsd_queues = cmd->info.uapsd_queue; } return 0; } int handle_get_cmd_in_patch(int host_cmd) { return -1; } int get_cmd(int host_cmd) { int ret = 0; ret = handle_get_cmd_in_patch(host_cmd); if(ret >=0) { return ret; } switch(host_cmd) { case NRF_WIFI_UMAC_CMD_TRIGGER_SCAN: return NL80211_CMD_TRIGGER_SCAN; case NRF_WIFI_UMAC_CMD_GET_SCAN_RESULTS: return NL80211_CMD_GET_SCAN; case NRF_WIFI_UMAC_CMD_AUTHENTICATE: return NL80211_CMD_AUTHENTICATE; case NRF_WIFI_UMAC_CMD_ASSOCIATE: return NL80211_CMD_ASSOCIATE; case NRF_WIFI_UMAC_CMD_DEAUTHENTICATE: return NL80211_CMD_DEAUTHENTICATE; case NRF_WIFI_UMAC_CMD_NEW_KEY: return NL80211_CMD_NEW_KEY; case NRF_WIFI_UMAC_CMD_SET_KEY: return NL80211_CMD_SET_KEY; case NRF_WIFI_UMAC_CMD_GET_KEY: return NL80211_CMD_GET_KEY; case NRF_WIFI_UMAC_CMD_JOIN_IBSS: return NL80211_CMD_JOIN_IBSS; case NRF_WIFI_UMAC_CMD_SET_BSS: return NL80211_CMD_SET_BSS; case NRF_WIFI_UMAC_CMD_START_AP: return NL80211_CMD_START_AP; case NRF_WIFI_UMAC_CMD_SET_BEACON: return NL80211_CMD_SET_BEACON; case NRF_WIFI_UMAC_CMD_STOP_AP: return NL80211_CMD_STOP_AP; case NRF_WIFI_UMAC_CMD_SET_INTERFACE: return NL80211_CMD_SET_INTERFACE; case NRF_WIFI_UMAC_CMD_SET_IFFLAGS: return IMG_CMD_SET_IFFLAGS; case NRF_WIFI_UMAC_CMD_NEW_INTERFACE: return NL80211_CMD_NEW_INTERFACE; case NRF_WIFI_UMAC_CMD_DEL_INTERFACE: return NL80211_CMD_DEL_INTERFACE; case NRF_WIFI_UMAC_CMD_SET_CHANNEL: return NL80211_CMD_SET_CHANNEL; case NRF_WIFI_UMAC_CMD_SET_WIPHY: return NL80211_CMD_SET_WIPHY; case NRF_WIFI_UMAC_CMD_DEL_STATION: return NL80211_CMD_DEL_STATION; case NRF_WIFI_UMAC_CMD_NEW_STATION: return NL80211_CMD_NEW_STATION; case NRF_WIFI_UMAC_CMD_SET_STATION: return NL80211_CMD_SET_STATION; case NRF_WIFI_UMAC_CMD_GET_STATION: return NL80211_CMD_GET_STATION; case NRF_WIFI_UMAC_CMD_DEL_KEY: return NL80211_CMD_DEL_KEY; case NRF_WIFI_UMAC_CMD_REGISTER_FRAME: return NL80211_CMD_REGISTER_FRAME; case NRF_WIFI_UMAC_CMD_FRAME: return NL80211_CMD_FRAME; case NRF_WIFI_UMAC_CMD_REMAIN_ON_CHANNEL: return NL80211_CMD_REMAIN_ON_CHANNEL; case NRF_WIFI_UMAC_CMD_CANCEL_REMAIN_ON_CHANNEL: return NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL; case NRF_WIFI_UMAC_CMD_START_P2P_DEVICE: return NL80211_CMD_START_P2P_DEVICE; case NRF_WIFI_UMAC_CMD_STOP_P2P_DEVICE: return NL80211_CMD_STOP_P2P_DEVICE; #ifdef WIN_MLME case NRF_WIFI_UMAC_CMD_WIN_STA_CONNECT: return IMG_CMD_WIN_STA_CONNECT; #endif case NRF_WIFI_UMAC_CMD_SET_QOS_MAP: return NL80211_CMD_SET_QOS_MAP; case NRF_WIFI_UMAC_CMD_GET_CHANNEL: return IMG_CMD_GET_CHANNEL; case NRF_WIFI_UMAC_CMD_GET_TX_POWER: return IMG_CMD_GET_TX_POWER; case NRF_WIFI_UMAC_CMD_SET_POWER_SAVE: return NL80211_CMD_SET_POWER_SAVE; case NRF_WIFI_UMAC_CMD_GET_INTERFACE: return NL80211_CMD_GET_INTERFACE; case NRF_WIFI_UMAC_CMD_GET_WIPHY: return NL80211_CMD_GET_WIPHY; case NRF_WIFI_UMAC_CMD_GET_IFHWADDR: return IMG_CMD_GET_IFHWADDR; case NRF_WIFI_UMAC_CMD_SET_IFHWADDR: return IMG_CMD_SET_IFHWADDR; case NRF_WIFI_UMAC_CMD_GET_REG: return NL80211_CMD_GET_REG; case NRF_WIFI_UMAC_CMD_SET_REG: return NL80211_CMD_SET_REG; case NRF_WIFI_UMAC_CMD_REQ_SET_REG: return NL80211_CMD_REQ_SET_REG; case NRF_WIFI_UMAC_CMD_CONFIG_UAPSD: return IMG_CMD_CONFIG_UAPSD; case NRF_WIFI_UMAC_CMD_CONFIG_TWT: return IMG_CMD_CONFIG_TWT; case NRF_WIFI_UMAC_CMD_TEARDOWN_TWT: return IMG_CMD_TEARDOWN_TWT; case NRF_WIFI_UMAC_CMD_ABORT_SCAN: return NL80211_CMD_ABORT_SCAN; case NRF_WIFI_UMAC_CMD_MCAST_FILTER: return IMG_CMD_MCAST_FILTER; default: { printk("UNKNOWN UMAC COMMAND %d\n", host_cmd); return -1; } } } int send_cmd_status_event_to_host(unsigned int cmd_id, int ret_ststus) { struct nrf_wifi_umac_event_cmd_status *cmd_status; unsigned int req_len; if (cmd_id == NRF_WIFI_UMAC_CMD_REGISTER_FRAME || cmd_id == NRF_WIFI_UMAC_CMD_DEAUTHENTICATE) return 0; if(ret_ststus >= 0) { if(cmd_id == NRF_WIFI_UMAC_CMD_GET_REG || cmd_id == NRF_WIFI_UMAC_CMD_GET_KEY || cmd_id == NRF_WIFI_UMAC_CMD_GET_STATION || cmd_id == NRF_WIFI_UMAC_CMD_GET_WIPHY || cmd_id == NRF_WIFI_UMAC_CMD_GET_INTERFACE || cmd_id == NRF_WIFI_UMAC_CMD_GET_SCAN_RESULTS || cmd_id == NRF_WIFI_UMAC_CMD_SET_INTERFACE || cmd_id == NRF_WIFI_UMAC_CMD_SET_IFFLAGS || #ifdef WIN_MLME cmd_id == NRF_WIFI_UMAC_CMD_WIN_STA_CONNECT || #endif /* WIN_MLME */ cmd_id == NRF_WIFI_UMAC_CMD_GET_CHANNEL || cmd_id == NRF_WIFI_UMAC_CMD_GET_IFHWADDR || cmd_id == NRF_WIFI_UMAC_CMD_SET_IFHWADDR || cmd_id == IMG_CMD_CONFIG_UAPSD || cmd_id == NRF_WIFI_UMAC_CMD_CONFIG_TWT || cmd_id == NRF_WIFI_UMAC_CMD_TEARDOWN_TWT || cmd_id == NRF_WIFI_UMAC_CMD_GET_TX_POWER || cmd_id == NRF_WIFI_UMAC_CMD_ABORT_SCAN) { return 0; } } req_len = sizeof(struct nrf_wifi_umac_event_cmd_status); cmd_status = umac_event_alloc(IMG_MODULE_IFACE_UMAC_WPAS_RESP_PORT, &req_len); if (!cmd_status) return -ENOBUFS; cmd_status->umac_hdr.cmd_evnt = NRF_WIFI_UMAC_EVENT_CMD_STATUS; cmd_status->umac_hdr.portid = 0; cmd_status->umac_hdr.seq = 0; cmd_status->cmd_id = cmd_id; cmd_status->cmd_status = ret_ststus; img_genlmsg_reply((void *)cmd_status, sizeof(*cmd_status)); return 0; } /* * General list handling functions */ static int hw_addr_create_ex(struct netdev_hw_addr_list *list, const unsigned char *addr, int addr_len, unsigned char addr_type, bool global, bool sync) { struct netdev_hw_addr *ha; int alloc_size; alloc_size = sizeof(*ha); ha = kmalloc(alloc_size, GFP_ATOMIC); if (!ha) return -ENOMEM; memcpy(ha->addr, addr, addr_len); ha->type = addr_type; ha->refcount = 1; ha->global_use = global; ha->synced = sync ? 1 : 0; ha->sync_cnt = 0; list_add_tail_rcu(&ha->list, &list->list); list->count++; return 0; } int umac_prepare_mcast_filter(struct nrf_wifi_umac_cmd_mcast_filter *mcast_cfg, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) { u64 mc, ret = 0, count = 0; unsigned int i = 0; struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local; unsigned char mac_addr1[ETH_ALEN]; sdata = IEEE80211_DEV_TO_SUB_IF(wdev->netdev); local = sdata->local; count = mcast_cfg->info.count; for (i = 0; i < count; i++) { hw_addr_create_ex(&wdev->netdev->mc, mcast_cfg->info.mcast_bssid[i].bssid, wdev->netdev->addr_len, NETDEV_HW_ADDR_T_MULTICAST, false, false) ; } spin_lock_bh(&local->filter_lock); if (local->ops->prepare_multicast) { ret = local->ops->prepare_multicast(&local->hw, &wdev->netdev->mc); } spin_unlock_bh(&local->filter_lock); return ret; } int handle_wlan_umac_command_proc_in_patch1(void *cmdbuf,int cmd_type,struct cfg80211_registered_device *cfg80211_rdev,int *ret) { return 0; } int handle_wlan_umac_command_proc_in_patch2(void *cmdbuf,int cmd_type,struct cfg80211_registered_device *rdev,struct wireless_dev *wdev,struct net_device *netdev,int *ret) { return 0; } int last_command_type; int rpu_msg_handler(void *); unsigned int wlan_umac_command_proc(void *cmdbuf) { int command_type; int ret = 0; struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; struct net_device *netdev; unsigned char no_ack_status = 0; struct nrf_wifi_umac_hdr *cmd_hdr = (struct nrf_wifi_umac_hdr *)cmdbuf; command_type = get_cmd(cmd_hdr->cmd_evnt); last_command_type = command_type; rdev = cfg80211_rdev; if(handle_wlan_umac_command_proc_in_patch1(cmdbuf, command_type, rdev, &ret)) { return 0; } switch(command_type) { case NL80211_CMD_NEW_INTERFACE: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_new_interface, 1); ret = umac_proc_cmd_new_interface((struct nrf_wifi_umac_cmd_add_vif *)cmdbuf); } break; case IMG_CMD_SET_IFHWADDR: { ret = umac_set_ifhwaddr_byname((struct nrf_wifi_cmd_set_ifhwaddr *)cmdbuf, cfg80211_rdev); } break; case IMG_CMD_SET_IFFLAGS: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_ifflags, 1); ret = umac_set_ifflags((struct nrf_wifi_umac_cmd_chg_vif_state *)cmdbuf, cfg80211_rdev); IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_ifflags_done, 1); } break; case NL80211_CMD_SET_REG: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_reg, 1); ret = nl80211_set_reg(cmdbuf); } break; case NL80211_CMD_GET_REG: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_get_reg, 1); ret = nl80211_get_reg_do(rdev); } break; case NL80211_CMD_REQ_SET_REG: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_req_set_reg, 1); ret = nl80211_req_set_reg(cmdbuf); } break; } wdev = get_wdev(rdev, cmd_hdr->ids); if(wdev == NULL) { printk("%s:%d invalid index\n", __FUNCTION__, __LINE__); return -ENODEV; } netdev = wdev->netdev; if(handle_wlan_umac_command_proc_in_patch2(cmdbuf, command_type, rdev, wdev, netdev, &ret)) { return 0; } switch(command_type) { case NL80211_CMD_TRIGGER_SCAN: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_trigger_scan, 1); ret = nl80211_trigger_scan(cmdbuf, rdev, wdev); } break; #ifdef ADHOC_MODE_SUPPORT case NL80211_CMD_JOIN_IBSS: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_join_ibss, 1); netdev = wdev->netdev; ret = nl80211_join_ibss(cmdbuf, rdev, netdev); } break; #endif /* ADHOC_MODE_SUPPORT */ case NL80211_CMD_SET_INTERFACE: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_interface, 1); ret = nl80211_set_interface(cmdbuf, rdev, netdev); } break; case NL80211_CMD_SET_CHANNEL: { netdev = wdev->netdev; ret = nl80211_set_channel(cmdbuf, rdev, netdev); } break; case NL80211_CMD_SET_WIPHY: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_wiphy, 1); ret = nl80211_set_wiphy(cmdbuf, rdev, netdev); } break; case NL80211_CMD_SET_KEY: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_key, 1); ret = nl80211_set_key(cmdbuf, rdev, netdev); } break; case NL80211_CMD_NEW_KEY: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_new_key, 1); ret = nl80211_new_key(cmdbuf, rdev, netdev); } break; case NL80211_CMD_DEL_KEY: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_del_key, 1); ret = nl80211_del_key(cmdbuf, rdev, netdev); } break; case NL80211_CMD_AUTHENTICATE: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_auth, 1); ret = nl80211_authenticate(cmdbuf, rdev, netdev); } break; case NL80211_CMD_ASSOCIATE: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_assoc, 1); ret = nl80211_associate(cmdbuf, rdev, netdev); } break; case NL80211_CMD_DEL_INTERFACE: { ret = nl80211_del_interface(cmdbuf, rdev, wdev); } break; case NL80211_CMD_SET_STATION: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_station, 1); ret = nl80211_set_station(cmdbuf, rdev, netdev); } break; case NL80211_CMD_NEW_STATION: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_new_station, 1); ret = nl80211_new_station(cmdbuf, rdev, netdev); } break; case NL80211_CMD_DEL_STATION: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_del_station, 1); ret = nl80211_del_station(cmdbuf, rdev, netdev); } break; case NL80211_CMD_REGISTER_FRAME: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_register_frame, 1); ret = nl80211_register_mgmt(cmdbuf, rdev, wdev); } break; case NL80211_CMD_FRAME: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_frame, 1); no_ack_status = ((struct nrf_wifi_umac_cmd_mgmt_tx *)cmdbuf)->info.nrf_wifi_flags & NRF_WIFI_CMD_FRAME_DONT_WAIT_FOR_ACK; ret = nl80211_tx_mgmt(cmdbuf, rdev, wdev); cmd_hdr->rpu_ret_val = ret; if ((cmd_hdr->cmd_evnt == NRF_WIFI_UMAC_CMD_FRAME && !no_ack_status)) { return 0; } } break; case NL80211_CMD_GET_INTERFACE: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_get_interface, 1); ret = nl80211_get_interface(cmdbuf, rdev, wdev); } break; case NL80211_CMD_GET_STATION: { ret = nl80211_get_station(cmdbuf, rdev, netdev); } break; case NL80211_CMD_GET_SCAN: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_get_scan, 1); umac_wait_for_get_scan = 0; ret = nl80211_dump_scan(cmdbuf, rdev, wdev); } break; case NL80211_CMD_DEAUTHENTICATE: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_deauth, 1); ret = nl80211_deauthenticate(cmdbuf, rdev, netdev); } break; case NL80211_CMD_DISASSOCIATE: { ret = nl80211_disassociate(cmdbuf, rdev, netdev); } break; case NL80211_CMD_GET_KEY: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_get_key, 1); ret = nl80211_get_key(cmdbuf, rdev, netdev); } break; case NL80211_CMD_START_AP: { IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_start_ap, 1); ret = nl80211_start_ap(cmdbuf, rdev, netdev); } break; case NL80211_CMD_SET_BEACON: { ret = nl80211_set_beacon(cmdbuf, rdev, netdev); } break; case NL80211_CMD_SET_BSS: { struct nrf_wifi_umac_cmd_set_wiphy *cmd_set_wiphy; cmd_set_wiphy = (struct nrf_wifi_umac_cmd_set_wiphy *)cmdbuf; IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_set_bss, 1); ret = nl80211_set_bss(cmdbuf, rdev, netdev); if(ret < 0) { printk("wlan_umac_command_proc: NL80211_CMD_SET_BSS ret = %d\n", ret); } cmd_set_wiphy->umac_hdr.cmd_evnt = NRF_WIFI_UMAC_CMD_SET_WIPHY; cmd_set_wiphy->umac_hdr.ids.wdev_id = wdev->identifier; cmd_set_wiphy->umac_hdr.ids.valid_fields |= NRF_WIFI_INDEX_IDS_WDEV_ID_VALID; cmd_set_wiphy->valid_fields = NRF_WIFI_CMD_SET_WIPHY_TXQ_PARAMS_VALID; //after sending START_AP command. /*Best Effort*/ cmd_set_wiphy->info.txq_params.ac= 0; cmd_set_wiphy->info.txq_params.txop = 0; cmd_set_wiphy->info.txq_params.cwmin = 15; cmd_set_wiphy->info.txq_params.cwmax = 1023; cmd_set_wiphy->info.txq_params.aifs = 3; ret = nl80211_set_wiphy(cmdbuf, rdev, netdev); if(ret < 0) { printk("wlan_umac_command_proc: NRF_WIFI_UMAC_CMD_SET_WIPHY ret = %d\n", ret); } /*Back Ground*/ cmd_set_wiphy->info.txq_params.ac= 1; cmd_set_wiphy->info.txq_params.txop = 0; cmd_set_wiphy->info.txq_params.cwmin = 15; cmd_set_wiphy->info.txq_params.cwmax = 1023; cmd_set_wiphy->info.txq_params.aifs = 7; ret = nl80211_set_wiphy(cmdbuf, rdev, netdev); if(ret < 0) { printk("wlan_umac_command_proc: NRF_WIFI_UMAC_CMD_SET_WIPHY ret = %d\n", ret); } /*Video*/ cmd_set_wiphy->info.txq_params.ac= 2; cmd_set_wiphy->info.txq_params.txop = 94; cmd_set_wiphy->info.txq_params.cwmin = 7; cmd_set_wiphy->info.txq_params.cwmax = 15; cmd_set_wiphy->info.txq_params.aifs = 2; ret = nl80211_set_wiphy(cmdbuf, rdev, netdev); if(ret < 0) { printk("wlan_umac_command_proc: NRF_WIFI_UMAC_CMD_SET_WIPHY ret = %d\n", ret); } /*Voice*/ cmd_set_wiphy->info.txq_params.ac= 3; cmd_set_wiphy->info.txq_params.txop = 47; cmd_set_wiphy->info.txq_params.cwmin = 3; cmd_set_wiphy->info.txq_params.cwmax = 7; cmd_set_wiphy->info.txq_params.aifs = 2; ret = nl80211_set_wiphy(cmdbuf, rdev, netdev); if(ret < 0) { printk("wlan_umac_command_proc: NRF_WIFI_UMAC_CMD_SET_WIPHY ret = %d\n", ret); } } break; case NL80211_CMD_STOP_AP: { ret = img_nl80211_stop_ap(rdev, netdev); } break; case NL80211_CMD_GET_WIPHY: { img_nl80211_stop_ap(rdev, netdev); ret = nl80211_get_wiphy(cmdbuf, rdev); } break; case NL80211_CMD_START_P2P_DEVICE: { ret = nl80211_start_p2p_device(cmdbuf, rdev, wdev); } break; case NL80211_CMD_STOP_P2P_DEVICE: { ret = nl80211_stop_p2p_device(cmdbuf, rdev, wdev); } break; case NL80211_CMD_REMAIN_ON_CHANNEL: { ret = nl80211_remain_on_channel(cmdbuf, rdev, wdev); } break; case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: { ret = nl80211_cancel_remain_on_channel(cmdbuf, rdev, wdev); } break; case NL80211_CMD_SET_POWER_SAVE: { ret = img_nl80211_set_power_save(cmdbuf, rdev, netdev); } break; case NL80211_CMD_SET_QOS_MAP: { ret = nl80211_set_qos_map(cmdbuf, rdev, netdev); } break; case IMG_CMD_GET_CHANNEL: { ret = umac_proc_cmd_get_channel(cmdbuf, rdev, wdev); } break; case IMG_CMD_GET_TX_POWER: { ret = umac_proc_cmd_get_tx_power(cmdbuf, rdev, wdev); } break; #ifdef WIN_MLME case IMG_CMD_WIN_STA_CONNECT: { ret = umac_proc_cmd_win_sta_connect(cmdbuf); } break; #endif case IMG_CMD_CONFIG_TWT: { ret = img_umac_proc_cmd_config_twt_req(cmdbuf,wdev); } break; case IMG_CMD_TEARDOWN_TWT: { ret = img_umac_proc_cmd_twt_teardown(cmdbuf,wdev); } break; case IMG_CMD_CONFIG_UAPSD: { ret = umac_proc_config_uapsd(cmdbuf,netdev); } break; case NL80211_CMD_ABORT_SCAN: { ret = nl80211_abort_scan(rdev, wdev); } break; case IMG_CMD_MCAST_FILTER: { ret = umac_prepare_mcast_filter(cmdbuf, rdev, wdev); } break; default: { UMAC_OUTMSG("%s:%d: unhandled command_type: %d\n", __FUNCTION__, __LINE__, command_type); printk("%s:%d: unhandled command_type: %d\n", __FUNCTION__, __LINE__, command_type); } break; } cmd_hdr->rpu_ret_val = ret; ret = send_cmd_status_event_to_host(cmd_hdr->cmd_evnt, ret); return 0; } /* End of wlan_umac_cmd_proc() */ int img_sys_proc_host_msg(void *msg); char cmd_processing; void umac_task() { struct mbox_message *mbox_msg; void *msg = NULL; void *msg1 = NULL; unsigned int len; int ret; enum img_module_iface_port_id port_id; for(;;) { mbox_msg = KRN_getMbox(&umacCmdMbox, INFWAIT); if(mbox_msg == NULL) { continue; } update_jiffie(); msg = mbox_msg->msg; len = mbox_msg->msg_len; port_id = mbox_msg->port_id; cmd_processing = true; switch(port_id) { case IMG_MODULE_IFACE_WPAS_UMAC_PORT: { struct host_rpu_msg *host_rpu_msg = (struct host_rpu_msg *)msg; if(host_rpu_msg->type == NRF_WIFI_HOST_RPU_MSG_TYPE_DATA) { img_data_proc_host_msg(msg); } else if(host_rpu_msg->type == NRF_WIFI_HOST_RPU_MSG_TYPE_UMAC) { wlan_umac_command_proc((void *)host_rpu_msg->msg); umac_hal_resubmit_cmd_buff(msg); } else if(host_rpu_msg->type == NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM) { img_sys_proc_host_msg(msg); } } break; case IMG_MODULE_IFACE_WORK_QUEUE_PORT: { IMG_RX_DBG_PARAM_INCR(work_mbox_rcv, 1); struct work_struct *work; work = (struct work_struct *)msg; work->func(work); } break; case IMG_MODULE_IFACE_TIMER_PORT: { IMG_RX_DBG_PARAM_INCR(timer_mbox_rcv, 1); timer_list_t *timer = (timer_list_t *)msg; timer->timer_pending = 0; timer->function((struct timer_list *)timer->data); } break; case IMG_MODULE_IFACE_TASKLET_PORT: { IMG_RX_DBG_PARAM_INCR(tasklet_mbox_rcv, 1); struct tasklet_struct *tasklet = (struct tasklet_struct *)msg; tasklet->func(tasklet->data); } break; case IMG_MODULE_IFACE_TXDONE_PORT: /*tx done handling in tx thread*/ { rpu_msg_handler((void *)msg); free(msg); } break; default: { UMAC_OUTMSG("ERROR: message rcvd from unexpected port %d\n", port_id); } } free(mbox_msg); mbox_msg = NULL; cmd_processing = false; } } int check_mac80211_activity() { struct wireless_dev *wdev = NULL; struct net_device *netdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local; struct ieee80211_if_managed *ifmgd; int ifindex_valid, wdevid_valid; struct sta_info *sta; u64 wdev_id = 0; struct tid_ampdu_rx *tid_agg_rx; int i,j; list_for_each_entry(wdev, &cfg80211_rdev->wiphy.wdev_list, list) { netdev = wdev->netdev; sdata = IEEE80211_DEV_TO_SUB_IF(netdev); local = sdata->local; ifmgd = &sdata->u.mgd; if(sdata->vif.type != NL80211_IFTYPE_STATION) { IMG_SLEEP_DBG_PARAM_INCR(not_station, 1); return 1; } if(local->scan_req) { return 1; } if(ifmgd->auth_data) { IMG_SLEEP_DBG_PARAM_INCR(authenticating, 1); return 1; } if(ifmgd->assoc_data) { IMG_SLEEP_DBG_PARAM_INCR(associating, 1); return 1; } list_for_each_entry_rcu(sta, &local->sta_list, list) { for(i=0;iampdu_mlme.tid_rx[i]); if (!tid_agg_rx) continue; for(j=0; j < tid_agg_rx->buf_size; j++) { if(!skb_queue_empty(&tid_agg_rx->reorder_buf[j])) { IMG_SLEEP_DBG_PARAM_INCR(reorder_not_empty, 1); return 1; } } } } } return 0; } extern void umac_rx_task(void); int hal_hpqm_check_rpu_sleep(void); int check_umac_activity(void) { int ret; if(check_mac80211_activity()) { return 1; } if(img_cmd_event_dbg_params.cmd_set_ifflags != img_cmd_event_dbg_params.cmd_set_ifflags_done) { IMG_SLEEP_DBG_PARAM_INCR(pre_init, 1); return 1; } if(umac_wait_for_get_scan) /*wait for host to get scan results after scan done, as display scan results are stored in core memory*/ { IMG_SLEEP_DBG_PARAM_INCR(get_scan, 1); return 1; } if(rxMbox.items.first) { IMG_SLEEP_DBG_PARAM_INCR(rx_mbox_pending, 1); return 1; } if(umacCmdMbox.items.first) { IMG_SLEEP_DBG_PARAM_INCR(tx_mbox_pending, 1); return 1; } if(IMG_RX_DBG_PARAM_VAL(current_refill_gap)) { IMG_SLEEP_DBG_PARAM_INCR(rx_pending, 1); return 1; } if(cmd_processing) { IMG_SLEEP_DBG_PARAM_INCR(cmd_processing, 1); return 1; } if(IMG_TX_DBG_PARAM_VAL(tx_cmds_currently_in_use)) { IMG_SLEEP_DBG_PARAM_INCR(tx_cmds_currently_in_use, 1); return 1; } if(IMG_TX_DBG_PARAM_VAL(tx_cmds_to_lmac) != IMG_TX_DBG_PARAM_VAL(tx_dones_from_lmac)) { IMG_SLEEP_DBG_PARAM_INCR(tx_done_pending, 1); return 1; } ret = hal_hpqm_check_rpu_sleep(); if(ret) { return 1; } return 0; } #ifdef ENABLE_OTP void umac_read_otp_params() { unsigned char start_index, end_index; unsigned int *param = (unsigned int *)&otp_params; unsigned char i = 0; unsigned int control_info[4]; while((UCC_READ32(0xA401B804) & 0x4) != 4); UCC_WRITE32(0xA401B800, 0x1); while((UCC_READ32(0xA401B804) & 0x4) != 4); for(i=0;i<4;i++){ UCC_WRITE32(0xA401B810,i); while((UCC_READ32(0xA401B804) & 0x2) != 2); control_info[i] = UCC_READ32(0xA401B814); } if((control_info[0] == 0xFFFFFFFF) && (control_info[1] == 0xFFFFFFFF) && (control_info[2] == 0xFFFFFFFF) && (control_info[3] == 0xFFFFFFFF)){ for(i=0; i<15;i++){ otp_params.prodtest_trim[i] = 0x3FFF00; } memset(&otp_params.info_part, 0xFF, 92); return; } i=0; /*First set of params*/ end_index = 58; for(start_index = 32; start_index < end_index; start_index++){ UCC_WRITE32(0xA401B810,start_index); while((UCC_READ32(0xA401B804) & 0x2) != 2); param[i] = UCC_READ32(0xA401B814); i++; } /*Second set of params*/ end_index = 85; for(start_index = 72; start_index < end_index; start_index++){ UCC_WRITE32(0xA401B810, start_index); while((UCC_READ32(0xA401B804) & 0x2) != 2); param[i] = UCC_READ32(0xA401B814); i++; } } #endif void wlan_init_umac_task() { KRN_initMbox(&umacCmdMbox); KRN_initMbox(&rxMbox); KRN_startTask(umac_rx_task, &umac_rx_task_g, umac_rx_stack, umac_rx_stack_size, UMAC_RX_TASK_PRIORITY, NULL, UMAC_RX_TASK_NAME); } int regulatory_init(void); void umac_modules_init() { IF_UMAC_COLD_BOOT ieee80211_init(); regulatory_init(); ENDIF_UMAC_COLD_BOOT hal_module_init(); } void umac_init_reg_lists(void); struct ieee80211_local *get_local_ptr(void); void chg_irq_register(void); void umac_init() { struct ieee80211_local *local; IMG_SLEEP_DBG_PARAM_INCR(umac_init, 1); osal_init(); img_crypto_init(); wlan_init_umac_task(); IF_UMAC_COLD_BOOT IMG_SLEEP_DBG_PARAM_INCR(umac_init_coldboot, 1); sleep_dbg.max_twt_awake_cnt = 10000; #ifdef ENABLE_OTP umac_read_otp_params(); #endif ENDIF_UMAC_COLD_BOOT IF_UMAC_WARM_BOOT IMG_SLEEP_DBG_PARAM_INCR(umac_init_warmboot, 1); umac_modules_init(); #ifdef BSS_OPTIMIZATION if(cfg80211_rdev){ INIT_LIST_HEAD(&cfg80211_rdev->display_bss_list); } #endif /* BSS_DTATBASE2_TEST */ umac_init_reg_lists(); { unsigned int value = 0; value = UCC_READ32(ABS_SYS_UCCP_CORE_INT_ENAB); value |= (1 << SYS_UCCP_CORE_MTX2_INT_IRQ_ENAB_SHIFT); UCC_WRITE32(ABS_SYS_UCCP_CORE_INT_ENAB, value); value = 0; value |= (1 << SYS_UCCP_CORE_MTX2_INT_EN_SHIFT); UCC_WRITE32(ABS_SYS_UCCP_CORE_MTX2_INT_ENABLE, value); } chg_irq_register(); ENDIF_UMAC_WARM_BOOT }