2 ******************************************************************************
6 * @brief TX function definitions
8 * Copyright (C) ESWIN 2015-2020
10 ******************************************************************************
13 #include "ecrnx_msg_tx.h"
14 #include "ecrnx_mod_params.h"
15 #include "reg_access.h"
16 #ifdef CONFIG_ECRNX_BFMER
17 #include "ecrnx_bfmer.h"
18 #endif //(CONFIG_ECRNX_BFMER)
19 #include "ecrnx_compat.h"
20 #include "ecrnx_defs.h"
21 #include "ecrnx_calibration_data.h"
22 #include "eswin_utils.h"
25 const struct mac_addr mac_addr_bcst = {{0xFFFF, 0xFFFF, 0xFFFF}};
27 /* Default MAC Rx filters that can be changed by mac80211
28 * (via the configure_filter() callback) */
29 #define ECRNX_MAC80211_CHANGEABLE ( \
30 NXMAC_ACCEPT_BA_BIT | \
31 NXMAC_ACCEPT_BAR_BIT | \
32 NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT | \
33 NXMAC_ACCEPT_PROBE_REQ_BIT | \
34 NXMAC_ACCEPT_PS_POLL_BIT \
37 /* Default MAC Rx filters that cannot be changed by mac80211 */
38 #define ECRNX_MAC80211_NOT_CHANGEABLE ( \
39 NXMAC_ACCEPT_QO_S_NULL_BIT | \
40 NXMAC_ACCEPT_Q_DATA_BIT | \
41 NXMAC_ACCEPT_DATA_BIT | \
42 NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT | \
43 NXMAC_ACCEPT_MY_UNICAST_BIT | \
44 NXMAC_ACCEPT_BROADCAST_BIT | \
45 NXMAC_ACCEPT_BEACON_BIT | \
46 NXMAC_ACCEPT_PROBE_RESP_BIT \
49 /* Default MAC Rx filter */
50 #define ECRNX_DEFAULT_RX_FILTER (ECRNX_MAC80211_CHANGEABLE | ECRNX_MAC80211_NOT_CHANGEABLE)
52 const int bw2chnl[] = {
53 [NL80211_CHAN_WIDTH_20_NOHT] = PHY_CHNL_BW_20,
54 [NL80211_CHAN_WIDTH_20] = PHY_CHNL_BW_20,
55 [NL80211_CHAN_WIDTH_40] = PHY_CHNL_BW_40,
56 [NL80211_CHAN_WIDTH_80] = PHY_CHNL_BW_80,
57 [NL80211_CHAN_WIDTH_160] = PHY_CHNL_BW_160,
58 [NL80211_CHAN_WIDTH_80P80] = PHY_CHNL_BW_80P80,
61 const int chnl2bw[] = {
62 [PHY_CHNL_BW_20] = NL80211_CHAN_WIDTH_20,
63 [PHY_CHNL_BW_40] = NL80211_CHAN_WIDTH_40,
64 [PHY_CHNL_BW_80] = NL80211_CHAN_WIDTH_80,
65 [PHY_CHNL_BW_160] = NL80211_CHAN_WIDTH_160,
66 [PHY_CHNL_BW_80P80] = NL80211_CHAN_WIDTH_80P80,
69 /*****************************************************************************/
71 * Parse the ampdu density to retrieve the value in usec, according to the
72 * values defined in ieee80211.h
74 static inline u8 ecrnx_ampdudensity2usec(u8 ampdudensity)
76 switch (ampdudensity) {
77 case IEEE80211_HT_MPDU_DENSITY_NONE:
79 /* 1 microsecond is our granularity */
80 case IEEE80211_HT_MPDU_DENSITY_0_25:
81 case IEEE80211_HT_MPDU_DENSITY_0_5:
82 case IEEE80211_HT_MPDU_DENSITY_1:
84 case IEEE80211_HT_MPDU_DENSITY_2:
86 case IEEE80211_HT_MPDU_DENSITY_4:
88 case IEEE80211_HT_MPDU_DENSITY_8:
90 case IEEE80211_HT_MPDU_DENSITY_16:
97 static inline bool use_pairwise_key(struct cfg80211_crypto_settings *crypto)
99 if ((crypto->cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
100 (crypto->cipher_group == WLAN_CIPHER_SUITE_WEP104))
106 static inline bool is_non_blocking_msg(int id)
108 return ((id == MM_TIM_UPDATE_REQ) || (id == ME_RC_SET_RATE_REQ) ||
109 (id == MM_BFMER_ENABLE_REQ) || (id == ME_TRAFFIC_IND_REQ) ||
110 (id == TDLS_PEER_TRAFFIC_IND_REQ) ||
111 (id == MESH_PATH_CREATE_REQ) || (id == MESH_PROXY_ADD_REQ) ||
112 (id == SM_EXTERNAL_AUTH_REQUIRED_RSP));
115 #ifdef CONFIG_ECRNX_FULLMAC
117 * copy_connect_ies -- Copy Association Elements in the the request buffer
118 * send to the firmware
120 * @vif: Vif that received the connection request
121 * @req: Connection request to send to the firmware
122 * @sme: Connection info
124 * For driver that do not use userspace SME (like this one) the host connection
125 * request doesn't explicitly mentions that the connection can use FT over the
126 * air. if FT is possible, send the FT elements (as received in update_ft_ies callback)
129 * In all other cases simply copy the list povided by the user space in the
132 static void copy_connect_ies(struct ecrnx_vif *vif, struct sm_connect_req *req,
133 struct cfg80211_connect_params *sme)
135 if ((sme->auth_type == NL80211_AUTHTYPE_FT) && !(vif->sta.flags & ECRNX_STA_FT_OVER_DS))
137 const struct ecrnx_element *rsne, *fte, *mde;
139 rsne = cfg80211_find_ecrnx_elem(WLAN_EID_RSN, vif->sta.ft_assoc_ies,
140 vif->sta.ft_assoc_ies_len);
141 fte = cfg80211_find_ecrnx_elem(WLAN_EID_FAST_BSS_TRANSITION, vif->sta.ft_assoc_ies,
142 vif->sta.ft_assoc_ies_len);
143 mde = cfg80211_find_ecrnx_elem(WLAN_EID_MOBILITY_DOMAIN,
144 vif->sta.ft_assoc_ies, vif->sta.ft_assoc_ies_len);
145 pos = (uint8_t *)req->ie_buf;
147 // We can use FT over the air
148 memcpy(&vif->sta.ft_target_ap, sme->bssid, ETH_ALEN);
151 memcpy(pos, rsne, sizeof(struct ecrnx_element) + rsne->datalen);
152 pos += sizeof(struct ecrnx_element) + rsne->datalen;
154 memcpy(pos, mde, sizeof(struct ecrnx_element) + mde->datalen);
155 pos += sizeof(struct ecrnx_element) + mde->datalen;
157 memcpy(pos, fte, sizeof(struct ecrnx_element) + fte->datalen);
158 pos += sizeof(struct ecrnx_element) + fte->datalen;
161 req->ie_len = pos - (uint8_t *)req->ie_buf;
165 memcpy(req->ie_buf, sme->ie, sme->ie_len);
166 req->ie_len = sme->ie_len;
171 * update_connect_req -- Return the length of the association request IEs
173 * @vif: Vif that received the connection request
174 * @sme: Connection info
176 * Return the ft_ie_len in case of FT.
177 * FT over the air is possible if:
178 * - auth_type = AUTOMATIC (if already set to FT then it means FT over DS)
179 * - already associated to a FT BSS
180 * - Target Mobility domain is the same as the curent one
182 * If FT is not possible return ie length of the connection info
184 static int update_connect_req(struct ecrnx_vif *vif, struct cfg80211_connect_params *sme)
187 (vif->sta.ft_assoc_ies) &&
188 (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC))
190 const struct ecrnx_element *rsne, *fte, *mde, *mde_req;
193 mde_req = cfg80211_find_ecrnx_elem(WLAN_EID_MOBILITY_DOMAIN,
194 sme->ie, sme->ie_len);
195 mde = cfg80211_find_ecrnx_elem(WLAN_EID_MOBILITY_DOMAIN,
196 vif->sta.ft_assoc_ies, vif->sta.ft_assoc_ies_len);
197 if (!mde || !mde_req ||
198 memcmp(mde, mde_req, sizeof(struct ecrnx_element) + mde->datalen))
203 ft_ie_len += sizeof(struct ecrnx_element) + mde->datalen;
205 rsne = cfg80211_find_ecrnx_elem(WLAN_EID_RSN, vif->sta.ft_assoc_ies,
206 vif->sta.ft_assoc_ies_len);
207 fte = cfg80211_find_ecrnx_elem(WLAN_EID_FAST_BSS_TRANSITION, vif->sta.ft_assoc_ies,
208 vif->sta.ft_assoc_ies_len);
212 ft_ie_len += 2 * sizeof(struct ecrnx_element) + rsne->datalen + fte->datalen;
213 sme->auth_type = NL80211_AUTHTYPE_FT;
216 else if (rsne || fte)
218 netdev_warn(vif->ndev, "Missing RSNE or FTE element, skip FT over air");
222 sme->auth_type = NL80211_AUTHTYPE_FT;
229 static inline u8_l get_chan_flags(uint32_t flags)
232 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
233 if (flags & IEEE80211_CHAN_PASSIVE_SCAN)
235 if (flags & IEEE80211_CHAN_NO_IR)
236 chan_flags |= CHAN_NO_IR;
237 if (flags & IEEE80211_CHAN_RADAR)
238 chan_flags |= CHAN_RADAR;
243 static inline s8_l chan_to_fw_pwr(int power)
245 return power > 127 ? 127 : (s8_l)power;
248 static void cfg80211_to_ecrnx_chan(const struct cfg80211_chan_def *chandef,
249 struct mac_chan_op *chan)
251 chan->band = chandef->chan->band;
252 chan->type = bw2chnl[chandef->width];
253 chan->prim20_freq = chandef->chan->center_freq;
254 chan->center1_freq = chandef->center_freq1;
255 chan->center2_freq = chandef->center_freq2;
256 chan->flags = get_chan_flags(chandef->chan->flags);
257 chan->tx_power = chan_to_fw_pwr(chandef->chan->max_power);
260 static inline void limit_chan_bw(u8_l *bw, u16_l primary, u16_l *center1)
262 int oft, new_oft = 10;
264 if (*bw <= PHY_CHNL_BW_40)
267 oft = *center1 - primary;
268 *bw = PHY_CHNL_BW_40;
271 new_oft = new_oft * -1;
272 if (abs(oft) == 10 || abs(oft) == 50)
273 new_oft = new_oft * -1;
275 *center1 = primary + new_oft;
279 ******************************************************************************
280 * @brief Allocate memory for a message
282 * This primitive allocates memory for a message that has to be sent. The memory
283 * is allocated dynamically on the heap and the length of the variable parameter
284 * structure has to be provided in order to allocate the correct size.
286 * Several additional parameters are provided which will be preset in the message
287 * and which may be used internally to choose the kind of memory to allocate.
289 * The memory allocated will be automatically freed by the kernel, after the
290 * pointer has been sent to ke_msg_send(). If the message is not sent, it must
291 * be freed explicitly with ke_msg_free().
293 * Allocation failure is considered critical and should not happen.
295 * @param[in] id Message identifier
296 * @param[in] dest_id Destination Task Identifier
297 * @param[in] src_id Source Task Identifier
298 * @param[in] param_len Size of the message parameters to be allocated
300 * @return Pointer to the parameter member of the ke_msg. If the parameter
301 * structure is empty, the pointer will point to the end of the message
302 * and should not be used (except to retrieve the message pointer or to
304 ******************************************************************************
306 static inline void *ecrnx_msg_zalloc(lmac_msg_id_t const id,
307 lmac_task_id_t const dest_id,
308 lmac_task_id_t const src_id,
309 uint16_t const param_len)
311 struct lmac_msg *msg;
314 if (is_non_blocking_msg(id) && in_softirq())
319 msg = (struct lmac_msg *)kzalloc(sizeof(struct lmac_msg) + param_len,
322 ECRNX_ERR(KERN_CRIT "%s: msg allocation failed\n", __func__);
327 msg->dest_id = dest_id;
328 msg->src_id = src_id;
329 msg->param_len = param_len;
334 static void ecrnx_msg_free(struct ecrnx_hw *ecrnx_hw, const void *msg_params)
336 struct lmac_msg *msg = container_of((void *)msg_params,
337 struct lmac_msg, param);
339 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
341 /* Free the message */
345 static int ecrnx_send_msg(struct ecrnx_hw *ecrnx_hw, const void *msg_params,
346 int reqcfm, lmac_msg_id_t reqid, void *cfm)
348 struct lmac_msg *msg;
349 struct ecrnx_cmd *cmd;
353 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
355 msg = container_of((void *)msg_params, struct lmac_msg, param);
357 if (!test_bit(ECRNX_DEV_STARTED, &ecrnx_hw->flags) &&
358 reqid != MM_RESET_CFM && reqid != MM_VERSION_CFM &&
359 reqid != MM_START_CFM && reqid != MM_SET_IDLE_CFM &&
360 reqid != ME_CONFIG_CFM && reqid != MM_SET_PS_MODE_CFM &&
361 reqid != ME_CHAN_CONFIG_CFM && reqid != MM_SET_GAIN_DELTA_CFM &&
362 reqid != MM_GET_CAL_RESULT_CFM) {
363 ECRNX_ERR(KERN_CRIT "%s: bypassing (ECRNX_DEV_RESTARTING set) 0x%02x\n",
367 } else if (!ecrnx_hw->ipc_env) {
368 ECRNX_ERR(KERN_CRIT "%s: bypassing (restart must have failed)\n", __func__);
373 nonblock = is_non_blocking_msg(msg->id);
375 #if defined(CONFIG_ECRNX_ESWIN_USB)
376 if(register_status == false){
382 cmd = kzalloc(sizeof(struct ecrnx_cmd), nonblock ? GFP_ATOMIC : GFP_KERNEL);
383 cmd->result = -EINTR;
389 cmd->flags = ECRNX_CMD_FLAG_NONBLOCK;
391 cmd->flags |= ECRNX_CMD_FLAG_REQ_CFM;
392 if(ecrnx_hw->wiphy != NULL)
394 ret = ecrnx_hw->cmd_mgr.queue(&ecrnx_hw->cmd_mgr, cmd);
405 /******************************************************************************
406 * Control messages handling functions (SOFTMAC and FULLMAC)
407 *****************************************************************************/
408 int ecrnx_send_reset(struct ecrnx_hw *ecrnx_hw)
412 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
414 /* RESET REQ has no parameter */
415 void_param = ecrnx_msg_zalloc(MM_RESET_REQ, TASK_MM, DRV_TASK_ID, 0);
419 return ecrnx_send_msg(ecrnx_hw, void_param, 1, MM_RESET_CFM, NULL);
422 int ecrnx_send_start(struct ecrnx_hw *ecrnx_hw)
424 struct mm_start_req *start_req_param;
426 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
428 /* Build the START REQ message */
429 start_req_param = ecrnx_msg_zalloc(MM_START_REQ, TASK_MM, DRV_TASK_ID,
430 sizeof(struct mm_start_req));
431 if (!start_req_param)
434 /* Set parameters for the START message */
435 memcpy(&start_req_param->phy_cfg, &ecrnx_hw->phy.cfg, sizeof(ecrnx_hw->phy.cfg));
436 start_req_param->uapsd_timeout = (u32_l)ecrnx_hw->mod_params->uapsd_timeout;
437 start_req_param->lp_clk_accuracy = (u16_l)ecrnx_hw->mod_params->lp_clk_ppm;
438 start_req_param->tx_timeout[AC_BK] = (u16_l)ecrnx_hw->mod_params->tx_to_bk;
439 start_req_param->tx_timeout[AC_BE] = (u16_l)ecrnx_hw->mod_params->tx_to_be;
440 start_req_param->tx_timeout[AC_VI] = (u16_l)ecrnx_hw->mod_params->tx_to_vi;
441 start_req_param->tx_timeout[AC_VO] = (u16_l)ecrnx_hw->mod_params->tx_to_vo;
443 /* Send the START REQ message to LMAC FW */
444 return ecrnx_send_msg(ecrnx_hw, start_req_param, 1, MM_START_CFM, NULL);
447 int ecrnx_send_version_req(struct ecrnx_hw *ecrnx_hw, struct mm_version_cfm *cfm)
451 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
452 /* VERSION REQ has no parameter */
453 void_param = ecrnx_msg_zalloc(MM_VERSION_REQ, TASK_MM, DRV_TASK_ID, 0);
457 return ecrnx_send_msg(ecrnx_hw, void_param, 1, MM_VERSION_CFM, cfm);
460 int ecrnx_send_add_if(struct ecrnx_hw *ecrnx_hw, const unsigned char *mac,
461 enum nl80211_iftype iftype, bool p2p, struct mm_add_if_cfm *cfm)
463 struct mm_add_if_req *add_if_req_param;
465 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
467 /* Build the ADD_IF_REQ message */
468 add_if_req_param = ecrnx_msg_zalloc(MM_ADD_IF_REQ, TASK_MM, DRV_TASK_ID,
469 sizeof(struct mm_add_if_req));
470 if (!add_if_req_param)
473 /* Set parameters for the ADD_IF_REQ message */
474 memcpy(&(add_if_req_param->addr.array[0]), mac, ETH_ALEN);
476 #ifdef CONFIG_ECRNX_FULLMAC
477 case NL80211_IFTYPE_P2P_CLIENT:
478 add_if_req_param->p2p = true;
479 add_if_req_param->type = MM_STA;
481 #endif /* CONFIG_ECRNX_FULLMAC */
482 case NL80211_IFTYPE_STATION:
483 add_if_req_param->type = MM_STA;
486 case NL80211_IFTYPE_ADHOC:
487 add_if_req_param->type = MM_IBSS;
490 #ifdef CONFIG_ECRNX_FULLMAC
491 case NL80211_IFTYPE_P2P_GO:
492 add_if_req_param->p2p = true;
493 add_if_req_param->type = MM_AP;
495 #endif /* CONFIG_ECRNX_FULLMAC */
496 case NL80211_IFTYPE_AP:
497 add_if_req_param->type = MM_AP;
499 case NL80211_IFTYPE_MESH_POINT:
500 add_if_req_param->type = MM_MESH_POINT;
502 case NL80211_IFTYPE_AP_VLAN:
504 case NL80211_IFTYPE_MONITOR:
505 add_if_req_param->type = MM_MONITOR;
508 add_if_req_param->type = MM_STA;
512 #ifdef CONFIG_ECRNX_SOFTMAC
513 add_if_req_param->p2p = p2p;
514 #endif /* CONFIG_ECRNX_SOFTMAC */
516 /* Send the ADD_IF_REQ message to LMAC FW */
517 return ecrnx_send_msg(ecrnx_hw, add_if_req_param, 1, MM_ADD_IF_CFM, cfm);
520 int ecrnx_send_remove_if(struct ecrnx_hw *ecrnx_hw, u8 vif_index)
522 struct mm_remove_if_req *remove_if_req;
524 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
526 /* Build the MM_REMOVE_IF_REQ message */
527 remove_if_req = ecrnx_msg_zalloc(MM_REMOVE_IF_REQ, TASK_MM, DRV_TASK_ID,
528 sizeof(struct mm_remove_if_req));
532 /* Set parameters for the MM_REMOVE_IF_REQ message */
533 remove_if_req->inst_nbr = vif_index;
535 /* Send the MM_REMOVE_IF_REQ message to LMAC FW */
536 return ecrnx_send_msg(ecrnx_hw, remove_if_req, 1, MM_REMOVE_IF_CFM, NULL);
539 int ecrnx_send_set_channel(struct ecrnx_hw *ecrnx_hw, int phy_idx,
540 struct mm_set_channel_cfm *cfm)
542 #ifdef CONFIG_ECRNX_SOFTMAC
543 struct cfg80211_chan_def *chandef = &ecrnx_hw->hw->conf.chandef;
544 #endif /* CONFIG_ECRNX_SOFTMAC */
545 struct mm_set_channel_req *req;
547 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
549 if (phy_idx >= ecrnx_hw->phy.cnt)
552 req = ecrnx_msg_zalloc(MM_SET_CHANNEL_REQ, TASK_MM, DRV_TASK_ID,
553 sizeof(struct mm_set_channel_req));
558 #ifdef CONFIG_ECRNX_SOFTMAC
559 cfg80211_to_ecrnx_chan(chandef, &req->chan);
561 /* On FULLMAC only setting channel of secondary chain */
562 wiphy_err(ecrnx_hw->wiphy, "Trying to set channel of primary chain");
564 #endif /* CONFIG_ECRNX_SOFTMAC */
566 req->chan = ecrnx_hw->phy.sec_chan;
569 req->index = phy_idx;
571 if (ecrnx_hw->phy.limit_bw)
572 limit_chan_bw(&req->chan.type, req->chan.prim20_freq, &req->chan.center1_freq);
574 /*ECRNX_DBG("mac80211: freq=%d(c1:%d - c2:%d)/width=%d - band=%d\n"
575 " hw(%d): prim20=%d(c1:%d - c2:%d)/ type=%d - band=%d\n",
576 center_freq, center_freq1, center_freq2, width, band,
577 phy_idx, req->chan.prim20_freq, req->chan.center1_freq,
578 req->chan.center2_freq, req->chan.type, req->chan.band);*/
580 /* Send the MM_SET_CHANNEL_REQ REQ message to LMAC FW */
581 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_SET_CHANNEL_CFM, cfm);
585 int ecrnx_send_key_add(struct ecrnx_hw *ecrnx_hw, u8 vif_idx, u8 sta_idx, bool pairwise,
586 u8 *key, u8 key_len, u8 key_idx, u8 cipher_suite,
587 struct mm_key_add_cfm *cfm)
589 struct mm_key_add_req *key_add_req;
591 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
593 /* Build the MM_KEY_ADD_REQ message */
594 key_add_req = ecrnx_msg_zalloc(MM_KEY_ADD_REQ, TASK_MM, DRV_TASK_ID,
595 sizeof(struct mm_key_add_req));
599 /* Set parameters for the MM_KEY_ADD_REQ message */
600 if (sta_idx != 0xFF) {
602 key_add_req->sta_idx = sta_idx;
605 key_add_req->sta_idx = sta_idx;
606 key_add_req->key_idx = (u8_l)key_idx; /* only useful for default keys */
608 key_add_req->pairwise = pairwise;
609 key_add_req->inst_nbr = vif_idx;
610 key_add_req->key.length = key_len;
611 memcpy(&(key_add_req->key.array[0]), key, key_len);
613 key_add_req->cipher_suite = cipher_suite;
615 ECRNX_DBG("%s: sta_idx:%d key_idx:%d inst_nbr:%d cipher:%d key_len:%d\n", __func__,
616 key_add_req->sta_idx, key_add_req->key_idx, key_add_req->inst_nbr,
617 key_add_req->cipher_suite, key_add_req->key.length);
618 #if defined(CONFIG_ECRNX_DBG) || defined(CONFIG_DYNAMIC_DEBUG)
619 print_hex_dump_bytes("key: ", DUMP_PREFIX_OFFSET, key_add_req->key.array, key_add_req->key.length);
622 /* Send the MM_KEY_ADD_REQ message to LMAC FW */
623 return ecrnx_send_msg(ecrnx_hw, key_add_req, 1, MM_KEY_ADD_CFM, cfm);
626 int ecrnx_send_key_del(struct ecrnx_hw *ecrnx_hw, uint8_t hw_key_idx)
628 struct mm_key_del_req *key_del_req;
630 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
632 /* Build the MM_KEY_DEL_REQ message */
633 key_del_req = ecrnx_msg_zalloc(MM_KEY_DEL_REQ, TASK_MM, DRV_TASK_ID,
634 sizeof(struct mm_key_del_req));
638 /* Set parameters for the MM_KEY_DEL_REQ message */
639 key_del_req->hw_key_idx = hw_key_idx;
641 /* Send the MM_KEY_DEL_REQ message to LMAC FW */
642 return ecrnx_send_msg(ecrnx_hw, key_del_req, 1, MM_KEY_DEL_CFM, NULL);
645 int ecrnx_send_bcn_change(struct ecrnx_hw *ecrnx_hw, u8 vif_idx, dma_addr_t bcn_addr,
646 u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft)
648 struct mm_bcn_change_req *req;
650 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
652 /* Build the MM_BCN_CHANGE_REQ message */
653 req = ecrnx_msg_zalloc(MM_BCN_CHANGE_REQ, TASK_MM, DRV_TASK_ID,
654 sizeof(struct mm_bcn_change_req));
658 /* Set parameters for the MM_BCN_CHANGE_REQ message */
659 req->bcn_ptr = bcn_addr;
660 req->bcn_len = bcn_len;
661 req->tim_oft = tim_oft;
662 req->tim_len = tim_len;
663 req->inst_nbr = vif_idx;
665 #if defined(CONFIG_ECRNX_SOFTMAC)
666 BUILD_BUG_ON_MSG(IEEE80211_MAX_CSA_COUNTERS_NUM != BCN_MAX_CSA_CPT,
667 "BCN_MAX_CSA_CPT and IEEE80211_MAX_CSA_COUNTERS_NUM "
668 "have different value");
669 #endif /* CONFIG_ECRNX_SOFTMAC */
672 for (i = 0; i < BCN_MAX_CSA_CPT; i++) {
673 req->csa_oft[i] = csa_oft[i];
677 /* Send the MM_BCN_CHANGE_REQ message to LMAC FW */
678 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_BCN_CHANGE_CFM, NULL);
681 int ecrnx_send_roc(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
682 struct ieee80211_channel *chan, unsigned int duration)
684 struct mm_remain_on_channel_req *req;
685 struct cfg80211_chan_def chandef;
687 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
689 /* Create channel definition structure */
690 cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
692 /* Build the MM_REMAIN_ON_CHANNEL_REQ message */
693 req = ecrnx_msg_zalloc(MM_REMAIN_ON_CHANNEL_REQ, TASK_MM, DRV_TASK_ID,
694 sizeof(struct mm_remain_on_channel_req));
698 /* Set parameters for the MM_REMAIN_ON_CHANNEL_REQ message */
699 req->op_code = MM_ROC_OP_START;
700 req->vif_index = vif->vif_index;
701 req->duration_ms = duration;
702 cfg80211_to_ecrnx_chan(&chandef, &req->chan);
704 /* Send the MM_REMAIN_ON_CHANNEL_REQ message to LMAC FW */
705 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_REMAIN_ON_CHANNEL_CFM, NULL);
708 int ecrnx_send_cancel_roc(struct ecrnx_hw *ecrnx_hw)
710 struct mm_remain_on_channel_req *req;
712 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
714 /* Build the MM_REMAIN_ON_CHANNEL_REQ message */
715 req = ecrnx_msg_zalloc(MM_REMAIN_ON_CHANNEL_REQ, TASK_MM, DRV_TASK_ID,
716 sizeof(struct mm_remain_on_channel_req));
720 /* Set parameters for the MM_REMAIN_ON_CHANNEL_REQ message */
721 req->op_code = MM_ROC_OP_CANCEL;
723 /* Send the MM_REMAIN_ON_CHANNEL_REQ message to LMAC FW */
724 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_REMAIN_ON_CHANNEL_CFM, NULL);
727 int ecrnx_send_set_power(struct ecrnx_hw *ecrnx_hw, u8 vif_idx, s8 pwr,
728 struct mm_set_power_cfm *cfm)
730 struct mm_set_power_req *req;
732 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
734 /* Build the MM_SET_POWER_REQ message */
735 req = ecrnx_msg_zalloc(MM_SET_POWER_REQ, TASK_MM, DRV_TASK_ID,
736 sizeof(struct mm_set_power_req));
740 /* Set parameters for the MM_SET_POWER_REQ message */
741 req->inst_nbr = vif_idx;
744 /* Send the MM_SET_POWER_REQ message to LMAC FW */
745 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_SET_POWER_CFM, cfm);
748 int ecrnx_send_set_edca(struct ecrnx_hw *ecrnx_hw, u8 hw_queue, u32 param,
749 bool uapsd, u8 inst_nbr)
751 struct mm_set_edca_req *set_edca_req;
753 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
755 /* Build the MM_SET_EDCA_REQ message */
756 set_edca_req = ecrnx_msg_zalloc(MM_SET_EDCA_REQ, TASK_MM, DRV_TASK_ID,
757 sizeof(struct mm_set_edca_req));
761 /* Set parameters for the MM_SET_EDCA_REQ message */
762 set_edca_req->ac_param = param;
763 set_edca_req->uapsd = uapsd;
764 set_edca_req->hw_queue = hw_queue;
765 set_edca_req->inst_nbr = inst_nbr;
767 /* Send the MM_SET_EDCA_REQ message to LMAC FW */
768 return ecrnx_send_msg(ecrnx_hw, set_edca_req, 1, MM_SET_EDCA_CFM, NULL);
771 #ifdef CONFIG_ECRNX_P2P_DEBUGFS
772 int ecrnx_send_p2p_oppps_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif,
773 u8 ctw, struct mm_set_p2p_oppps_cfm *cfm)
775 struct mm_set_p2p_oppps_req *p2p_oppps_req;
778 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
780 /* Build the MM_SET_P2P_OPPPS_REQ message */
781 p2p_oppps_req = ecrnx_msg_zalloc(MM_SET_P2P_OPPPS_REQ, TASK_MM, DRV_TASK_ID,
782 sizeof(struct mm_set_p2p_oppps_req));
784 if (!p2p_oppps_req) {
788 /* Fill the message parameters */
789 p2p_oppps_req->vif_index = ecrnx_vif->vif_index;
790 p2p_oppps_req->ctwindow = ctw;
792 /* Send the MM_P2P_OPPPS_REQ message to LMAC FW */
793 error = ecrnx_send_msg(ecrnx_hw, p2p_oppps_req, 1, MM_SET_P2P_OPPPS_CFM, cfm);
798 int ecrnx_send_p2p_noa_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif,
799 int count, int interval, int duration, bool dyn_noa,
800 struct mm_set_p2p_noa_cfm *cfm)
802 struct mm_set_p2p_noa_req *p2p_noa_req;
805 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
811 if (duration >= interval) {
812 dev_err(ecrnx_hw->dev, "Invalid p2p NOA config: interval=%d <= duration=%d\n",
817 /* Build the MM_SET_P2P_NOA_REQ message */
818 p2p_noa_req = ecrnx_msg_zalloc(MM_SET_P2P_NOA_REQ, TASK_MM, DRV_TASK_ID,
819 sizeof(struct mm_set_p2p_noa_req));
825 /* Fill the message parameters */
826 p2p_noa_req->vif_index = ecrnx_vif->vif_index;
827 p2p_noa_req->noa_inst_nb = 0;
828 p2p_noa_req->count = count;
831 p2p_noa_req->duration_us = duration * 1024;
832 p2p_noa_req->interval_us = interval * 1024;
833 p2p_noa_req->start_offset = (interval - duration - 10) * 1024;
834 p2p_noa_req->dyn_noa = dyn_noa;
837 /* Send the MM_SET_2P_NOA_REQ message to LMAC FW */
838 error = ecrnx_send_msg(ecrnx_hw, p2p_noa_req, 1, MM_SET_P2P_NOA_CFM, cfm);
842 #endif /* CONFIG_ECRNX_P2P_DEBUGFS */
844 /******************************************************************************
845 * Control messages handling functions (SOFTMAC only)
846 *****************************************************************************/
847 #ifdef CONFIG_ECRNX_SOFTMAC
848 int ecrnx_send_sta_add(struct ecrnx_hw *ecrnx_hw, struct ieee80211_sta *sta,
849 u8 inst_nbr, struct mm_sta_add_cfm *cfm)
851 struct mm_sta_add_req *sta_add_req;
852 union ecrnx_thd_phy_ctrl_info *phy;
853 struct ecrnx_sta *ecrnx_sta;
856 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
858 /* Build the MM_STA_ADD_REQ message */
859 sta_add_req = ecrnx_msg_zalloc(MM_STA_ADD_REQ, TASK_MM, DRV_TASK_ID,
860 sizeof(struct mm_sta_add_req));
864 /* Set parameters for the MM_STA_ADD_REQ message */
865 memcpy(&(sta_add_req->mac_addr.array[0]), &(sta->addr[0]), ETH_ALEN);
868 sta_add_req->capa_flags |= STA_QOS_CAPA;
869 /* TODO: check if a density of 0 microseconds is OK or not for LMAC */
870 if (sta->ht_cap.ht_supported) {
871 int ht_exp = sta->ht_cap.ampdu_factor;
874 sta_add_req->capa_flags |= STA_HT_CAPA;
875 sta_add_req->ampdu_size_max_ht =
876 (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + ht_exp)) - 1;
877 sta_add_req->ampdu_spacing_min =
878 ecrnx_ampdudensity2usec(sta->ht_cap.ampdu_density);
880 if (sta->vht_cap.vht_supported) {
881 sta_add_req->capa_flags |= STA_VHT_CAPA;
882 vht_exp = (sta->vht_cap.cap &
883 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
884 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
885 sta_add_req->ampdu_size_max_vht =
886 (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + vht_exp)) - 1;
889 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) && defined(CONFIG_ECRNX_HE)
890 if (sta->he_cap.has_he) {
891 int he_exp_ext = (sta->he_cap.he_cap_elem.mac_cap_info[3] &
892 IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >> 3;
894 sta_add_req->capa_flags |= STA_HE_CAPA;
895 if (sta->vht_cap.vht_supported) {
896 if ((vht_exp == 7) && he_exp_ext)
897 sta_add_req->ampdu_size_max_he =
898 (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + vht_exp + he_exp_ext)) - 1;
900 sta_add_req->ampdu_size_max_he = sta_add_req->ampdu_size_max_vht;
902 if ((ht_exp == 3) && he_exp_ext)
903 sta_add_req->ampdu_size_max_he =
904 (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + ht_exp + he_exp_ext)) - 1;
906 sta_add_req->ampdu_size_max_he = sta_add_req->ampdu_size_max_ht;
911 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
913 sta_add_req->capa_flags |= STA_MFP_CAPA;
916 ecrnx_sta = (struct ecrnx_sta *)sta->drv_priv;
917 /* TODO Set the interface index from the vif structure */
918 sta_add_req->inst_nbr = inst_nbr;
919 sta_add_req->tdls_sta = sta->tdls;
920 sta_add_req->tdls_sta_initiator = STA_TDLS_INITIATOR(sta);
921 sta_add_req->bssid_index = 0;
922 sta_add_req->max_bssid_ind = 0;
923 phy = (union ecrnx_thd_phy_ctrl_info *)&sta_add_req->paid_gid;
924 phy->partialAIDTx = ecrnx_sta->paid;
925 phy->groupIDTx = ecrnx_sta->gid;
927 /* Send the MM_STA_ADD_REQ message to LMAC FW */
928 error = ecrnx_send_msg(ecrnx_hw, sta_add_req, 1, MM_STA_ADD_CFM, cfm);
933 int ecrnx_send_sta_del(struct ecrnx_hw *ecrnx_hw, u8 sta_idx)
935 struct mm_sta_del_req *sta_del_req;
937 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
939 /* Build the MM_STA_DEL_REQ message */
940 sta_del_req = ecrnx_msg_zalloc(MM_STA_DEL_REQ, TASK_MM, DRV_TASK_ID,
941 sizeof(struct mm_sta_del_req));
945 /* Set parameters for the MM_STA_DEL_REQ message */
946 sta_del_req->sta_idx = sta_idx;
948 /* Send the MM_STA_DEL_REQ message to LMAC FW */
949 return ecrnx_send_msg(ecrnx_hw, sta_del_req, 1, MM_STA_DEL_CFM, NULL);
952 int ecrnx_send_set_filter(struct ecrnx_hw *ecrnx_hw, uint32_t filter)
954 struct mm_set_filter_req *set_filter_req_param;
955 uint32_t rx_filter = 0;
957 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
959 /* Build the MM_SET_FILTER_REQ message */
960 set_filter_req_param =
961 ecrnx_msg_zalloc(MM_SET_FILTER_REQ, TASK_MM, DRV_TASK_ID,
962 sizeof(struct mm_set_filter_req));
963 if (!set_filter_req_param)
966 /* Set parameters for the MM_SET_FILTER_REQ message */
967 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
968 if (filter & FIF_PROMISC_IN_BSS)
969 rx_filter |= NXMAC_ACCEPT_UNICAST_BIT;
971 if (filter & FIF_ALLMULTI)
972 rx_filter |= NXMAC_ACCEPT_MULTICAST_BIT;
974 if (filter & (FIF_FCSFAIL | FIF_PLCPFAIL))
975 rx_filter |= NXMAC_ACCEPT_ERROR_FRAMES_BIT;
977 if (filter & FIF_BCN_PRBRESP_PROMISC)
978 rx_filter |= NXMAC_ACCEPT_OTHER_BSSID_BIT;
980 if (filter & FIF_CONTROL)
981 rx_filter |= NXMAC_ACCEPT_OTHER_CNTRL_FRAMES_BIT |
982 NXMAC_ACCEPT_CF_END_BIT |
983 NXMAC_ACCEPT_ACK_BIT |
984 NXMAC_ACCEPT_CTS_BIT |
985 NXMAC_ACCEPT_RTS_BIT |
986 NXMAC_ACCEPT_BA_BIT | NXMAC_ACCEPT_BAR_BIT;
988 if (filter & FIF_OTHER_BSS)
989 rx_filter |= NXMAC_ACCEPT_OTHER_BSSID_BIT;
991 if (filter & FIF_PSPOLL) {
992 /* TODO: check if the MAC filters apply to our BSSID or is general */
993 rx_filter |= NXMAC_ACCEPT_PS_POLL_BIT;
996 if (filter & FIF_PROBE_REQ) {
997 rx_filter |= NXMAC_ACCEPT_PROBE_REQ_BIT;
998 rx_filter |= NXMAC_ACCEPT_ALL_BEACON_BIT;
1001 /* Add the filter flags that are set by default and cannot be changed here */
1002 rx_filter |= ECRNX_MAC80211_NOT_CHANGEABLE;
1005 if (ieee80211_hw_check(ecrnx_hw->hw, AMPDU_AGGREGATION))
1006 rx_filter |= NXMAC_ACCEPT_BA_BIT;
1008 /* Now copy all the flags into the message parameter */
1009 set_filter_req_param->filter = rx_filter;
1011 ECRNX_DBG("new total_flags = 0x%08x\nrx filter set to 0x%08x\n",
1014 /* Send the MM_SET_FILTER_REQ message to LMAC FW */
1015 return ecrnx_send_msg(ecrnx_hw, set_filter_req_param, 1, MM_SET_FILTER_CFM, NULL);
1019 int ecrnx_send_add_chanctx(struct ecrnx_hw *ecrnx_hw,
1020 struct ieee80211_chanctx_conf *ctx,
1021 struct mm_chan_ctxt_add_cfm *cfm)
1023 struct mm_chan_ctxt_add_req *req;
1025 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1027 /* Build the MM_CHAN_CTXT_ADD_REQ message */
1028 req = ecrnx_msg_zalloc(MM_CHAN_CTXT_ADD_REQ, TASK_MM, DRV_TASK_ID,
1029 sizeof(struct mm_chan_ctxt_add_req));
1033 /* Set parameters for the CHAN_CTXT_ADD_REQ message */
1034 cfg80211_to_ecrnx_chan(&ctx->def, &req->chan);
1036 if (ecrnx_hw->phy.limit_bw)
1037 limit_chan_bw(&req->chan.type, req->chan.prim20_freq,
1038 &req->chan.center1_freq);
1040 ECRNX_DBG("mac80211: freq=%d(c1:%d - c2:%d)/width=%d - band=%d\n"
1041 " prim20=%d(c1:%d - c2:%d)/ type=%d - band=%d\n",
1042 ctx->def.chan->center_freq, ctx->def.center_freq1,
1043 ctx->def.center_freq2, ctx->def.width, ctx->def.chan->band,
1044 req->chan.prim20_freq, req->chan.center1_freq,
1045 req->chan.center2_freq, req->chan.type, req->chan.band);
1046 /* Send the CHAN_CTXT_ADD_REQ message to LMAC FW */
1047 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_CHAN_CTXT_ADD_CFM, cfm);
1050 int ecrnx_send_del_chanctx(struct ecrnx_hw *ecrnx_hw, u8 index)
1052 struct mm_chan_ctxt_del_req *req;
1054 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1056 /* Build the MM_CHAN_CTXT_DEL_REQ message */
1057 req = ecrnx_msg_zalloc(MM_CHAN_CTXT_DEL_REQ, TASK_MM, DRV_TASK_ID,
1058 sizeof(struct mm_chan_ctxt_del_req));
1062 /* Set parameters for the MM_REMOVE_IF_REQ message */
1065 /* Send the MM_CHAN_CTXT_DEL_REQ message to LMAC FW */
1066 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_CHAN_CTXT_DEL_CFM, NULL);
1069 int ecrnx_send_link_chanctx(struct ecrnx_hw *ecrnx_hw, u8 vif_idx, u8 chan_idx,
1072 struct mm_chan_ctxt_link_req *req;
1074 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1076 /* Build the MM_CHAN_CTXT_LINK_REQ message */
1077 req = ecrnx_msg_zalloc(MM_CHAN_CTXT_LINK_REQ, TASK_MM, DRV_TASK_ID,
1078 sizeof(struct mm_chan_ctxt_link_req));
1082 /* Set parameters for the MM_CHAN_CTXT_LINK_REQ message */
1083 req->vif_index = vif_idx;
1084 req->chan_index = chan_idx;
1085 req->chan_switch = chan_switch;
1087 /* Send the MM_CHAN_CTXT_LINK_REQ message to LMAC FW */
1088 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_CHAN_CTXT_LINK_CFM, NULL);
1091 int ecrnx_send_unlink_chanctx(struct ecrnx_hw *ecrnx_hw, u8 vif_idx)
1093 struct mm_chan_ctxt_unlink_req *req;
1095 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1097 /* Build the MM_CHAN_CTXT_UNLINK_REQ message */
1098 req = ecrnx_msg_zalloc(MM_CHAN_CTXT_UNLINK_REQ, TASK_MM, DRV_TASK_ID,
1099 sizeof(struct mm_chan_ctxt_unlink_req));
1103 /* Set parameters for the MM_CHAN_CTXT_UNLINK_REQ message */
1104 req->vif_index = vif_idx;
1106 /* Send the MM_CHAN_CTXT_UNLINK_REQ message to LMAC FW */
1107 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_CHAN_CTXT_UNLINK_CFM, NULL);
1110 int ecrnx_send_update_chanctx(struct ecrnx_hw *ecrnx_hw,
1111 struct ieee80211_chanctx_conf *ctx)
1113 struct mm_chan_ctxt_update_req *req;
1114 struct ecrnx_chanctx *ecrnx_chanctx;
1116 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1118 /* Build the MM_CHAN_CTXT_UPDATE_REQ message */
1119 req = ecrnx_msg_zalloc(MM_CHAN_CTXT_UPDATE_REQ, TASK_MM, DRV_TASK_ID,
1120 sizeof(struct mm_chan_ctxt_update_req));
1124 /* Set parameters for the MM_CHAN_CTXT_UPDATE_REQ message */
1125 ecrnx_chanctx = (struct ecrnx_chanctx *)ctx->drv_priv;
1126 req->chan_index = ecrnx_chanctx->index;
1127 cfg80211_to_ecrnx_chan(&ctx->def, &req->chan);
1129 if (ecrnx_hw->phy.limit_bw)
1130 limit_chan_bw(&req->chan.type, req->chan.prim20_freq, &req->chan.center1_freq);
1132 ECRNX_DBG("mac80211: freq=%d(c1:%d - c2:%d)/width=%d - band=%d\n"
1133 " prim20=%d(c1:%d - c2:%d)/ type=%d - band=%d\n",
1134 ctx->def.chan->center_freq, ctx->def.center_freq1,
1135 ctx->def.center_freq2, ctx->def.width, ctx->def.chan->band,
1136 req->chan.prim20_freq, req->chan.center1_freq,
1137 req->chan.center2_freq, req->chan.type, req->chan.band);
1138 /* Send the MM_CHAN_CTXT_UPDATE_REQ message to LMAC FW */
1139 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_CHAN_CTXT_UPDATE_CFM, NULL);
1142 int ecrnx_send_sched_chanctx(struct ecrnx_hw *ecrnx_hw, u8 vif_idx, u8 chan_idx, u8 type)
1144 struct mm_chan_ctxt_sched_req *req;
1146 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1148 /* Build the MM_CHAN_CTXT_SCHED_REQ message */
1149 req = ecrnx_msg_zalloc(MM_CHAN_CTXT_SCHED_REQ, TASK_MM, DRV_TASK_ID,
1150 sizeof(struct mm_chan_ctxt_sched_req));
1154 /* Set parameters for the MM_CHAN_CTXT_SCHED_REQ message */
1155 req->vif_index = vif_idx;
1156 req->chan_index = chan_idx;
1159 /* Send the MM_CHAN_CTXT_SCHED_REQ message to LMAC FW */
1160 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_CHAN_CTXT_SCHED_CFM, NULL);
1163 int ecrnx_send_dtim_req(struct ecrnx_hw *ecrnx_hw, u8 dtim_period)
1165 struct mm_set_dtim_req *set_dtim_req;
1167 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1169 /* Build the MM_SET_DTIM_REQ message */
1170 set_dtim_req = ecrnx_msg_zalloc(MM_SET_DTIM_REQ, TASK_MM, DRV_TASK_ID,
1171 sizeof(struct mm_set_dtim_req));
1175 /* Set parameters for the MM_SET_DTIM_REQ message */
1176 set_dtim_req->dtim_period = dtim_period;
1178 /* Send the MM_SET_DTIM_REQ message to LMAC FW */
1179 return ecrnx_send_msg(ecrnx_hw, set_dtim_req, 1, MM_SET_DTIM_CFM, NULL);
1182 int ecrnx_send_set_br(struct ecrnx_hw *ecrnx_hw, u32 basic_rates, u8 vif_idx, u8 band)
1184 struct mm_set_basic_rates_req *set_basic_rates_req_param;
1186 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1188 /* Build the MM_SET_BASIC_RATES_REQ message */
1189 set_basic_rates_req_param =
1190 ecrnx_msg_zalloc(MM_SET_BASIC_RATES_REQ, TASK_MM, DRV_TASK_ID,
1191 sizeof(struct mm_set_basic_rates_req));
1192 if (!set_basic_rates_req_param)
1195 /* Set parameters for the MM_SET_BASIC_RATES_REQ message */
1196 set_basic_rates_req_param->rates = basic_rates;
1197 set_basic_rates_req_param->inst_nbr = vif_idx;
1198 set_basic_rates_req_param->band = band;
1200 /* Send the MM_SET_BASIC_RATES_REQ message to LMAC FW */
1201 return ecrnx_send_msg(ecrnx_hw, set_basic_rates_req_param, 1, MM_SET_BASIC_RATES_CFM, NULL);
1204 int ecrnx_send_set_beacon_int(struct ecrnx_hw *ecrnx_hw, u16 beacon_int, u8 vif_idx)
1206 struct mm_set_beacon_int_req *set_beacon_int_req_param;
1208 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1210 /* Build the MM_SET_BEACON_INT_REQ message */
1211 set_beacon_int_req_param =
1212 ecrnx_msg_zalloc(MM_SET_BEACON_INT_REQ, TASK_MM, DRV_TASK_ID,
1213 sizeof(struct mm_set_beacon_int_req));
1214 if (!set_beacon_int_req_param)
1217 /* Set parameters for the MM_SET_BEACON_INT_REQ message */
1218 set_beacon_int_req_param->beacon_int = beacon_int;
1219 set_beacon_int_req_param->inst_nbr = vif_idx;
1221 /* Send the MM_SET_BEACON_INT_REQ message to LMAC FW */
1222 return ecrnx_send_msg(ecrnx_hw, set_beacon_int_req_param, 1,
1223 MM_SET_BEACON_INT_CFM, NULL);
1226 int ecrnx_send_set_bssid(struct ecrnx_hw *ecrnx_hw, const u8 *bssid, u8 vif_idx)
1228 struct mm_set_bssid_req *set_bssid_req_param;
1230 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1232 /* Build the MM_SET_BSSID_REQ message */
1233 set_bssid_req_param = ecrnx_msg_zalloc(MM_SET_BSSID_REQ, TASK_MM, DRV_TASK_ID,
1234 sizeof(struct mm_set_bssid_req));
1235 if (!set_bssid_req_param)
1238 /* Set parameters for the MM_SET_BSSID_REQ message */
1239 memcpy(&(set_bssid_req_param->bssid.array[0]), bssid, ETH_ALEN);
1240 set_bssid_req_param->inst_nbr = vif_idx;
1242 /* Send the MM_SET_BSSID_REQ message to LMAC FW */
1243 return ecrnx_send_msg(ecrnx_hw, set_bssid_req_param, 1, MM_SET_BSSID_CFM, NULL);
1246 int ecrnx_send_set_vif_state(struct ecrnx_hw *ecrnx_hw, bool active,
1247 u16 aid, u8 vif_idx)
1249 struct mm_set_vif_state_req *req;
1251 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1253 /* Build the MM_SET_VIF_STATE_REQ message */
1254 req = ecrnx_msg_zalloc(MM_SET_VIF_STATE_REQ, TASK_MM, DRV_TASK_ID,
1255 sizeof(struct mm_set_vif_state_req));
1259 /* Set parameters for the MM_SET_VIF_STATE_REQ message */
1260 req->active = active;
1262 req->inst_nbr = vif_idx;
1264 /* Send the MM_SET_VIF_STATE_REQ message to LMAC FW */
1265 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_SET_VIF_STATE_CFM, NULL);
1268 int ecrnx_send_set_mode(struct ecrnx_hw *ecrnx_hw, u8 abgnmode)
1270 struct mm_set_mode_req *set_mode_req_param;
1272 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1274 /* Build the MM_SET_MODE_REQ message */
1275 set_mode_req_param = ecrnx_msg_zalloc(MM_SET_MODE_REQ, TASK_MM, DRV_TASK_ID,
1276 sizeof(struct mm_set_mode_req));
1277 if (!set_mode_req_param)
1280 set_mode_req_param->abgnmode = abgnmode;
1282 /* Send the MM_SET_MODE_REQ message to LMAC FW */
1283 return ecrnx_send_msg(ecrnx_hw, set_mode_req_param, 1, MM_SET_MODE_CFM, NULL);
1286 int ecrnx_send_set_idle(struct ecrnx_hw *ecrnx_hw, int idle)
1288 struct mm_set_idle_req *set_idle_req_param;
1290 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1292 set_idle_req_param = ecrnx_msg_zalloc(MM_SET_IDLE_REQ, TASK_MM, DRV_TASK_ID,
1293 sizeof(struct mm_set_idle_req));
1294 if (!set_idle_req_param)
1297 set_idle_req_param->hw_idle = idle;
1299 return ecrnx_send_msg(ecrnx_hw, set_idle_req_param, 1, MM_SET_IDLE_CFM, NULL);
1302 int ecrnx_send_set_ps_mode(struct ecrnx_hw *ecrnx_hw, u8 ps_mode)
1304 struct mm_set_ps_mode_req *set_ps_mode_req_param;
1306 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1308 set_ps_mode_req_param =
1309 ecrnx_msg_zalloc(MM_SET_PS_MODE_REQ, TASK_MM, DRV_TASK_ID,
1310 sizeof(struct mm_set_ps_mode_req));
1311 if (!set_ps_mode_req_param)
1314 set_ps_mode_req_param->new_state = ps_mode;
1316 return ecrnx_send_msg(ecrnx_hw, set_ps_mode_req_param, 1, MM_SET_PS_MODE_CFM, NULL);
1319 int ecrnx_send_set_ps_options(struct ecrnx_hw *ecrnx_hw, bool listen_bcmc,
1320 u16 listen_interval, u8 vif_idx)
1322 struct mm_set_ps_options_req *req;
1324 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1326 /* Build the MM_SET_PS_OPTIONS_REQ message */
1327 req = ecrnx_msg_zalloc(MM_SET_PS_OPTIONS_REQ, TASK_MM, DRV_TASK_ID,
1328 sizeof(struct mm_set_ps_options_req));
1332 /* Set parameters for the MM_SET_VIF_STATE_REQ message */
1333 req->listen_interval = listen_interval;
1334 req->dont_listen_bc_mc = !listen_bcmc;
1335 req->vif_index = vif_idx;
1337 /* Send the MM_SET_PS_OPTIONS_REQ message to LMAC FW */
1338 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_SET_PS_OPTIONS_CFM, NULL);
1341 int ecrnx_send_set_slottime(struct ecrnx_hw *ecrnx_hw, int use_short_slot)
1343 struct mm_set_slottime_req *set_slottime_req_param;
1345 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1347 /* Build the MM_SET_SLOTTIME_REQ message */
1348 set_slottime_req_param =
1349 ecrnx_msg_zalloc(MM_SET_SLOTTIME_REQ, TASK_MM, DRV_TASK_ID,
1350 sizeof(struct mm_set_slottime_req));
1351 if (!set_slottime_req_param)
1354 /* Set parameters for the MM_SET_SLOTTIME_REQ message */
1355 set_slottime_req_param->slottime = use_short_slot ? 9 : 20;
1357 /* Send the MM_SET_SLOTTIME_REQ message to LMAC FW */
1358 return ecrnx_send_msg(ecrnx_hw, set_slottime_req_param, 1, MM_SET_SLOTTIME_CFM, NULL);
1361 int ecrnx_send_ba_add(struct ecrnx_hw *ecrnx_hw, uint8_t type, uint8_t sta_idx,
1362 u16 tid, uint8_t bufsz, uint16_t ssn,
1363 struct mm_ba_add_cfm *cfm)
1365 struct mm_ba_add_req *req;
1367 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1369 /* Build the MM_BA_ADD_REQ message */
1370 req = ecrnx_msg_zalloc(MM_BA_ADD_REQ, TASK_MM, DRV_TASK_ID,
1371 sizeof(struct mm_ba_add_req));
1375 /* Set parameters for the MM_BA_ADD_REQ message */
1377 req->sta_idx = sta_idx;
1378 req->tid = (u8_l)tid;
1382 /* Send the MM_BA_ADD_REQ message to LMAC FW */
1383 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_BA_ADD_CFM, cfm);
1386 int ecrnx_send_ba_del(struct ecrnx_hw *ecrnx_hw, uint8_t sta_idx, u16 tid,
1387 struct mm_ba_del_cfm *cfm)
1389 struct mm_ba_del_req *req;
1391 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1393 /* Build the MM_BA_DEL_REQ message */
1394 req = ecrnx_msg_zalloc(MM_BA_DEL_REQ, TASK_MM, DRV_TASK_ID,
1395 sizeof(struct mm_ba_del_req));
1399 /* Set parameters */
1401 req->sta_idx = sta_idx;
1402 req->tid = (u8_l)tid;
1404 /* Send the MM_BA_DEL_REQ message to LMAC FW */
1405 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_BA_DEL_CFM, cfm);
1408 int ecrnx_send_scan_req(struct ecrnx_hw *ecrnx_hw, struct ieee80211_vif *vif,
1409 struct cfg80211_scan_request *param,
1410 struct scan_start_cfm *cfm)
1412 struct scan_start_req *req;
1414 struct ecrnx_vif *ecrnx_vif;
1415 uint8_t chan_flags = 0;
1417 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1419 ecrnx_vif = (struct ecrnx_vif *)vif->drv_priv;
1421 /* Build the SCAN_START_REQ message */
1422 req = ecrnx_msg_zalloc(SCAN_START_REQ, TASK_SCAN, DRV_TASK_ID,
1423 sizeof(struct scan_start_req));
1427 /* Set parameters */
1428 req->vif_idx = ecrnx_vif->vif_index;
1429 req->chan_cnt = (u8)min_t(int, SCAN_CHANNEL_MAX, param->n_channels);
1430 req->ssid_cnt = (u8)min_t(int, SCAN_SSID_MAX, param->n_ssids);
1431 req->bssid = mac_addr_bcst;
1432 req->no_cck = param->no_cck;
1433 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
1434 if (param->duration_mandatory)
1435 req->duration = ieee80211_tu_to_usec(param->duration);
1438 if (req->ssid_cnt == 0)
1439 chan_flags |= CHAN_NO_IR;
1440 for (i = 0; i < req->ssid_cnt; i++) {
1442 for (j = 0; j < param->ssids[i].ssid_len; j++)
1443 req->ssid[i].array[j] = param->ssids[i].ssid[j];
1444 req->ssid[i].length = param->ssids[i].ssid_len;
1448 if (ecrnx_ipc_elem_var_allocs(ecrnx_hw, &ecrnx_hw->scan_ie,
1449 param->ie_len, DMA_TO_DEVICE,
1450 NULL, param->ie, NULL))
1453 req->add_ie_len = param->ie_len;
1454 req->add_ies = ecrnx_hw->scan_ie.dma_addr;
1456 req->add_ie_len = 0;
1460 for (i = 0; i < req->chan_cnt; i++) {
1461 struct ieee80211_channel *chan = param->channels[i];
1463 req->chan[i].band = chan->band;
1464 req->chan[i].freq = chan->center_freq;
1465 req->chan[i].flags = chan_flags | get_chan_flags(chan->flags);
1466 req->chan[i].tx_power = chan_to_fw_pwr(chan->max_reg_power);
1469 /* Send the SCAN_START_REQ message to LMAC FW */
1470 return ecrnx_send_msg(ecrnx_hw, req, 1, SCAN_START_CFM, cfm);
1473 ecrnx_msg_free(ecrnx_hw, req);
1477 int ecrnx_send_scan_cancel_req(struct ecrnx_hw *ecrnx_hw,
1478 struct scan_cancel_cfm *cfm)
1480 struct scan_cancel_req *req;
1482 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1484 /* Build the SCAN_CANCEL_REQ message */
1485 req = ecrnx_msg_zalloc(SCAN_CANCEL_REQ, TASK_SCAN, DRV_TASK_ID,
1486 sizeof(struct scan_cancel_req));
1490 /* Send the SCAN_CANCEL_REQ message to LMAC FW */
1491 return ecrnx_send_msg(ecrnx_hw, req, 1, SCAN_CANCEL_CFM, cfm);
1494 void ecrnx_send_tdls_ps(struct ecrnx_hw *ecrnx_hw, bool ps_mode)
1496 if (!ecrnx_hw->mod_params->ps_on)
1499 ecrnx_send_set_ps_mode(ecrnx_hw, ps_mode);
1502 int ecrnx_send_tim_update(struct ecrnx_hw *ecrnx_hw, u8 vif_idx, u16 aid,
1505 struct mm_tim_update_req *req;
1507 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1509 /* Build the MM_TIM_UPDATE_REQ message */
1510 req = ecrnx_msg_zalloc(MM_TIM_UPDATE_REQ, TASK_MM, DRV_TASK_ID,
1511 sizeof(struct mm_tim_update_req));
1515 /* Set parameters for the MM_TIM_UPDATE_REQ message */
1517 req->tx_avail = tx_status;
1518 req->inst_nbr = vif_idx;
1520 /* Send the MM_TIM_UPDATE_REQ message to LMAC FW */
1521 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_TIM_UPDATE_CFM, NULL);
1523 #endif /* CONFIG_ECRNX_SOFTMAC */
1525 /******************************************************************************
1526 * Control messages handling functions (FULLMAC only)
1527 *****************************************************************************/
1528 #ifdef CONFIG_ECRNX_FULLMAC
1530 int ecrnx_send_me_config_req(struct ecrnx_hw *ecrnx_hw)
1532 struct me_config_req *req;
1533 struct wiphy *wiphy = ecrnx_hw->wiphy;
1534 #ifdef CONFIG_ECRNX_5G
1535 struct ieee80211_sta_ht_cap *ht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->ht_cap;
1536 struct ieee80211_sta_vht_cap *vht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->vht_cap;
1538 struct ieee80211_sta_ht_cap *ht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap;
1539 struct ieee80211_sta_vht_cap *vht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->vht_cap;
1541 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(CONFIG_ECRNX_HE)
1542 struct ieee80211_sta_he_cap const *he_cap;
1544 uint8_t *ht_mcs = (uint8_t *)&ht_cap->mcs;
1547 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1549 /* Build the ME_CONFIG_REQ message */
1550 req = ecrnx_msg_zalloc(ME_CONFIG_REQ, TASK_ME, DRV_TASK_ID,
1551 sizeof(struct me_config_req));
1555 /* Set parameters for the ME_CONFIG_REQ message */
1556 req->ht_supp = ht_cap->ht_supported;
1557 req->vht_supp = vht_cap->vht_supported;
1558 req->ht_cap.ht_capa_info = cpu_to_le16(ht_cap->cap);
1559 req->ht_cap.a_mpdu_param = ht_cap->ampdu_factor |
1560 (ht_cap->ampdu_density <<
1561 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
1562 for (i = 0; i < sizeof(ht_cap->mcs); i++)
1563 req->ht_cap.mcs_rate[i] = ht_mcs[i];
1564 req->ht_cap.ht_extended_capa = 0;
1565 req->ht_cap.tx_beamforming_capa = 0;
1566 req->ht_cap.asel_capa = 0;
1568 req->vht_cap.vht_capa_info = cpu_to_le32(vht_cap->cap);
1569 req->vht_cap.rx_highest = cpu_to_le16(vht_cap->vht_mcs.rx_highest);
1570 req->vht_cap.rx_mcs_map = cpu_to_le16(vht_cap->vht_mcs.rx_mcs_map);
1571 req->vht_cap.tx_highest = cpu_to_le16(vht_cap->vht_mcs.tx_highest);
1572 req->vht_cap.tx_mcs_map = cpu_to_le16(vht_cap->vht_mcs.tx_mcs_map);
1574 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(CONFIG_ECRNX_HE)
1575 #ifdef CONFIG_ECRNX_5G
1576 if (wiphy->bands[NL80211_BAND_5GHZ]->iftype_data != NULL) {
1577 he_cap = &wiphy->bands[NL80211_BAND_5GHZ]->iftype_data->he_cap;
1579 if (wiphy->bands[NL80211_BAND_2GHZ]->iftype_data != NULL) {
1580 he_cap = &wiphy->bands[NL80211_BAND_2GHZ]->iftype_data->he_cap;
1583 req->he_supp = he_cap->has_he;
1584 for (i = 0; i < ARRAY_SIZE(he_cap->he_cap_elem.mac_cap_info); i++) {
1585 req->he_cap.mac_cap_info[i] = he_cap->he_cap_elem.mac_cap_info[i];
1587 for (i = 0; i < ARRAY_SIZE(he_cap->he_cap_elem.phy_cap_info); i++) {
1588 req->he_cap.phy_cap_info[i] = he_cap->he_cap_elem.phy_cap_info[i];
1590 req->he_cap.mcs_supp.rx_mcs_80 = cpu_to_le16(he_cap->he_mcs_nss_supp.rx_mcs_80);
1591 req->he_cap.mcs_supp.tx_mcs_80 = cpu_to_le16(he_cap->he_mcs_nss_supp.tx_mcs_80);
1592 req->he_cap.mcs_supp.rx_mcs_160 = cpu_to_le16(he_cap->he_mcs_nss_supp.rx_mcs_160);
1593 req->he_cap.mcs_supp.tx_mcs_160 = cpu_to_le16(he_cap->he_mcs_nss_supp.tx_mcs_160);
1594 req->he_cap.mcs_supp.rx_mcs_80p80 = cpu_to_le16(he_cap->he_mcs_nss_supp.rx_mcs_80p80);
1595 req->he_cap.mcs_supp.tx_mcs_80p80 = cpu_to_le16(he_cap->he_mcs_nss_supp.tx_mcs_80p80);
1596 for (i = 0; i < MAC_HE_PPE_THRES_MAX_LEN; i++) {
1597 req->he_cap.ppe_thres[i] = he_cap->ppe_thres[i];
1599 req->he_ul_on = ecrnx_hw->mod_params->he_ul_on;
1602 req->he_ul_on = false;
1604 req->he_supp = ecrnx_he_cap.has_he;
1605 for (i = 0; i < ARRAY_SIZE(ecrnx_he_cap.he_cap_elem.mac_cap_info); i++) {
1606 req->he_cap.mac_cap_info[i] = ecrnx_he_cap.he_cap_elem.mac_cap_info[i];
1608 for (i = 0; i < ARRAY_SIZE(ecrnx_he_cap.he_cap_elem.phy_cap_info); i++) {
1609 req->he_cap.phy_cap_info[i] = ecrnx_he_cap.he_cap_elem.phy_cap_info[i];
1611 req->he_cap.mcs_supp.rx_mcs_80 = cpu_to_le16(ecrnx_he_cap.he_mcs_nss_supp.rx_mcs_80);
1612 req->he_cap.mcs_supp.tx_mcs_80 = cpu_to_le16(ecrnx_he_cap.he_mcs_nss_supp.tx_mcs_80);
1613 req->he_cap.mcs_supp.rx_mcs_160 = cpu_to_le16(ecrnx_he_cap.he_mcs_nss_supp.rx_mcs_160);
1614 req->he_cap.mcs_supp.tx_mcs_160 = cpu_to_le16(ecrnx_he_cap.he_mcs_nss_supp.tx_mcs_160);
1615 req->he_cap.mcs_supp.rx_mcs_80p80 = cpu_to_le16(ecrnx_he_cap.he_mcs_nss_supp.rx_mcs_80p80);
1616 req->he_cap.mcs_supp.tx_mcs_80p80 = cpu_to_le16(ecrnx_he_cap.he_mcs_nss_supp.tx_mcs_80p80);
1617 for (i = 0; i < MAC_HE_PPE_THRES_MAX_LEN; i++) {
1618 req->he_cap.ppe_thres[i] = ecrnx_he_cap.ppe_thres[i];
1622 req->ps_on = ecrnx_hw->mod_params->ps_on;
1623 req->dpsm = ecrnx_hw->mod_params->dpsm;
1625 * set sleep_flag for sdio slave.
1631 req->sleep_flag = 0x5;
1632 req->tx_lft = ecrnx_hw->mod_params->tx_lft;
1633 req->ant_div_on = ecrnx_hw->mod_params->ant_div;
1634 if (ecrnx_hw->mod_params->use_80)
1635 req->phy_bw_max = PHY_CHNL_BW_80;
1636 else if (ecrnx_hw->mod_params->use_2040)
1637 req->phy_bw_max = PHY_CHNL_BW_40;
1639 req->phy_bw_max = PHY_CHNL_BW_20;
1641 wiphy_info(wiphy, "HT supp %d, VHT supp %d, HE supp %d\n", req->ht_supp,
1645 /* Send the ME_CONFIG_REQ message to LMAC FW */
1646 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_CONFIG_CFM, NULL);
1649 int ecrnx_send_me_chan_config_req(struct ecrnx_hw *ecrnx_hw)
1651 struct me_chan_config_req *req;
1652 struct wiphy *wiphy = ecrnx_hw->wiphy;
1655 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1657 /* Build the ME_CHAN_CONFIG_REQ message */
1658 req = ecrnx_msg_zalloc(ME_CHAN_CONFIG_REQ, TASK_ME, DRV_TASK_ID,
1659 sizeof(struct me_chan_config_req));
1663 req->chan2G4_cnt= 0;
1664 if (wiphy->bands[NL80211_BAND_2GHZ] != NULL) {
1665 struct ieee80211_supported_band *b = wiphy->bands[NL80211_BAND_2GHZ];
1666 for (i = 0; i < b->n_channels; i++) {
1667 req->chan2G4[req->chan2G4_cnt].flags = 0;
1668 if (b->channels[i].flags & IEEE80211_CHAN_DISABLED)
1669 req->chan2G4[req->chan2G4_cnt].flags |= CHAN_DISABLED;
1670 req->chan2G4[req->chan2G4_cnt].flags |= get_chan_flags(b->channels[i].flags);
1671 req->chan2G4[req->chan2G4_cnt].band = NL80211_BAND_2GHZ;
1672 req->chan2G4[req->chan2G4_cnt].freq = b->channels[i].center_freq;
1673 req->chan2G4[req->chan2G4_cnt].tx_power = chan_to_fw_pwr(b->channels[i].max_power);
1675 if (req->chan2G4_cnt == MAC_DOMAINCHANNEL_24G_MAX)
1680 req->chan5G_cnt = 0;
1681 #ifdef CONFIG_ECRNX_5G
1682 if (wiphy->bands[NL80211_BAND_5GHZ] != NULL) {
1683 struct ieee80211_supported_band *b = wiphy->bands[NL80211_BAND_5GHZ];
1684 for (i = 0; i < b->n_channels; i++) {
1685 req->chan5G[req->chan5G_cnt].flags = 0;
1686 if (b->channels[i].flags & IEEE80211_CHAN_DISABLED)
1687 req->chan5G[req->chan5G_cnt].flags |= CHAN_DISABLED;
1688 req->chan5G[req->chan5G_cnt].flags |= get_chan_flags(b->channels[i].flags);
1689 req->chan5G[req->chan5G_cnt].band = NL80211_BAND_5GHZ;
1690 req->chan5G[req->chan5G_cnt].freq = b->channels[i].center_freq;
1691 req->chan5G[req->chan5G_cnt].tx_power = chan_to_fw_pwr(b->channels[i].max_power);
1693 if (req->chan5G_cnt == MAC_DOMAINCHANNEL_5G_MAX)
1698 /* Send the ME_CHAN_CONFIG_REQ message to LMAC FW */
1699 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_CHAN_CONFIG_CFM, NULL);
1702 int ecrnx_send_me_set_control_port_req(struct ecrnx_hw *ecrnx_hw, bool opened, u8 sta_idx)
1704 struct me_set_control_port_req *req;
1706 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1708 /* Build the ME_SET_CONTROL_PORT_REQ message */
1709 req = ecrnx_msg_zalloc(ME_SET_CONTROL_PORT_REQ, TASK_ME, DRV_TASK_ID,
1710 sizeof(struct me_set_control_port_req));
1714 /* Set parameters for the ME_SET_CONTROL_PORT_REQ message */
1715 req->sta_idx = sta_idx;
1716 req->control_port_open = opened;
1718 /* Send the ME_SET_CONTROL_PORT_REQ message to LMAC FW */
1719 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_SET_CONTROL_PORT_CFM, NULL);
1722 int ecrnx_send_me_sta_add(struct ecrnx_hw *ecrnx_hw, struct station_parameters *params,
1723 const u8 *mac, u8 inst_nbr, struct me_sta_add_cfm *cfm)
1725 struct me_sta_add_req *req;
1726 u8 *ht_mcs = (u8 *)¶ms->ht_capa->mcs;
1729 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1731 /* Build the MM_STA_ADD_REQ message */
1732 req = ecrnx_msg_zalloc(ME_STA_ADD_REQ, TASK_ME, DRV_TASK_ID,
1733 sizeof(struct me_sta_add_req));
1737 /* Set parameters for the MM_STA_ADD_REQ message */
1738 memcpy(&(req->mac_addr.array[0]), mac, ETH_ALEN);
1740 req->rate_set.length = params->supported_rates_len;
1741 for (i = 0; i < params->supported_rates_len; i++)
1742 req->rate_set.array[i] = params->supported_rates[i];
1746 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1747 if (params->capability & WLAN_CAPABILITY_SHORT_PREAMBLE){
1748 req->flags |= STA_SHORT_PREAMBLE_CAPA;
1752 if (params->ht_capa) {
1753 const struct ieee80211_ht_cap *ht_capa = params->ht_capa;
1755 req->flags |= STA_HT_CAPA;
1756 req->ht_cap.ht_capa_info = cpu_to_le16(ht_capa->cap_info);
1757 req->ht_cap.a_mpdu_param = ht_capa->ampdu_params_info;
1758 for (i = 0; i < sizeof(ht_capa->mcs); i++)
1759 req->ht_cap.mcs_rate[i] = ht_mcs[i];
1760 req->ht_cap.ht_extended_capa = cpu_to_le16(ht_capa->extended_ht_cap_info);
1761 req->ht_cap.tx_beamforming_capa = cpu_to_le32(ht_capa->tx_BF_cap_info);
1762 req->ht_cap.asel_capa = ht_capa->antenna_selection_info;
1765 if (params->vht_capa) {
1766 const struct ieee80211_vht_cap *vht_capa = params->vht_capa;
1768 req->flags |= STA_VHT_CAPA;
1769 req->vht_cap.vht_capa_info = cpu_to_le32(vht_capa->vht_cap_info);
1770 req->vht_cap.rx_highest = cpu_to_le16(vht_capa->supp_mcs.rx_highest);
1771 req->vht_cap.rx_mcs_map = cpu_to_le16(vht_capa->supp_mcs.rx_mcs_map);
1772 req->vht_cap.tx_highest = cpu_to_le16(vht_capa->supp_mcs.tx_highest);
1773 req->vht_cap.tx_mcs_map = cpu_to_le16(vht_capa->supp_mcs.tx_mcs_map);
1776 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) && defined(CONFIG_ECRNX_HE)
1777 if (params->he_capa) {
1778 const struct ieee80211_he_cap_elem *he_capa = params->he_capa;
1779 struct ieee80211_he_mcs_nss_supp *mcs_nss_supp =
1780 (struct ieee80211_he_mcs_nss_supp *)(he_capa + 1);
1782 req->flags |= STA_HE_CAPA;
1783 for (i = 0; i < ARRAY_SIZE(he_capa->mac_cap_info); i++) {
1784 req->he_cap.mac_cap_info[i] = he_capa->mac_cap_info[i];
1786 for (i = 0; i < ARRAY_SIZE(he_capa->phy_cap_info); i++) {
1787 req->he_cap.phy_cap_info[i] = he_capa->phy_cap_info[i];
1789 req->he_cap.mcs_supp.rx_mcs_80 = mcs_nss_supp->rx_mcs_80;
1790 req->he_cap.mcs_supp.tx_mcs_80 = mcs_nss_supp->tx_mcs_80;
1791 req->he_cap.mcs_supp.rx_mcs_160 = mcs_nss_supp->rx_mcs_160;
1792 req->he_cap.mcs_supp.tx_mcs_160 = mcs_nss_supp->tx_mcs_160;
1793 req->he_cap.mcs_supp.rx_mcs_80p80 = mcs_nss_supp->rx_mcs_80p80;
1794 req->he_cap.mcs_supp.tx_mcs_80p80 = mcs_nss_supp->tx_mcs_80p80;
1799 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME))
1800 req->flags |= STA_QOS_CAPA;
1802 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_MFP)) // if (sme->mfp == NL80211_MFP_REQUIRED || sme->mfp ==NL80211_MFP_OPTIONAL) //wfa must used NL80211_MFP_REQUIRED and NL80211_MFP_OPTIONAL
1803 req->flags |= STA_MFP_CAPA;
1805 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1806 if (params->opmode_notif_used) {
1807 req->flags |= STA_OPMOD_NOTIF;
1808 req->opmode = params->opmode_notif;
1812 req->aid = cpu_to_le16(params->aid);
1813 req->uapsd_queues = params->uapsd_queues;
1814 req->max_sp_len = params->max_sp * 2;
1815 req->vif_idx = inst_nbr;
1817 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
1818 struct ecrnx_vif *ecrnx_vif = ecrnx_hw->vif_table[inst_nbr];
1819 req->tdls_sta = true;
1820 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1821 if ((params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) &&
1822 !ecrnx_vif->tdls_chsw_prohibited)
1823 req->tdls_chsw_allowed = true;
1825 if (ecrnx_vif->tdls_status == TDLS_SETUP_RSP_TX)
1826 req->tdls_sta_initiator = true;
1829 /* Send the ME_STA_ADD_REQ message to LMAC FW */
1830 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_STA_ADD_CFM, cfm);
1833 int ecrnx_send_me_sta_del(struct ecrnx_hw *ecrnx_hw, u8 sta_idx, bool tdls_sta)
1835 struct me_sta_del_req *req;
1837 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1839 /* Build the MM_STA_DEL_REQ message */
1840 req = ecrnx_msg_zalloc(ME_STA_DEL_REQ, TASK_ME, DRV_TASK_ID,
1841 sizeof(struct me_sta_del_req));
1845 /* Set parameters for the MM_STA_DEL_REQ message */
1846 req->sta_idx = sta_idx;
1847 req->tdls_sta = tdls_sta;
1849 /* Send the ME_STA_DEL_REQ message to LMAC FW */
1850 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_STA_DEL_CFM, NULL);
1853 int ecrnx_send_me_traffic_ind(struct ecrnx_hw *ecrnx_hw, u8 sta_idx, bool uapsd, u8 tx_status)
1855 struct me_traffic_ind_req *req;
1857 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1859 /* Build the ME_UTRAFFIC_IND_REQ message */
1860 req = ecrnx_msg_zalloc(ME_TRAFFIC_IND_REQ, TASK_ME, DRV_TASK_ID,
1861 sizeof(struct me_traffic_ind_req));
1865 /* Set parameters for the ME_TRAFFIC_IND_REQ message */
1866 req->sta_idx = sta_idx;
1867 req->tx_avail = tx_status;
1870 /* Send the ME_TRAFFIC_IND_REQ to UMAC FW */
1871 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_TRAFFIC_IND_CFM, NULL);
1874 int ecrnx_send_twt_request(struct ecrnx_hw *ecrnx_hw,
1875 u8 setup_type, u8 vif_idx,
1876 struct twt_conf_tag *conf,
1877 struct twt_setup_cfm *cfm)
1879 struct twt_setup_req *req;
1881 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1883 /* Build the TWT_SETUP_REQ message */
1884 req = ecrnx_msg_zalloc(TWT_SETUP_REQ, TASK_TWT, DRV_TASK_ID,
1885 sizeof(struct twt_setup_req));
1889 memcpy(&req->conf, conf, sizeof(req->conf));
1890 req->setup_type = setup_type;
1891 req->vif_idx = vif_idx;
1893 /* Send the TWT_SETUP_REQ message to LMAC FW */
1894 return ecrnx_send_msg(ecrnx_hw, req, 1, TWT_SETUP_CFM, cfm);
1897 int ecrnx_send_twt_teardown(struct ecrnx_hw *ecrnx_hw,
1898 struct twt_teardown_req *twt_teardown,
1899 struct twt_teardown_cfm *cfm)
1901 struct twt_teardown_req *req;
1903 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1905 /* Build the TWT_TEARDOWN_REQ message */
1906 req = ecrnx_msg_zalloc(TWT_TEARDOWN_REQ, TASK_TWT, DRV_TASK_ID,
1907 sizeof(struct twt_teardown_req));
1911 memcpy(req, twt_teardown, sizeof(struct twt_teardown_req));
1913 /* Send the TWT_TEARDOWN_REQ message to LMAC FW */
1914 return ecrnx_send_msg(ecrnx_hw, req, 1, TWT_TEARDOWN_CFM, cfm);
1916 int ecrnx_send_me_rc_stats(struct ecrnx_hw *ecrnx_hw,
1918 struct me_rc_stats_cfm *cfm)
1920 struct me_rc_stats_req *req;
1922 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1924 /* Build the ME_RC_STATS_REQ message */
1925 req = ecrnx_msg_zalloc(ME_RC_STATS_REQ, TASK_ME, DRV_TASK_ID,
1926 sizeof(struct me_rc_stats_req));
1930 /* Set parameters for the ME_RC_STATS_REQ message */
1931 req->sta_idx = sta_idx;
1933 /* Send the ME_RC_STATS_REQ message to LMAC FW */
1934 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_RC_STATS_CFM, cfm);
1937 int ecrnx_send_me_rc_set_rate(struct ecrnx_hw *ecrnx_hw,
1941 struct me_rc_set_rate_req *req;
1943 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1945 /* Build the ME_RC_SET_RATE_REQ message */
1946 req = ecrnx_msg_zalloc(ME_RC_SET_RATE_REQ, TASK_ME, DRV_TASK_ID,
1947 sizeof(struct me_rc_set_rate_req));
1951 /* Set parameters for the ME_RC_SET_RATE_REQ message */
1952 req->sta_idx = sta_idx;
1953 req->fixed_rate_cfg = rate_cfg;
1955 /* Send the ME_RC_SET_RATE_REQ message to FW */
1956 return ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
1959 int ecrnx_send_me_set_ps_mode(struct ecrnx_hw *ecrnx_hw, u8 ps_mode)
1961 struct me_set_ps_mode_req *req;
1963 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1965 /* Build the ME_SET_PS_MODE_REQ message */
1966 req = ecrnx_msg_zalloc(ME_SET_PS_MODE_REQ, TASK_ME, DRV_TASK_ID,
1967 sizeof(struct me_set_ps_mode_req));
1971 /* Set parameters for the ME_SET_PS_MODE_REQ message */
1972 req->ps_state = ps_mode;
1974 /* Send the ME_SET_PS_MODE_REQ message to FW */
1975 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_SET_PS_MODE_CFM, NULL);
1978 int ecrnx_send_sm_connect_req(struct ecrnx_hw *ecrnx_hw,
1979 struct ecrnx_vif *ecrnx_vif,
1980 struct cfg80211_connect_params *sme,
1981 struct sm_connect_cfm *cfm)
1983 struct sm_connect_req *req;
1986 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
1988 ie_len = update_connect_req(ecrnx_vif, sme);
1989 /* Build the SM_CONNECT_REQ message */
1990 req = ecrnx_msg_zalloc(SM_CONNECT_REQ, TASK_SM, DRV_TASK_ID,
1991 (sizeof(struct sm_connect_req) + ie_len));
1995 /* Set parameters for the SM_CONNECT_REQ message */
1996 if (sme->crypto.n_ciphers_pairwise &&
1997 ((sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP40) ||
1998 (sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_TKIP) ||
1999 (sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP104)))
2000 req->flags |= DISABLE_HT;
2002 if (sme->crypto.control_port)
2003 req->flags |= CONTROL_PORT_HOST;
2005 if (sme->crypto.control_port_no_encrypt)
2006 req->flags |= CONTROL_PORT_NO_ENC;
2008 if (use_pairwise_key(&sme->crypto))
2009 req->flags |= WPA_WPA2_IN_USE;
2011 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2012 if (sme->mfp == NL80211_MFP_REQUIRED)
2013 req->flags |= MFP_IN_USE;
2016 req->ctrl_port_ethertype = sme->crypto.control_port_ethertype;
2019 memcpy(&req->bssid, sme->bssid, ETH_ALEN);
2021 req->bssid = mac_addr_bcst;
2022 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
2023 if (sme->prev_bssid)
2024 req->flags |= REASSOCIATION;
2026 if (ecrnx_vif->sta.ap)
2027 req->flags |= REASSOCIATION;
2029 if ((sme->auth_type == NL80211_AUTHTYPE_FT) && (ecrnx_vif->sta.flags & ECRNX_STA_FT_OVER_DS))
2030 req->flags |= (REASSOCIATION | FT_OVER_DS);
2031 req->vif_idx = ecrnx_vif->vif_index;
2033 req->chan.band = sme->channel->band;
2034 req->chan.freq = sme->channel->center_freq;
2035 req->chan.flags = get_chan_flags(sme->channel->flags);
2037 req->chan.freq = (u16_l)-1;
2039 for (i = 0; i < sme->ssid_len; i++)
2040 req->ssid.array[i] = sme->ssid[i];
2041 req->ssid.length = sme->ssid_len;
2043 req->listen_interval = ecrnx_mod_params.listen_itv;
2044 req->dont_wait_bcmc = !ecrnx_mod_params.listen_bcmc;
2047 if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC)
2048 req->auth_type = WLAN_AUTH_OPEN;
2049 else if (sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
2050 req->auth_type = WLAN_AUTH_OPEN;
2051 else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
2052 req->auth_type = WLAN_AUTH_SHARED_KEY;
2053 else if (sme->auth_type == NL80211_AUTHTYPE_FT)
2054 req->auth_type = WLAN_AUTH_FT;
2055 else if (sme->auth_type == NL80211_AUTHTYPE_SAE)
2056 req->auth_type = WLAN_AUTH_SAE;
2059 copy_connect_ies(ecrnx_vif, req, sme);
2061 /* Set UAPSD queues */
2062 req->uapsd_queues = ecrnx_mod_params.uapsd_queues;
2064 /* Send the SM_CONNECT_REQ message to LMAC FW */
2065 return ecrnx_send_msg(ecrnx_hw, req, 1, SM_CONNECT_CFM, cfm);
2068 ecrnx_msg_free(ecrnx_hw, req);
2072 int ecrnx_send_sm_disconnect_req(struct ecrnx_hw *ecrnx_hw,
2073 struct ecrnx_vif *ecrnx_vif,
2076 struct sm_disconnect_req *req;
2078 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2080 /* Build the SM_DISCONNECT_REQ message */
2081 req = ecrnx_msg_zalloc(SM_DISCONNECT_REQ, TASK_SM, DRV_TASK_ID,
2082 sizeof(struct sm_disconnect_req));
2086 /* Set parameters for the SM_DISCONNECT_REQ message */
2087 req->reason_code = reason;
2088 req->vif_idx = ecrnx_vif->vif_index;
2090 /* Send the SM_DISCONNECT_REQ message to LMAC FW */
2091 return ecrnx_send_msg(ecrnx_hw, req, 1, SM_DISCONNECT_CFM, NULL);
2094 int ecrnx_send_sm_external_auth_required_rsp(struct ecrnx_hw *ecrnx_hw,
2095 struct ecrnx_vif *ecrnx_vif,
2098 struct sm_external_auth_required_rsp *rsp;
2100 /* Build the SM_EXTERNAL_AUTH_CFM message */
2101 rsp = ecrnx_msg_zalloc(SM_EXTERNAL_AUTH_REQUIRED_RSP, TASK_SM, DRV_TASK_ID,
2102 sizeof(struct sm_external_auth_required_rsp));
2106 rsp->status = status;
2107 rsp->vif_idx = ecrnx_vif->vif_index;
2109 /* send the SM_EXTERNAL_AUTH_REQUIRED_RSP message UMAC FW */
2110 return ecrnx_send_msg(ecrnx_hw, rsp, 0, 0, NULL);
2112 int ecrnx_send_sm_ft_auth_rsp(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif,
2113 uint8_t *ie, int ie_len)
2115 struct sm_connect_req *rsp;
2116 rsp = ecrnx_msg_zalloc(SM_FT_AUTH_RSP, TASK_SM, DRV_TASK_ID,
2117 (sizeof(struct sm_connect_req) + ie_len));
2120 rsp->vif_idx = ecrnx_vif->vif_index;
2121 rsp->ie_len = ie_len;
2122 memcpy(rsp->ie_buf, ie, rsp->ie_len);
2123 return ecrnx_send_msg(ecrnx_hw, rsp, 0, 0, NULL);
2126 int ecrnx_send_apm_start_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2127 struct cfg80211_ap_settings *settings,
2128 struct apm_start_cfm *cfm,
2129 struct ecrnx_ipc_elem_var *elem)
2131 struct apm_start_req *req;
2132 struct ecrnx_bcn *bcn = &vif->ap.bcn;
2137 int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
2141 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2143 /* Build the APM_START_REQ message */
2144 req = ecrnx_msg_zalloc(APM_START_REQ, TASK_APM, DRV_TASK_ID,
2145 sizeof(struct apm_start_req));
2150 bcn->dtim = (u8)settings->dtim_period;
2151 buf = ecrnx_build_bcn(bcn, &settings->beacon);
2153 ecrnx_msg_free(ecrnx_hw, req);
2157 // Retrieve the basic rate set from the beacon buffer
2158 len = bcn->len - var_offset;
2159 var_pos = buf + var_offset;
2161 // Assume that rate higher that 54 Mbps are BSS membership
2162 #define IS_BASIC_RATE(r) (r & 0x80) && ((r & ~0x80) <= (54 * 2))
2164 rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
2166 const u8 *rates = rate_ie + 2;
2167 for (i = 0; (i < rate_ie[1]) && (rate_len < MAC_RATESET_LEN); i++) {
2168 if (IS_BASIC_RATE(rates[i]))
2169 req->basic_rates.array[rate_len++] = rates[i];
2172 rate_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, var_pos, len);
2174 const u8 *rates = rate_ie + 2;
2175 for (i = 0; (i < rate_ie[1]) && (rate_len < MAC_RATESET_LEN); i++) {
2176 if (IS_BASIC_RATE(rates[i]))
2177 req->basic_rates.array[rate_len++] = rates[i];
2180 req->basic_rates.length = rate_len;
2181 #undef IS_BASIC_RATE
2183 // Sync buffer for FW
2184 if ((error = ecrnx_ipc_elem_var_allocs(ecrnx_hw, elem, bcn->len,
2185 DMA_TO_DEVICE, buf, NULL, NULL))) {
2189 /* Set parameters for the APM_START_REQ message */
2190 req->vif_idx = vif->vif_index;
2191 req->bcn_addr = elem->dma_addr;
2192 req->bcn_len = bcn->len;
2193 req->tim_oft = bcn->head_len;
2194 req->tim_len = bcn->tim_len;
2195 cfg80211_to_ecrnx_chan(&settings->chandef, &req->chan);
2196 req->bcn_int = settings->beacon_interval;
2197 if (settings->crypto.control_port)
2198 flags |= CONTROL_PORT_HOST;
2200 if (settings->crypto.control_port_no_encrypt)
2201 flags |= CONTROL_PORT_NO_ENC;
2203 if (use_pairwise_key(&settings->crypto))
2204 flags |= WPA_WPA2_IN_USE;
2206 if (settings->crypto.control_port_ethertype)
2207 req->ctrl_port_ethertype = settings->crypto.control_port_ethertype;
2209 req->ctrl_port_ethertype = ETH_P_PAE;
2212 /* Send the APM_START_REQ message to LMAC FW */
2213 return ecrnx_send_msg(ecrnx_hw, req, 1, APM_START_CFM, cfm);
2216 int ecrnx_send_apm_stop_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif)
2218 struct apm_stop_req *req;
2220 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2222 /* Build the APM_STOP_REQ message */
2223 req = ecrnx_msg_zalloc(APM_STOP_REQ, TASK_APM, DRV_TASK_ID,
2224 sizeof(struct apm_stop_req));
2228 /* Set parameters for the APM_STOP_REQ message */
2229 req->vif_idx = vif->vif_index;
2231 /* Send the APM_STOP_REQ message to LMAC FW */
2232 return ecrnx_send_msg(ecrnx_hw, req, 1, APM_STOP_CFM, NULL);
2235 int ecrnx_send_apm_probe_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2236 struct ecrnx_sta *sta, struct apm_probe_client_cfm *cfm)
2238 struct apm_probe_client_req *req;
2240 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2242 req = ecrnx_msg_zalloc(APM_PROBE_CLIENT_REQ, TASK_APM, DRV_TASK_ID,
2243 sizeof(struct apm_probe_client_req));
2247 req->vif_idx = vif->vif_index;
2248 req->sta_idx = sta->sta_idx;
2250 /* Send the APM_PROBE_CLIENT_REQ message to UMAC FW */
2251 return ecrnx_send_msg(ecrnx_hw, req, 1, APM_PROBE_CLIENT_CFM, cfm);
2253 int ecrnx_send_scanu_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif,
2254 struct cfg80211_scan_request *param)
2256 struct scanu_start_req *req;
2257 int i, chan_num = 0;
2258 uint8_t chan_flags = 0;
2260 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2262 /* Build the SCANU_START_REQ message */
2263 req = ecrnx_msg_zalloc(SCANU_START_REQ, TASK_SCANU, DRV_TASK_ID,
2264 sizeof(struct scanu_start_req));
2268 /* Set parameters */
2269 req->vif_idx = ecrnx_vif->vif_index;
2270 req->chan_cnt = (u8)min_t(int, SCAN_CHANNEL_MAX, param->n_channels);
2271 req->ssid_cnt = (u8)min_t(int, SCAN_SSID_MAX, param->n_ssids);
2272 req->bssid = mac_addr_bcst;
2273 req->no_cck = param->no_cck;
2274 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
2275 if (param->duration_mandatory)
2276 req->duration = ieee80211_tu_to_usec(param->duration);
2279 if(param->n_ssids > SCAN_SSID_MAX){
2280 ECRNX_PRINT("%s:n_ssids: %d \n", __func__, param->n_ssids);
2281 for (i = 0; i < param->n_ssids; i++){
2282 print_hex_dump_bytes("[ecrnx]scan_req: ", DUMP_PREFIX_NONE, ¶m->ssids[i], param->ssids[i].ssid_len);
2283 ECRNX_PRINT("i:%d, ssid_len:%d \n", i, param->ssids[i].ssid_len);
2287 if (req->ssid_cnt == 0)
2288 chan_flags |= CHAN_NO_IR;
2289 for (i = 0; i < req->ssid_cnt; i++) {
2291 for (j = 0; j < param->ssids[i].ssid_len; j++)
2292 req->ssid[i].array[j] = param->ssids[i].ssid[j];
2293 req->ssid[i].length = param->ssids[i].ssid_len;
2296 if(req->ssid_cnt == 1 && param->ssids[0].ssid_len > 0)
2298 if (strcmp(req->ssid[0].array, "DIRECT-"))
2301 req->ssid[1].length = 0;
2307 if (ecrnx_ipc_elem_var_allocs(ecrnx_hw, &ecrnx_hw->scan_ie,
2308 param->ie_len, DMA_TO_DEVICE,
2309 NULL, param->ie, NULL))
2311 req->add_ie_len = param->ie_len;
2312 req->add_ies = ecrnx_hw->scan_ie.dma_addr;
2314 req->add_ie_len = 0;
2318 for (i = 0; i < req->chan_cnt; i++) {
2319 struct ieee80211_channel *chan = param->channels[i];
2324 req->chan[chan_num].band = chan->band;
2325 req->chan[chan_num].freq = chan->center_freq;
2326 req->chan[chan_num].flags = chan_flags | get_chan_flags(chan->flags);
2327 req->chan[chan_num].tx_power = chan_to_fw_pwr(chan->max_reg_power);
2329 //printk("--%d set ch, %d,%d,%d,%d\n", i, req->chan[i].band, req->chan[i].freq, req->chan[i].flags, req->chan[i].tx_power);
2331 req->chan_cnt = chan_num;
2332 /* Send the SCANU_START_REQ message to LMAC FW */
2333 return ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
2336 ecrnx_msg_free(ecrnx_hw, req);
2340 int ecrnx_send_scanu_cancel_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif)
2342 struct scanu_cancel_req *req = NULL;
2344 /* Build the SCANU_START_REQ message */
2345 req = ecrnx_msg_zalloc(SCANU_CANCEL_REQ, TASK_SCANU, DRV_TASK_ID,
2346 sizeof(struct scanu_cancel_req));
2351 req->vif_idx = ecrnx_vif->vif_index;
2352 ECRNX_PRINT("%s: vif_idx:%d; \n", __func__, req->vif_idx);
2353 return ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
2356 int ecrnx_send_apm_start_cac_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2357 struct cfg80211_chan_def *chandef,
2358 struct apm_start_cac_cfm *cfm)
2360 struct apm_start_cac_req *req;
2362 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2364 /* Build the APM_START_CAC_REQ message */
2365 req = ecrnx_msg_zalloc(APM_START_CAC_REQ, TASK_APM, DRV_TASK_ID,
2366 sizeof(struct apm_start_cac_req));
2370 /* Set parameters for the APM_START_CAC_REQ message */
2371 req->vif_idx = vif->vif_index;
2372 cfg80211_to_ecrnx_chan(chandef, &req->chan);
2374 /* Send the APM_START_CAC_REQ message to LMAC FW */
2375 return ecrnx_send_msg(ecrnx_hw, req, 1, APM_START_CAC_CFM, cfm);
2378 int ecrnx_send_apm_stop_cac_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif)
2380 struct apm_stop_cac_req *req;
2382 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2384 /* Build the APM_STOP_CAC_REQ message */
2385 req = ecrnx_msg_zalloc(APM_STOP_CAC_REQ, TASK_APM, DRV_TASK_ID,
2386 sizeof(struct apm_stop_cac_req));
2390 /* Set parameters for the APM_STOP_CAC_REQ message */
2391 req->vif_idx = vif->vif_index;
2393 /* Send the APM_STOP_CAC_REQ message to LMAC FW */
2394 return ecrnx_send_msg(ecrnx_hw, req, 1, APM_STOP_CAC_CFM, NULL);
2397 int ecrnx_send_mesh_start_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2398 const struct mesh_config *conf, const struct mesh_setup *setup,
2399 struct mesh_start_cfm *cfm)
2402 struct mesh_start_req *req;
2403 // Supported basic rates
2404 struct ieee80211_supported_band *band = ecrnx_hw->wiphy->bands[setup->chandef.chan->band];
2409 /* DMA Address to be unmapped after confirmation reception */
2412 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2414 /* Build the MESH_START_REQ message */
2415 req = ecrnx_msg_zalloc(MESH_START_REQ, TASK_MESH, DRV_TASK_ID,
2416 sizeof(struct mesh_start_req));
2421 req->vif_index = vif->vif_index;
2422 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2423 req->bcn_int = setup->beacon_interval;
2424 req->dtim_period = setup->dtim_period;
2426 req->mesh_id_len = setup->mesh_id_len;
2428 for (i = 0; i < setup->mesh_id_len; i++) {
2429 req->mesh_id[i] = *(setup->mesh_id + i);
2432 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2433 req->user_mpm = setup->user_mpm;
2435 req->is_auth = setup->is_authenticated;
2436 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
2437 req->auth_id = setup->auth_id;
2439 req->ie_len = setup->ie_len;
2441 if (setup->ie_len) {
2443 * Need to provide a Virtual Address to the MAC so that it can download the
2444 * additional information elements.
2446 req->ie_addr = dma_map_single(ecrnx_hw->dev, (void *)setup->ie,
2447 setup->ie_len, DMA_FROM_DEVICE);
2449 /* Check DMA mapping result */
2450 if (dma_mapping_error(ecrnx_hw->dev, req->ie_addr)) {
2451 ECRNX_ERR(KERN_CRIT "%s - DMA Mapping error on additional IEs\n", __func__);
2453 /* Consider there is no Additional IEs */
2456 /* Store DMA Address so that we can unmap the memory section once MESH_START_CFM is received */
2457 dma_addr = req->ie_addr;
2461 /* Provide rate information */
2462 req->basic_rates.length = 0;
2463 for (i = 0; i < band->n_bitrates; i++) {
2464 u16 rate = band->bitrates[i].bitrate;
2466 /* Read value is in in units of 100 Kbps, provided value is in units
2467 * of 1Mbps, and multiplied by 2 so that 5.5 becomes 11 */
2468 rate = (rate << 1) / 10;
2470 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
2471 if (setup->basic_rates & CO_BIT(i)) {
2476 req->basic_rates.array[i] = (u8)rate;
2477 req->basic_rates.length++;
2480 /* Provide channel information */
2481 cfg80211_to_ecrnx_chan(&setup->chandef, &req->chan);
2483 /* Send the MESH_START_REQ message to UMAC FW */
2484 status = ecrnx_send_msg(ecrnx_hw, req, 1, MESH_START_CFM, cfm);
2486 /* Unmap DMA area */
2487 if (setup->ie_len) {
2488 dma_unmap_single(ecrnx_hw->dev, dma_addr, setup->ie_len, DMA_TO_DEVICE);
2491 /* Return the status */
2495 int ecrnx_send_mesh_stop_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2496 struct mesh_stop_cfm *cfm)
2499 struct mesh_stop_req *req;
2501 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2503 /* Build the MESH_STOP_REQ message */
2504 req = ecrnx_msg_zalloc(MESH_STOP_REQ, TASK_MESH, DRV_TASK_ID,
2505 sizeof(struct mesh_stop_req));
2510 req->vif_idx = vif->vif_index;
2512 /* Send the MESH_STOP_REQ message to UMAC FW */
2513 return ecrnx_send_msg(ecrnx_hw, req, 1, MESH_STOP_CFM, cfm);
2516 int ecrnx_send_mesh_update_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2517 u32 mask, const struct mesh_config *p_mconf, struct mesh_update_cfm *cfm)
2520 struct mesh_update_req *req;
2521 // Keep only bit for fields which can be updated
2522 u32 supp_mask = (mask << 1) & (CO_BIT(NL80211_MESHCONF_GATE_ANNOUNCEMENTS)
2523 | CO_BIT(NL80211_MESHCONF_HWMP_ROOTMODE)
2524 | CO_BIT(NL80211_MESHCONF_FORWARDING)
2525 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2526 | CO_BIT(NL80211_MESHCONF_POWER_MODE)
2531 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2537 /* Build the MESH_UPDATE_REQ message */
2538 req = ecrnx_msg_zalloc(MESH_UPDATE_REQ, TASK_MESH, DRV_TASK_ID,
2539 sizeof(struct mesh_update_req));
2545 req->vif_idx = vif->vif_index;
2547 if (supp_mask & CO_BIT(NL80211_MESHCONF_GATE_ANNOUNCEMENTS))
2549 req->flags |= CO_BIT(MESH_UPDATE_FLAGS_GATE_MODE_BIT);
2550 req->gate_announ = p_mconf->dot11MeshGateAnnouncementProtocol;
2553 if (supp_mask & CO_BIT(NL80211_MESHCONF_HWMP_ROOTMODE))
2555 req->flags |= CO_BIT(MESH_UPDATE_FLAGS_ROOT_MODE_BIT);
2556 req->root_mode = p_mconf->dot11MeshHWMPRootMode;
2559 if (supp_mask & CO_BIT(NL80211_MESHCONF_FORWARDING))
2561 req->flags |= CO_BIT(MESH_UPDATE_FLAGS_MESH_FWD_BIT);
2562 req->mesh_forward = p_mconf->dot11MeshForwarding;
2564 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
2565 if (supp_mask & CO_BIT(NL80211_MESHCONF_POWER_MODE))
2567 req->flags |= CO_BIT(MESH_UPDATE_FLAGS_LOCAL_PSM_BIT);
2568 req->local_ps_mode = p_mconf->power_mode;
2571 /* Send the MESH_UPDATE_REQ message to UMAC FW */
2572 return ecrnx_send_msg(ecrnx_hw, req, 1, MESH_UPDATE_CFM, cfm);
2575 int ecrnx_send_mesh_peer_info_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2576 u8 sta_idx, struct mesh_peer_info_cfm *cfm)
2579 struct mesh_peer_info_req *req;
2581 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2583 /* Build the MESH_PEER_INFO_REQ message */
2584 req = ecrnx_msg_zalloc(MESH_PEER_INFO_REQ, TASK_MESH, DRV_TASK_ID,
2585 sizeof(struct mesh_peer_info_req));
2590 req->sta_idx = sta_idx;
2592 /* Send the MESH_PEER_INFO_REQ message to UMAC FW */
2593 return ecrnx_send_msg(ecrnx_hw, req, 1, MESH_PEER_INFO_CFM, cfm);
2596 void ecrnx_send_mesh_peer_update_ntf(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif,
2597 u8 sta_idx, u8 mlink_state)
2600 struct mesh_peer_update_ntf *ntf;
2602 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2604 /* Build the MESH_PEER_UPDATE_NTF message */
2605 ntf = ecrnx_msg_zalloc(MESH_PEER_UPDATE_NTF, TASK_MESH, DRV_TASK_ID,
2606 sizeof(struct mesh_peer_update_ntf));
2609 ntf->vif_idx = vif->vif_index;
2610 ntf->sta_idx = sta_idx;
2611 ntf->state = mlink_state;
2613 /* Send the MESH_PEER_INFO_REQ message to UMAC FW */
2614 ecrnx_send_msg(ecrnx_hw, ntf, 0, 0, NULL);
2618 void ecrnx_send_mesh_path_create_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif, u8 *tgt_addr)
2620 struct mesh_path_create_req *req;
2621 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2623 /* Check if we are already waiting for a confirmation */
2624 if (vif->ap.flags & ECRNX_AP_CREATE_MESH_PATH)
2627 /* Build the MESH_PATH_CREATE_REQ message */
2628 req = ecrnx_msg_zalloc(MESH_PATH_CREATE_REQ, TASK_MESH, DRV_TASK_ID,
2629 sizeof(struct mesh_path_create_req));
2633 req->vif_idx = vif->vif_index;
2634 memcpy(&req->tgt_mac_addr, tgt_addr, ETH_ALEN);
2636 vif->ap.flags |= ECRNX_AP_CREATE_MESH_PATH;
2638 /* Send the MESH_PATH_CREATE_REQ message to UMAC FW */
2639 ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
2642 int ecrnx_send_mesh_path_update_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif, const u8 *tgt_addr,
2643 const u8 *p_nhop_addr, struct mesh_path_update_cfm *cfm)
2646 struct mesh_path_update_req *req;
2648 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2650 /* Build the MESH_PATH_UPDATE_REQ message */
2651 req = ecrnx_msg_zalloc(MESH_PATH_UPDATE_REQ, TASK_MESH, DRV_TASK_ID,
2652 sizeof(struct mesh_path_update_req));
2657 req->delete = (p_nhop_addr == NULL);
2658 req->vif_idx = vif->vif_index;
2659 memcpy(&req->tgt_mac_addr, tgt_addr, ETH_ALEN);
2662 memcpy(&req->nhop_mac_addr, p_nhop_addr, ETH_ALEN);
2665 /* Send the MESH_PATH_UPDATE_REQ message to UMAC FW */
2666 return ecrnx_send_msg(ecrnx_hw, req, 1, MESH_PATH_UPDATE_CFM, cfm);
2669 void ecrnx_send_mesh_proxy_add_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *vif, u8 *ext_addr)
2672 struct mesh_proxy_add_req *req;
2674 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2676 /* Build the MESH_PROXY_ADD_REQ message */
2677 req = ecrnx_msg_zalloc(MESH_PROXY_ADD_REQ, TASK_MESH, DRV_TASK_ID,
2678 sizeof(struct mesh_proxy_add_req));
2681 req->vif_idx = vif->vif_index;
2682 memcpy(&req->ext_sta_addr, ext_addr, ETH_ALEN);
2684 /* Send the MESH_PROXY_ADD_REQ message to UMAC FW */
2685 ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
2689 int ecrnx_send_tdls_peer_traffic_ind_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif)
2691 struct tdls_peer_traffic_ind_req *tdls_peer_traffic_ind_req;
2693 if (!ecrnx_vif->sta.tdls_sta)
2696 /* Build the TDLS_PEER_TRAFFIC_IND_REQ message */
2697 tdls_peer_traffic_ind_req = ecrnx_msg_zalloc(TDLS_PEER_TRAFFIC_IND_REQ, TASK_TDLS, DRV_TASK_ID,
2698 sizeof(struct tdls_peer_traffic_ind_req));
2700 if (!tdls_peer_traffic_ind_req)
2703 /* Set parameters for the TDLS_PEER_TRAFFIC_IND_REQ message */
2704 tdls_peer_traffic_ind_req->vif_index = ecrnx_vif->vif_index;
2705 tdls_peer_traffic_ind_req->sta_idx = ecrnx_vif->sta.tdls_sta->sta_idx;
2706 memcpy(&(tdls_peer_traffic_ind_req->peer_mac_addr.array[0]),
2707 ecrnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN);
2708 tdls_peer_traffic_ind_req->dialog_token = 0; // check dialog token value
2709 tdls_peer_traffic_ind_req->last_tid = ecrnx_vif->sta.tdls_sta->tdls.last_tid;
2710 tdls_peer_traffic_ind_req->last_sn = ecrnx_vif->sta.tdls_sta->tdls.last_sn;
2712 /* Send the TDLS_PEER_TRAFFIC_IND_REQ message to LMAC FW */
2713 return ecrnx_send_msg(ecrnx_hw, tdls_peer_traffic_ind_req, 0, 0, NULL);
2716 int ecrnx_send_config_monitor_req(struct ecrnx_hw *ecrnx_hw,
2717 struct cfg80211_chan_def *chandef,
2718 struct me_config_monitor_cfm *cfm)
2720 struct me_config_monitor_req *req;
2722 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2724 /* Build the ME_CONFIG_MONITOR_REQ message */
2725 req = ecrnx_msg_zalloc(ME_CONFIG_MONITOR_REQ, TASK_ME, DRV_TASK_ID,
2726 sizeof(struct me_config_monitor_req));
2731 req->chan_set = true;
2732 cfg80211_to_ecrnx_chan(chandef, &req->chan);
2734 if (ecrnx_hw->phy.limit_bw)
2735 limit_chan_bw(&req->chan.type, req->chan.prim20_freq, &req->chan.center1_freq);
2737 req->chan_set = false;
2740 req->uf = ecrnx_hw->mod_params->uf;
2742 /* Send the ME_CONFIG_MONITOR_REQ message to FW */
2743 return ecrnx_send_msg(ecrnx_hw, req, 1, ME_CONFIG_MONITOR_CFM, cfm);
2745 #endif /* CONFIG_ECRNX_FULLMAC */
2747 #ifdef CONFIG_ECRNX_P2P
2748 int ecrnx_send_p2p_start_listen_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif, unsigned int duration)
2750 struct p2p_listen_start_req *req;
2751 struct ecrnx_p2p_listen *p2p_listen = &ecrnx_hw->p2p_listen;
2754 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2756 if(p2p_listen->listen_started)
2758 ECRNX_ERR("P2P listen already ongoing\n");
2762 p2p_listen->ecrnx_vif = ecrnx_vif;
2763 p2p_listen->listen_duration = duration;
2765 if(ecrnx_hw->scan_request)
2767 ECRNX_ERR("Delaying p2p listen until scan done\n");
2771 /* Build the P2P_LISTEN_START_REQ message */
2772 req = ecrnx_msg_zalloc(P2P_LISTEN_START_REQ, TASK_P2P_LISTEN, DRV_TASK_ID,
2773 sizeof(struct p2p_listen_start_req));
2777 req->vif_idx = ecrnx_vif->vif_index;
2779 rc = ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
2783 p2p_listen->listen_started = 1;
2788 int ecrnx_send_p2p_cancel_listen_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif)
2790 struct p2p_cancel_listen_req *req;
2791 struct ecrnx_p2p_listen *p2p_listen = &ecrnx_hw->p2p_listen;
2793 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2795 /* Build the P2P_CANCEL_LISTEN_REQ message */
2796 req = ecrnx_msg_zalloc(P2P_CANCEL_LISTEN_REQ, TASK_P2P_LISTEN, DRV_TASK_ID,
2797 sizeof(struct p2p_cancel_listen_req));
2801 req->vif_idx = ecrnx_vif->vif_index;
2802 p2p_listen->listen_started = 0;
2803 //return rwnx_send_msg(rwnx_hw, req, 1, P2P_CANCEL_LISTEN_CFM, NULL);
2804 ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
2811 int ecrnx_send_tdls_chan_switch_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_vif *ecrnx_vif,
2812 struct ecrnx_sta *ecrnx_sta, bool sta_initiator,
2813 u8 oper_class, struct cfg80211_chan_def *chandef,
2814 struct tdls_chan_switch_cfm *cfm)
2816 struct tdls_chan_switch_req *tdls_chan_switch_req;
2818 #ifdef CONFIG_ECRNX_SOFTMAC
2819 /* Check if channel switch already enabled on a TDLS peer */
2820 if (ecrnx_hw->tdls_info.chsw_en) {
2821 ECRNX_ERR("TDLS channel switch already enabled for another TDLS station\n");
2826 /* Build the TDLS_CHAN_SWITCH_REQ message */
2827 tdls_chan_switch_req = ecrnx_msg_zalloc(TDLS_CHAN_SWITCH_REQ, TASK_TDLS, DRV_TASK_ID,
2828 sizeof(struct tdls_chan_switch_req));
2830 if (!tdls_chan_switch_req)
2833 /* Set parameters for the TDLS_CHAN_SWITCH_REQ message */
2834 tdls_chan_switch_req->vif_index = ecrnx_vif->vif_index;
2835 tdls_chan_switch_req->sta_idx = ecrnx_sta->sta_idx;
2836 memcpy(&(tdls_chan_switch_req->peer_mac_addr.array[0]),
2837 ecrnx_sta_addr(ecrnx_sta), ETH_ALEN);
2838 tdls_chan_switch_req->initiator = sta_initiator;
2839 cfg80211_to_ecrnx_chan(chandef, &tdls_chan_switch_req->chan);
2840 tdls_chan_switch_req->op_class = oper_class;
2842 /* Send the TDLS_CHAN_SWITCH_REQ message to LMAC FW */
2843 return ecrnx_send_msg(ecrnx_hw, tdls_chan_switch_req, 1, TDLS_CHAN_SWITCH_CFM, cfm);
2846 int ecrnx_send_tdls_cancel_chan_switch_req(struct ecrnx_hw *ecrnx_hw,
2847 struct ecrnx_vif *ecrnx_vif,
2848 struct ecrnx_sta *ecrnx_sta,
2849 struct tdls_cancel_chan_switch_cfm *cfm)
2851 struct tdls_cancel_chan_switch_req *tdls_cancel_chan_switch_req;
2853 /* Build the TDLS_CHAN_SWITCH_REQ message */
2854 tdls_cancel_chan_switch_req = ecrnx_msg_zalloc(TDLS_CANCEL_CHAN_SWITCH_REQ, TASK_TDLS, DRV_TASK_ID,
2855 sizeof(struct tdls_cancel_chan_switch_req));
2856 if (!tdls_cancel_chan_switch_req)
2859 /* Set parameters for the TDLS_CHAN_SWITCH_REQ message */
2860 tdls_cancel_chan_switch_req->vif_index = ecrnx_vif->vif_index;
2861 tdls_cancel_chan_switch_req->sta_idx = ecrnx_sta->sta_idx;
2862 memcpy(&(tdls_cancel_chan_switch_req->peer_mac_addr.array[0]),
2863 ecrnx_sta_addr(ecrnx_sta), ETH_ALEN);
2865 /* Send the TDLS_CHAN_SWITCH_REQ message to LMAC FW */
2866 return ecrnx_send_msg(ecrnx_hw, tdls_cancel_chan_switch_req, 1, TDLS_CANCEL_CHAN_SWITCH_CFM, cfm);
2869 #ifdef CONFIG_ECRNX_BFMER
2870 #ifdef CONFIG_ECRNX_SOFTMAC
2871 void ecrnx_send_bfmer_enable(struct ecrnx_hw *ecrnx_hw, struct ieee80211_sta *sta)
2873 void ecrnx_send_bfmer_enable(struct ecrnx_hw *ecrnx_hw, struct ecrnx_sta *ecrnx_sta,
2874 const struct ieee80211_vht_cap *vht_cap)
2875 #endif /* CONFIG_ECRNX_SOFTMAC*/
2877 struct mm_bfmer_enable_req *bfmer_en_req;
2878 #ifdef CONFIG_ECRNX_SOFTMAC
2879 struct ecrnx_sta *ecrnx_sta = (struct ecrnx_sta *)&sta->drv_priv;
2882 __le32 vht_capability;
2884 #endif /* CONFIG_ECRNX_SOFTMAC */
2886 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2888 #ifdef CONFIG_ECRNX_SOFTMAC
2889 if (!sta->vht_cap.vht_supported) {
2892 #endif /* CONFIG_ECRNX_SOFTMAC */
2896 #ifdef CONFIG_ECRNX_SOFTMAC
2897 vht_capability = sta->vht_cap.cap;
2899 vht_capability = vht_cap->vht_cap_info;
2900 #endif /* CONFIG_ECRNX_SOFTMAC */
2902 if (!(vht_capability & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) {
2906 #ifdef CONFIG_ECRNX_FULLMAC
2907 rx_nss = ecrnx_bfmer_get_rx_nss(vht_cap);
2908 #endif /* CONFIG_ECRNX_FULLMAC */
2910 /* Allocate a structure that will contain the beamforming report */
2911 if (ecrnx_bfmer_report_add(ecrnx_hw, ecrnx_sta, ECRNX_BFMER_REPORT_SPACE_SIZE))
2916 /* Build the MM_BFMER_ENABLE_REQ message */
2917 bfmer_en_req = ecrnx_msg_zalloc(MM_BFMER_ENABLE_REQ, TASK_MM, DRV_TASK_ID,
2918 sizeof(struct mm_bfmer_enable_req));
2920 /* Check message allocation */
2921 if (!bfmer_en_req) {
2922 /* Free memory allocated for the report */
2923 ecrnx_bfmer_report_del(ecrnx_hw, ecrnx_sta);
2925 /* Do not use beamforming */
2929 /* Provide DMA address to the MAC */
2930 bfmer_en_req->host_bfr_addr = ecrnx_sta->bfm_report->dma_addr;
2931 bfmer_en_req->host_bfr_size = ECRNX_BFMER_REPORT_SPACE_SIZE;
2932 bfmer_en_req->sta_idx = ecrnx_sta->sta_idx;
2933 #ifdef CONFIG_ECRNX_SOFTMAC
2934 bfmer_en_req->aid = sta->aid;
2935 bfmer_en_req->rx_nss = sta->rx_nss;
2937 bfmer_en_req->aid = ecrnx_sta->aid;
2938 bfmer_en_req->rx_nss = rx_nss;
2939 #endif /* CONFIG_ECRNX_SOFTMAC */
2941 if (vht_capability & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) {
2942 bfmer_en_req->vht_mu_bfmee = true;
2944 bfmer_en_req->vht_mu_bfmee = false;
2947 /* Send the MM_BFMER_EN_REQ message to LMAC FW */
2948 ecrnx_send_msg(ecrnx_hw, bfmer_en_req, 0, 0, NULL);
2954 #ifdef CONFIG_ECRNX_MUMIMO_TX
2955 int ecrnx_send_mu_group_update_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_sta *ecrnx_sta)
2957 struct mm_mu_group_update_req *req;
2958 int group_id, i = 0;
2961 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
2963 /* Build the MM_MU_GROUP_UPDATE_REQ message */
2964 req = ecrnx_msg_zalloc(MM_MU_GROUP_UPDATE_REQ, TASK_MM, DRV_TASK_ID,
2965 sizeof(struct mm_mu_group_update_req) +
2966 ecrnx_sta->group_info.cnt * sizeof(req->groups[0]));
2968 /* Check message allocation */
2972 /* Go through the groups the STA belongs to */
2973 group_sta_for_each(ecrnx_sta, group_id, map) {
2974 int user_pos = ecrnx_mu_group_sta_get_pos(ecrnx_hw, ecrnx_sta, group_id);
2976 if (WARN((i >= ecrnx_sta->group_info.cnt),
2977 "STA%d: Too much group (%d)\n",
2978 ecrnx_sta->sta_idx, i + 1))
2981 req->groups[i].group_id = group_id;
2982 req->groups[i].user_pos = user_pos;
2987 req->group_cnt = ecrnx_sta->group_info.cnt;
2988 req->sta_idx = ecrnx_sta->sta_idx;
2990 /* Send the MM_MU_GROUP_UPDATE_REQ message to LMAC FW */
2991 return ecrnx_send_msg(ecrnx_hw, req, 1, MM_MU_GROUP_UPDATE_CFM, NULL);
2993 #endif /* CONFIG_ECRNX_MUMIMO_TX */
2994 #endif /* CONFIG_ECRNX_BFMER */
2996 /**********************************************************************
2998 *********************************************************************/
2999 int ecrnx_send_dbg_trigger_req(struct ecrnx_hw *ecrnx_hw, char *msg)
3001 struct mm_dbg_trigger_req *req;
3003 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3005 /* Build the MM_DBG_TRIGGER_REQ message */
3006 req = ecrnx_msg_zalloc(MM_DBG_TRIGGER_REQ, TASK_MM, DRV_TASK_ID,
3007 sizeof(struct mm_dbg_trigger_req));
3011 /* Set parameters for the MM_DBG_TRIGGER_REQ message */
3012 strncpy(req->error, msg, sizeof(req->error));
3014 /* Send the MM_DBG_TRIGGER_REQ message to LMAC FW */
3015 return ecrnx_send_msg(ecrnx_hw, req, 0, -1, NULL);
3018 int ecrnx_send_dbg_mem_read_req(struct ecrnx_hw *ecrnx_hw, u32 mem_addr,
3019 struct dbg_mem_read_cfm *cfm)
3021 struct dbg_mem_read_req *mem_read_req;
3023 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3025 /* Build the DBG_MEM_READ_REQ message */
3026 mem_read_req = ecrnx_msg_zalloc(DBG_MEM_READ_REQ, TASK_DBG, DRV_TASK_ID,
3027 sizeof(struct dbg_mem_read_req));
3031 /* Set parameters for the DBG_MEM_READ_REQ message */
3032 mem_read_req->memaddr = mem_addr;
3034 /* Send the DBG_MEM_READ_REQ message to LMAC FW */
3035 return ecrnx_send_msg(ecrnx_hw, mem_read_req, 1, DBG_MEM_READ_CFM, cfm);
3038 int ecrnx_send_dbg_mem_write_req(struct ecrnx_hw *ecrnx_hw, u32 mem_addr,
3041 struct dbg_mem_write_req *mem_write_req;
3043 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3045 /* Build the DBG_MEM_WRITE_REQ message */
3046 mem_write_req = ecrnx_msg_zalloc(DBG_MEM_WRITE_REQ, TASK_DBG, DRV_TASK_ID,
3047 sizeof(struct dbg_mem_write_req));
3051 /* Set parameters for the DBG_MEM_WRITE_REQ message */
3052 mem_write_req->memaddr = mem_addr;
3053 mem_write_req->memdata = mem_data;
3055 /* Send the DBG_MEM_WRITE_REQ message to LMAC FW */
3056 return ecrnx_send_msg(ecrnx_hw, mem_write_req, 1, DBG_MEM_WRITE_CFM, NULL);
3059 int ecrnx_send_dbg_set_mod_filter_req(struct ecrnx_hw *ecrnx_hw, u32 filter)
3061 struct dbg_set_mod_filter_req *set_mod_filter_req;
3063 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3065 /* Build the DBG_SET_MOD_FILTER_REQ message */
3066 set_mod_filter_req =
3067 ecrnx_msg_zalloc(DBG_SET_MOD_FILTER_REQ, TASK_DBG, DRV_TASK_ID,
3068 sizeof(struct dbg_set_mod_filter_req));
3069 if (!set_mod_filter_req)
3072 /* Set parameters for the DBG_SET_MOD_FILTER_REQ message */
3073 set_mod_filter_req->mod_filter = filter;
3075 /* Send the DBG_SET_MOD_FILTER_REQ message to LMAC FW */
3076 return ecrnx_send_msg(ecrnx_hw, set_mod_filter_req, 1, DBG_SET_MOD_FILTER_CFM, NULL);
3079 int ecrnx_send_dbg_set_sev_filter_req(struct ecrnx_hw *ecrnx_hw, u32 filter)
3081 struct dbg_set_sev_filter_req *set_sev_filter_req;
3083 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3085 /* Build the DBG_SET_SEV_FILTER_REQ message */
3086 set_sev_filter_req =
3087 ecrnx_msg_zalloc(DBG_SET_SEV_FILTER_REQ, TASK_DBG, DRV_TASK_ID,
3088 sizeof(struct dbg_set_sev_filter_req));
3089 if (!set_sev_filter_req)
3092 /* Set parameters for the DBG_SET_SEV_FILTER_REQ message */
3093 set_sev_filter_req->sev_filter = filter;
3095 /* Send the DBG_SET_SEV_FILTER_REQ message to LMAC FW */
3096 return ecrnx_send_msg(ecrnx_hw, set_sev_filter_req, 1, DBG_SET_SEV_FILTER_CFM, NULL);
3099 int ecrnx_send_dbg_get_sys_stat_req(struct ecrnx_hw *ecrnx_hw,
3100 struct dbg_get_sys_stat_cfm *cfm)
3104 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3106 /* Allocate the message */
3107 req = ecrnx_msg_zalloc(DBG_GET_SYS_STAT_REQ, TASK_DBG, DRV_TASK_ID, 0);
3111 /* Send the DBG_MEM_READ_REQ message to LMAC FW */
3112 return ecrnx_send_msg(ecrnx_hw, req, 1, DBG_GET_SYS_STAT_CFM, cfm);
3115 int ecrnx_send_cfg_rssi_req(struct ecrnx_hw *ecrnx_hw, u8 vif_index, int rssi_thold, u32 rssi_hyst)
3117 struct mm_cfg_rssi_req *req;
3119 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3121 /* Build the MM_CFG_RSSI_REQ message */
3122 req = ecrnx_msg_zalloc(MM_CFG_RSSI_REQ, TASK_MM, DRV_TASK_ID,
3123 sizeof(struct mm_cfg_rssi_req));
3127 /* Set parameters for the MM_CFG_RSSI_REQ message */
3128 req->vif_index = vif_index;
3129 req->rssi_thold = (s8)rssi_thold;
3130 req->rssi_hyst = (u8)rssi_hyst;
3132 /* Send the MM_CFG_RSSI_REQ message to LMAC FW */
3133 return ecrnx_send_msg(ecrnx_hw, req, 0, 0, NULL);
3136 extern bool set_gain;
3137 int ecrnx_send_set_gain_delta_req(struct ecrnx_hw *ecrnx_hw)
3141 if (set_gain != true)
3144 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3146 /* Build the MM_SET_GAIN_DELTA_REQ message */
3147 delta = ecrnx_msg_zalloc(MM_SET_GAIN_DELTA_REQ, TASK_MM, DRV_TASK_ID,
3148 GAIN_DELTA_CFG_BUF_SIZE);
3152 /* Set parameters for the MM_SET_GAIN_DELTA_REQ message */
3153 memset(delta, 0, GAIN_DELTA_CFG_BUF_SIZE);
3154 memcpy(delta, gain_delta, GAIN_DELTA_CFG_BUF_SIZE);
3156 /* Send the MM_SET_GAIN_DELTA_REQ message to LMAC FW */
3157 return ecrnx_send_msg(ecrnx_hw, delta, 0, MM_SET_GAIN_DELTA_CFM, NULL);
3160 int ecrnx_send_cal_result_get_req(struct ecrnx_hw *ecrnx_hw, void *cfm)
3164 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
3165 /* calibration result get REQ has no parameter */
3166 void_param = ecrnx_msg_zalloc(MM_GET_CAL_RESULT_REQ, TASK_MM, DRV_TASK_ID, 0);
3170 return ecrnx_send_msg(ecrnx_hw, void_param, 1, MM_GET_CAL_RESULT_CFM, cfm);