// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #include #include #include #include "img_utils.h" #include "mac80211.h" int send_rx_buffs_to_host(void *event_buff, int size); void send_event_to_host(void *event_buff); int img_data_send_init_done() { int ret = 0; void *msg; struct host_rpu_msg *host_rpu_msg = NULL; struct nrf_wifi_event_init_done *event_init_done; int msg_len = sizeof(struct nrf_wifi_event_init_done); int total_event_buff_len; IPL_T oldipl; oldipl = raiseIPL(); msg = kzalloc(sizeof(struct nrf_wifi_event_init_done) + sizeof(struct host_rpu_msg), GFP_KERNEL); if (msg == NULL) { restoreIPL(oldipl); return -1; } host_rpu_msg = msg; host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg); host_rpu_msg->hdr.resubmit = true; event_init_done = (struct nrf_wifi_event_init_done *)host_rpu_msg->msg; host_rpu_msg->hdr.len += sizeof(struct nrf_wifi_event_init_done); event_init_done->sys_head.cmd_event = NRF_WIFI_EVENT_INIT_DONE; event_init_done->sys_head.len = sizeof(struct nrf_wifi_event_init_done); IMG_CMD_EVENT_DBG_PARAM_INCR(event_init_done, 1); send_rx_buffs_to_host(host_rpu_msg, host_rpu_msg->hdr.len); restoreIPL(oldipl); return ret; } int img_data_send_deinit_done() { int ret = 0; void *msg; struct host_rpu_msg *host_rpu_msg; struct nrf_wifi_event_deinit_done *event_deinit_done; int msg_len = sizeof(struct nrf_wifi_event_deinit_done); int total_event_buff_len; IPL_T oldipl; oldipl = raiseIPL(); msg = kzalloc(sizeof(struct nrf_wifi_event_deinit_done) + sizeof(struct host_rpu_msg), GFP_KERNEL); if (msg == NULL) { restoreIPL(oldipl); return -1; } host_rpu_msg = msg; host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg); host_rpu_msg->hdr.resubmit = true; event_deinit_done = (struct nrf_wifi_event_deinit_done *)host_rpu_msg->msg; host_rpu_msg->hdr.len += sizeof(struct nrf_wifi_event_deinit_done); event_deinit_done->sys_head.cmd_event = NRF_WIFI_EVENT_DEINIT_DONE; event_deinit_done->sys_head.len = sizeof(struct nrf_wifi_event_deinit_done); send_rx_buffs_to_host(host_rpu_msg, host_rpu_msg->hdr.len); restoreIPL(oldipl); return ret; } int img_data_send_tx_buff_done(unsigned char *event_ptr, int tx_desc_num, unsigned int num_tx_pkts, unsigned char *tx_status_code, unsigned char *timestamp_t1, unsigned char *timestamp_t4) { int ret = 0; struct host_rpu_msg *host_rpu_msg = (struct host_rpu_msg *)event_ptr; struct nrf_wifi_tx_buff_done *tx_buff_done; int index; IPL_T oldipl; memset(event_ptr, 0, RPU_DATA_CMD_SIZE_MAX_TX); oldipl = KRN_raiseIPL(); host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_DATA; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg); host_rpu_msg->hdr.resubmit = false; tx_buff_done = (struct nrf_wifi_tx_buff_done *)host_rpu_msg->msg; host_rpu_msg->hdr.len += sizeof(struct nrf_wifi_tx_buff_done); tx_buff_done->umac_head.cmd = NRF_WIFI_CMD_TX_BUFF_DONE; tx_buff_done->umac_head.len = sizeof(struct nrf_wifi_tx_buff_done); tx_buff_done->tx_desc_num = tx_desc_num; for(index = 0; index < num_tx_pkts; index ++) { tx_buff_done->tx_status_code[index] = ((tx_status_code[index] == 0) ? NRF_WIFI_TX_STATUS_SUCCESS : NRF_WIFI_TX_STATUS_FAILED); } tx_buff_done->num_tx_status_code = num_tx_pkts; memcpy(tx_buff_done->timestamp_t1, timestamp_t1, 6); memcpy(tx_buff_done->timestamp_t4, timestamp_t4, 6); send_event_to_host(host_rpu_msg); KRN_restoreIPL(oldipl); return ret; } void img_data_fill_rx_event(struct sk_buff *skb, struct nrf_wifi_rx_buff *rx_buff, int info_type, unsigned char l3_l4_chesum_status, int rx_pkt_consumed, unsigned char trim_len) { int i; struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct nrf_wifi_rx_buff_info *rx_info = rx_buff->rx_buff_info; if (info_type == RX_MULTI_PKT_INFO) { struct primary_pkt_info *primary_pkt_info = (struct primary_pkt_info *)skb->pkt_info; for (i = 0; i < primary_pkt_info->rx_evnt->rx_pkt_cnt; i++) { if (primary_pkt_info->rx_evnt->mpdu_ctrl[i].skb_pointer == 0) { continue; } IMG_RX_DBG_PARAM_INCR(host_consumed_pkts, 1); IMG_RX_DBG_PARAM_DECR(current_refill_gap, 1); rx_info[rx_buff->rx_pkt_cnt].descriptor_id = primary_pkt_info->rx_evnt->mpdu_ctrl[i].skb_desc_no; rx_info[rx_buff->rx_pkt_cnt].rx_pkt_len = primary_pkt_info->rx_evnt->mpdu_ctrl[i].rx_pkt_len - trim_len; rx_info[rx_buff->rx_pkt_cnt].pkt_type = primary_pkt_info->rx_evnt->mpdu_ctrl[i].pkt_type; rx_buff->frequency = rx_status->freq; rx_buff->signal = rx_status->signal * 100; rx_buff->rx_pkt_cnt ++; } } else if (info_type == RX_SINGLE_PKT_INFO) { struct secondary_pkt_info *secondary_pkt_info; secondary_pkt_info = (struct secondary_pkt_info *)skb->pkt_info; IMG_RX_DBG_PARAM_INCR(host_consumed_pkts, 1); IMG_RX_DBG_PARAM_DECR(current_refill_gap, 1); rx_info[rx_buff->rx_pkt_cnt].descriptor_id = secondary_pkt_info->descriptor_id; rx_info[rx_buff->rx_pkt_cnt].rx_pkt_len = secondary_pkt_info->pkt_len - trim_len; rx_info[rx_buff->rx_pkt_cnt].pkt_type = secondary_pkt_info->pkt_type; rx_buff->frequency = rx_status->freq; rx_buff->signal = rx_status->signal * 100; rx_buff->rx_pkt_cnt ++; } else if (info_type == AMSDU_PKT_INFO) { struct amsdu_pkt_info *amsdu_info = (struct amsdu_pkt_info *)skb->pkt_info; for (i = 0; i < amsdu_info->pkt_cnt; i++) { IMG_RX_DBG_PARAM_INCR(host_consumed_pkts, 1); IMG_RX_DBG_PARAM_DECR(current_refill_gap, 1); rx_info[rx_buff->rx_pkt_cnt].descriptor_id = amsdu_info->mpdu_ctrl[i].skb_desc_no; rx_info[rx_buff->rx_pkt_cnt].rx_pkt_len = amsdu_info->mpdu_ctrl[i].rx_pkt_len; rx_info[rx_buff->rx_pkt_cnt].pkt_type = amsdu_info->mpdu_ctrl[i].pkt_type; rx_buff->frequency = rx_status->freq; rx_buff->signal = rx_status->signal * 100; rx_buff->rx_pkt_cnt ++; } } } int img_data_send_rx_buff(struct sk_buff *skb, unsigned char l3_l4_chesum_status, int rx_pkt_consumed) { int ret = 0; void *msg; struct host_rpu_msg *host_rpu_msg; struct nrf_wifi_rx_buff *rx_buff; int rx_event_len; int total_event_buff_len; enum pkt_type info_type; enum pkt_type released_skb_info_type; int i; struct primary_pkt_info *primary_pkt_info = NULL; struct secondary_pkt_info *secondary_pkt_info; struct amsdu_pkt_info *amsdu_info; struct sk_buff_head *released_frames; struct sk_buff *released_skb; int hdrlen; int no_pkts; IPL_T oldipl; info_type = *((enum pkt_type *)(skb->pkt_info)); if (info_type == RX_MULTI_PKT_INFO) { primary_pkt_info = (struct primary_pkt_info *)skb->pkt_info; released_frames = &primary_pkt_info->released_frames; hdrlen = primary_pkt_info->rx_evnt->mpduOvrHead; no_pkts = primary_pkt_info->rx_evnt->rx_pkt_cnt; } else if (info_type == RX_SINGLE_PKT_INFO) { secondary_pkt_info = (struct secondary_pkt_info *)skb->pkt_info; released_frames = &secondary_pkt_info->released_frames; hdrlen = secondary_pkt_info->hdr_len; no_pkts = 1; } else { amsdu_info = (struct amsdu_pkt_info *)skb->pkt_info; released_frames = &amsdu_info->released_frames; hdrlen = amsdu_info->hdr_len; no_pkts = 1; } rx_event_len = sizeof(struct nrf_wifi_rx_buff) + ((no_pkts + released_frames->qlen) * sizeof(struct nrf_wifi_rx_buff_info)); oldipl = KRN_raiseIPL(); msg = kzalloc(sizeof(struct host_rpu_msg) + rx_event_len, GFP_KERNEL); if(msg == NULL) { KRN_restoreIPL(oldipl); return -1; } host_rpu_msg = msg; host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_DATA; rx_buff = (struct nrf_wifi_rx_buff *)host_rpu_msg->msg; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg) + rx_event_len; host_rpu_msg->hdr.resubmit = true; rx_buff->umac_head.cmd = NRF_WIFI_CMD_RX_BUFF; rx_buff->umac_head.len = rx_event_len; rx_buff->rx_pkt_type = rx_pkt_consumed; rx_buff->rx_pkt_cnt = 0; if(rx_pkt_consumed == NRF_WIFI_RX_PKT_DATA) rx_buff->wdev_id = skb->dev->ieee80211_ptr->identifier; rx_buff->mac_header_len = hdrlen; img_data_fill_rx_event(skb, rx_buff, info_type, l3_l4_chesum_status, rx_pkt_consumed, skb->trim_len); while((released_skb = __skb_dequeue(released_frames))) { released_skb_info_type = *((enum pkt_type *)(released_skb->pkt_info)); img_data_fill_rx_event(released_skb, rx_buff, released_skb_info_type, l3_l4_chesum_status, rx_pkt_consumed, skb->trim_len); if(released_skb_info_type == RX_MULTI_PKT_INFO) { struct primary_pkt_info *released_skb_primary_pkt_info = (struct primary_pkt_info *)released_skb->pkt_info; kfree(released_skb_primary_pkt_info->rx_evnt); } img_data_reset_skb_data_info(released_skb); released_skb->destructor = NULL; kfree_skb(released_skb); } if(info_type == RX_MULTI_PKT_INFO) { kfree(primary_pkt_info->rx_evnt); } send_rx_buffs_to_host(host_rpu_msg, host_rpu_msg->hdr.len); KRN_restoreIPL(oldipl); return ret; } int img_data_send_carrier_state(int carrier_on, int wdev_id) { int ret = 0; void *msg; struct host_rpu_msg *host_rpu_msg; struct nrf_wifi_data_carrier_state *carrier_state = NULL; int msg_len = sizeof(struct nrf_wifi_data_carrier_state); int total_event_buff_len; IPL_T oldipl; oldipl = raiseIPL(); msg = kzalloc(sizeof(struct nrf_wifi_data_carrier_state) + sizeof(struct host_rpu_msg), GFP_KERNEL); if (msg == NULL) { return -1; } host_rpu_msg = msg; host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_DATA; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg); host_rpu_msg->hdr.resubmit = true; carrier_state = (struct nrf_wifi_data_carrier_state *)host_rpu_msg->msg; carrier_state->umac_head.len = sizeof(struct nrf_wifi_data_carrier_state); carrier_state->wdev_id = wdev_id; host_rpu_msg->hdr.len += sizeof(struct nrf_wifi_data_carrier_state); if (carrier_on == 0) { carrier_state->umac_head.cmd = NRF_WIFI_CMD_CARRIER_OFF; } else { carrier_state->umac_head.cmd = NRF_WIFI_CMD_CARRIER_ON; } send_rx_buffs_to_host(host_rpu_msg, host_rpu_msg->hdr.len); restoreIPL(oldipl); return ret; } int img_send_sta_ps_state(unsigned char ps_state, int wdev_id, unsigned char *mac_addr) { int ret = 0; void *msg; struct host_rpu_msg *host_rpu_msg; struct nrf_wifi_sap_client_pwrsave *cl_ps_state; int msg_len = sizeof(struct nrf_wifi_sap_client_pwrsave); IPL_T oldipl; oldipl = raiseIPL(); msg = kzalloc(sizeof(struct nrf_wifi_sap_client_pwrsave) + sizeof(struct host_rpu_msg), GFP_KERNEL); if (msg == NULL) { return -1; } host_rpu_msg = msg; host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_DATA; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg); host_rpu_msg->hdr.resubmit = true; cl_ps_state = (struct nrf_wifi_sap_client_pwrsave *)host_rpu_msg->msg; cl_ps_state->umac_head.len = sizeof(struct nrf_wifi_sap_client_pwrsave); cl_ps_state->wdev_id = wdev_id; cl_ps_state->sta_ps_state = ps_state; memcpy(cl_ps_state->mac_addr, mac_addr, ETH_ALEN); host_rpu_msg->hdr.len += sizeof(struct nrf_wifi_sap_client_pwrsave); cl_ps_state->umac_head.cmd = NRF_WIFI_CMD_PM_MODE; IMG_CMD_EVENT_DBG_PARAM_INCR(event_ps_state, 1); send_rx_buffs_to_host(host_rpu_msg, host_rpu_msg->hdr.len); restoreIPL(oldipl); return ret; } int img_send_sta_ps_get_frames(int wdev_id, unsigned char *mac_addr, char num_frames) { int ret = 0; void *msg; struct host_rpu_msg *host_rpu_msg; struct nrf_wifi_sap_ps_get_frames *get_frames; int msg_len = sizeof(struct nrf_wifi_sap_ps_get_frames); IPL_T oldipl; oldipl = raiseIPL(); msg = kzalloc(sizeof(struct nrf_wifi_sap_ps_get_frames) + sizeof(struct host_rpu_msg), GFP_KERNEL); if (msg == NULL) { return -1; } host_rpu_msg = msg; host_rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_DATA; host_rpu_msg->hdr.len = sizeof(struct host_rpu_msg); host_rpu_msg->hdr.resubmit = true; get_frames = (struct nrf_wifi_sap_ps_get_frames *)host_rpu_msg->msg; get_frames->umac_head.len = sizeof(struct nrf_wifi_sap_ps_get_frames); get_frames->wdev_id = wdev_id; memcpy(get_frames->mac_addr, mac_addr, ETH_ALEN); host_rpu_msg->hdr.len += sizeof(struct nrf_wifi_sap_ps_get_frames); get_frames->umac_head.cmd = NRF_WIFI_CMD_PS_GET_FRAMES; get_frames->num_frames = num_frames; send_rx_buffs_to_host(host_rpu_msg, host_rpu_msg->hdr.len); restoreIPL(oldipl); return ret; }