Files
kunlun/plc/halmac/vdev/mac_vdev.c
2024-09-28 14:24:04 +08:00

1733 lines
48 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "mac_vdev_api.h"
#include "mac_vdev.h"
#include "mac_pdev.h"
#include "iot_errno.h"
#include "iot_mem_pool.h"
#include "mac_msg.h"
#include "mac.h"
#include "mac_peer.h"
#include "mac_sched.h"
#include "mac_sched_hw.h"
#include "mac_cmn_hw.h"
#include "mac_tx_hw.h" /* for flush */
#include "mac_desc_engine.h"
#include "mac_rx_buf_ring.h"
#include "mac_cert_test.h"
#include "plc_cert_test.h"
#include "iot_io.h"
#include "mac_rx_hw.h"
#include "hw_war.h"
#include "iot_gptmr_api.h"
#include "rate_control.h"
#include "mac_reset.h"
#include "mac_init_api.h"
#include "phy_chn.h"
#include "phy_txrx_pwr.h"
#include "phy_phase.h"
#include "plc_mme_zero_cross.h"
#include "mac_ppm_scan.h"
#include "mac_pm.h"
#include "mac_tx_power.h"
#include "mac_channel.h"
#include "mac_stream.h"
#include "mac_mm_sniffer.h"
#include "mac_check_spur_sta.h"
#include "mac_rf_vdev.h"
#include "mac_rf_sched.h"
#include "mac_rf_tx_hw.h"
#include "mac_rf.h"
#include "mac_rf_scan.h"
#include "mac_rf_tx_power.h"
#if HPLC_RF_DEV_SUPPORT
#include "mac_rf_common_hw.h"
#endif
#include "hw_phy_init.h"
#include "iot_oem_api.h"
static void mac_vdev_set_force_phase(mac_vdev_t *vdev,
uint8_t force_en, uint8_t force_phase)
{
IOT_ASSERT(vdev);
uint8_t node_role = mac_vdev_cfg_get_node_role(vdev);
if (PLC_DEV_ROLE_CCO == node_role) {
cfg_phy_tx_phase_select(force_en, force_phase);
} else {
phy_set_trx_switch_gpio_phase(force_phase);
}
}
/*
* @brief vdev_set_sec_key() - set security key
* @param vdev: mac vdev pointer
* @param sec_key: point to sec_key infomation
*/
static void vdev_set_sec_key(mac_vdev_t *vdev, mac_sec_key_t *sec_key)
{
if (NULL == vdev->sec_key) {
iot_printf("vdev sec_key is null\n");
goto out;
}
if ((sec_key->encrypt_type > MAC_ENCRYPT_IEEE1901_1_PB_AES_CBC) ||
(sec_key->encrypt_type < MAC_ENCRYPT_SG_MSDU_AES_CBC)) {
iot_printf("vdev set sec algorithm type is error\n");
goto out;
}
if (sec_key->key_type == ENCRYPT_KEY_TYPE_NONE) {
iot_printf("vdev set sec key type is error\n");
goto out;
}
if ((sec_key->keybits != MAC_ENCRYPT_KEY_BIT_LEN_128) &&
(sec_key->keybits != MAC_ENCRYPT_KEY_BIT_LEN_192) &&
(sec_key->keybits != MAC_ENCRYPT_KEY_BIT_LEN_256)) {
iot_printf("vdev set sec keybits = %d is error\n", sec_key->keybits);
goto out;
}
os_mem_cpy(vdev->sec_key, sec_key, sizeof(mac_sec_key_t));
out:
return;
}
tei_t vdev_get_tei(mac_vdev_t* vdev)
{
if (NULL == vdev) {
IOT_ASSERT(0);
return PLC_TEI_INVAL;
}
mac_peer_t *self_peer = (mac_peer_t*)vdev->self_peer;
if (self_peer) {
return (tei_t)self_peer->tei;
}
return PLC_TEI_INVAL;
}
void vdev_set_tei(mac_vdev_t* vdev, tei_t tei)
{
IOT_ASSERT(vdev);
mac_peer_t *self_peer = (mac_peer_t*)vdev->self_peer;
if (self_peer) {
/* if not reduced vdev, update hw tei */
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
self_peer->tei = tei;
mac_config_tei(vdev, tei);
}
}
}
uint32_t mac_create_vdev(uint8_t pdev_id, uint8_t *vdev_id_created,
mac_vdev_cfg_t *cfg)
{
uint32_t ret = 0;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_CREATE_VDEV;
msg->msg.data1 = pdev_id;
msg->msg.data2 = cfg;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
ret = msg->msg.data1;
*vdev_id_created = (uint8_t)(((uint32_t)msg->msg.data2) & 0xFF);
mac_free_msg_sync(msg);
out:
return ret;
}
uint32_t mac_create_vdev_internal(uint8_t pdev_id, uint8_t *vdev_id_created,
mac_vdev_cfg_t *cfg)
{
uint32_t cur_vdev_num, vdev_id = MAX_VDEV_NUM, ret;
mac_vdev_t *vdev;
mac_pdev_t *pdev;
if (pdev_id >= MAX_PDEV_NUM) {
return ERR_INVAL;
}
pdev = get_pdev_ptr(pdev_id);
if (!pdev) {
return ERR_INVAL;
}
cur_vdev_num = pdev->cur_vdev_num;
IOT_ASSERT(cur_vdev_num + 1 <= MAX_VDEV_NUM);
for (uint32_t i = 0; i < MAX_VDEV_NUM; i++) {
if (pdev->vdev[i] == NULL) {
vdev_id = i;
break;
}
}
IOT_ASSERT(vdev_id < MAX_VDEV_NUM);
vdev = iot_mem_pool_alloc(&pdev->vdev_pool);
if (vdev == NULL) {
return ERR_NOMEM;
}
os_mem_set(vdev, 0, sizeof(*vdev));
pdev->vdev[vdev_id] = vdev;
pdev->cur_vdev_num++;
vdev->vdev_id = (vdevid_t)vdev_id;
vdev->ref_pdev_id = pdev_id;
/* create self peer */
ret = mac_peer_alloc(vdev, PLC_TEI_INVAL, \
1, 1, 0, 0, (mac_peer_t **)&vdev->self_peer);
IOT_ASSERT(ret == 0);
/* create bcast peer */
ret = mac_peer_alloc(vdev, PLC_TEI_BCAST, \
0, 1, 0, 0, (mac_peer_t **)&vdev->bcast_peer);
IOT_ASSERT(ret == 0);
if (cfg) {
vdev->mac_vdev_cfg = *cfg;
if (cfg->node_role == PLC_DEV_ROLE_CCO) {
vdev_set_tei(vdev, PLC_TEI_CCO);
/* init logical phase of CCO role device */
vdev->l_phase1 = PLC_PHASE_ALL;
vdev->l_phase2 = PLC_PHASE_ALL;
vdev->l_phase3 = PLC_PHASE_ALL;
switch (cfg->p_phase_cnt) {
case 3:
vdev->l_phase3 = PLC_PHASE_C;
case 2:
vdev->l_phase2 = PLC_PHASE_B;
case 1:
vdev->l_phase1 = PLC_PHASE_A;
break;
default:
IOT_ASSERT(0);
break;
}
/* td tx nncco phase */
vdev->nncco_tx_3phase = (uint8_t)cfg->is_td_tx_nncco_3phase;
vdev->nncco_td_tx_phase = PLC_PHASE_A;
} else {
vdev_set_tei(vdev, PLC_TEI_INVAL);
/* sta role device logical phase will be inited later when upper
* layer plan to start the vdev. see mac_set_vdev_cfg_internal.
*/
IOT_ASSERT(cfg->p_phase_cnt == 1);
vdev->l_phase1 = PLC_PHASE_ALL;
vdev->l_phase2 = PLC_PHASE_ALL;
vdev->l_phase3 = PLC_PHASE_ALL;
}
}
*vdev_id_created = (uint8_t)vdev_id;
/* if this vdev not reduced, need create cfg and hw ctxt */
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
if (!vdev->sub_peer_bitmap) {
vdev->sub_peer_bitmap = os_mem_malloc(PLC_MAC_COMMON_MID,
sizeof(mac_tei_map_t));
}
IOT_ASSERT(vdev->sub_peer_bitmap);
mac_tei_map_reset((mac_tei_map_t *)vdev->sub_peer_bitmap);
/* init the beacon ctx */
mac_beacon_init(&vdev->bcn_ctx, vdev);
/* init the scheduler context */
mac_sched_init(vdev);
/* init mac rf info */
vdev->mac_rf = mac_rf_init();
/* init power cap */
mac_fix_power_init(vdev);
#if MAC_STREAM_TIMEOUT_SUPPORT
/*create timer for stream out*/
vdev->stream_timeout_timer = \
os_create_timer(PLC_MAC_RX_MID, true, \
mac_vdev_del_timeout_stream, vdev);
#endif
/* ppm per vdev should be init,
* because sometimes nid=0's cert
* bcn still be needed to sync ppm
*/
mac_ppm_init(&vdev->mac_ppm, phy_get_cal_ppm_in_pib(), 0);
/* rate control */
ra_init(vdev, RATE_ADAPTION_ENABLE);
} //if (!vdev->mac_vdev_cfg.is_reduced_vdev)
/* time stamp for record */
vdev->last_rx_ntb = 0;
vdev->last_tx_ntb = 0;
#if PLC_SUPPORT_DBG_PKT_MODE
/* init to allow send dbg pkt in rx only period */
vdev_set_block_dbg_pkt_4_rx_only(vdev, false);
#endif
#if CERT_WAR_TX_PWR == 1
vdev->cert_war_pwr = 0;
#endif
/* support rf dev */
if (cfg && !vdev->mac_vdev_cfg.is_reduced_vdev) {
ret = mac_create_rf_vdev_internal(pdev_id, vdev->vdev_id,
RF_PDEV_ID, &vdev->rf_vdev_id);
if (!ret) {
iot_printf("rf vdev creat success\n");
} else {
iot_printf("rf vdev creat fail\n");
}
}
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
vdev->sec_key = os_mem_malloc(PLC_MAC_COMMON_MID,
sizeof(mac_sec_key_t));
}
return 0;
}
mac_vdev_t *get_vdev_ptr(uint32_t pdev_id, uint32_t vdev_id) {
if (pdev_id >= MAX_PDEV_NUM || vdev_id >= MAX_VDEV_NUM) {
IOT_ASSERT(0);
return NULL;
}
return g_mac_pdev[pdev_id]->vdev[vdev_id];
}
uint32_t mac_start_vdev(uint8_t pdev_id, uint8_t vdev_id,
mac_vdev_start_cfg_t *cfg)
{
uint32_t ret = 0;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_START_VDEV;
msg->msg.data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->msg.data2 = cfg;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
ret = msg->msg.data1;
mac_free_msg_sync(msg);
out:
return ret;
}
uint32_t mac_start_vdev_internal(uint8_t pdev_id, uint8_t vdev_id,
mac_vdev_start_cfg_t *cfg)
{
uint64_t start_ntb;
mac_vdev_t *vdev;
mac_pdev_t *pdev_ptr = \
(mac_pdev_t *)g_mac_pdev[pdev_id];
if (cfg == NULL) {
return ERR_INVAL;
}
vdev = get_vdev_ptr(pdev_id, vdev_id);
if (vdev == NULL) {
return ERR_INVAL;
}
if (vdev->is_up) {
return ERR_OK;
}
// todo: temporary implementation for testing beacon receiving
vdev->start_cfg = *cfg;
#if CERT_WAR_TX_PWR == 1
/* check mac addr when start vdev */
vdev->cert_war_pwr = mac_cert_war_tx_pwr(cfg->mac_addr);
#endif
vdev->is_up = 1;
/* if this vdev not reduced, need init config and hw info */
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
/* clear rise power flag */
phy_rise_pwr_flag_set(false);
/* config local device role to HW */
mac_config_role(vdev, mac_vdev_cfg_get_node_role(vdev));
mac_sched_stop(vdev);
if (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_STA) {
/* add separate phy select for PHY */
phy_rx_phase_force_set(1, 0);
/* force tx phase A for K68 */
cfg_phy_tx_phase_select(1, 1);
if (vdev->bcn_ctx.sta.force_sw_sync) {
/* disable HW ntb sync feature */
mac_sched_enable_hw_ntb_sync(vdev, 0);
} else {
/* enable HW ntb sync feature */
mac_sched_enable_hw_ntb_sync(vdev, 1);
}
#if STATIC_POWER_SAVE
/* start power save */
mac_pm_start(pdev_ptr);
pdev_ptr->mac_pm.fc_ok_pm =
mac_pm_switch_by_fc_ok(cfg->mac_addr);
#endif
#if MAC_ZC_START_FOLLOW_VDEV
mac_zc_set_func_cmd(pdev_id, MAC_ZC_FUNC_CMD_RESET_HW, NULL);
#endif
} else if (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_CCO) {
/* disable it for CCo */
mac_sched_enable_hw_ntb_sync(vdev, 0);
#if FORCE_CCO_ON_3_PHASE
/* for CCO working on 3 phase */
phy_rx_phase_force_set(1, 0);
#endif
/* restart mac zc for cco only */
mac_zc_set_func_cmd(pdev_id, MAC_ZC_FUNC_CMD_RESET_HW, NULL);
}
/* config HW golden gap as suggested by HW team */
mac_sched_sync_ntb(vdev, MAC_SCHED_GOLDEN_GAP, 0);
/* config HW scheduler to RX only mode */
mac_sched_set_bp_ahead_alert(vdev, MAC_BP_AHEAD_ALERT_DUR);
mac_sched_set_recursive_mode(vdev, 0);
start_ntb = mac_sched_get_ntb64(vdev);
mac_sched_set_csma_only(vdev, start_ntb, 0);
/* enable hw rx */
mac_rx_all_ring_enable(pdev_ptr);
/* enable check spur */
mac_check_spur_en(&pdev_ptr->mac_check_spur_ctxt, true);
if (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_STA) {
/* sta check spur start timer */
mac_sta_check_spur_timer_start(&pdev_ptr->mac_check_spur_ctxt,
vdev, MAC_STA_CHECK_SPUR);
/* start the scan */
mac_scan_start(&pdev_ptr->scan);
#if K48_STA_MULTI_CHANNEL_SELECT_ENABLE
iot_mac_k48sta_scan_channel_start(pdev_ptr);
#endif
}
#if (MAC_MM_SNIFFER_MODE)
mac_mm_sniffer_init(vdev);
#endif
mac_vdev_war_rx_abort_init();
} //if (!vdev->mac_vdev_cfg.is_reduced_vdev)
/* clear stop flag */
vdev->stop_flag = 0;
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
#if ENA_WAR_421_DEBUG
extern uint32_t g_is_check_phy_rx;
g_is_check_phy_rx = 1;
vdev->last_rx_ntb = 0;
#endif
#if MAC_STREAM_TIMEOUT_SUPPORT
if(vdev->stream_timeout_timer)
{
os_start_timer(vdev->stream_timeout_timer, \
MAC_RX_STREAM_TIMEOUT_MS); //20s
}
#endif
mac_ppm_record_timer_start(&vdev->mac_ppm);
} //if (!vdev->mac_vdev_cfg.is_reduced_vdev)
/* enable tx rx process */
mac_sw_trig_start(true);
#if PLC_SUPPORT_DBG_PKT_MODE
/* init to allow send dbg pkt in rx only period */
vdev_set_block_dbg_pkt_4_rx_only(vdev, false);
if ((PLC_INV_DBG_PKT_MODE_VDEV_ID != pdev_ptr->dbg_pkt_vdev_id) \
&& (vdev_id != pdev_ptr->dbg_pkt_vdev_id)) {
mac_start_vdev_internal(pdev_id, \
(uint8_t)pdev_ptr->dbg_pkt_vdev_id, cfg);
}
if (vdev->mac_vdev_cfg.is_reduced_vdev \
&& (pdev_ptr->dbg_pkt_vdev_id == vdev->vdev_id)) {
vdev_set_nid(vdev, PLC_DBG_PKT_MODE_NID);
}
#endif
/* if rf_cfg is not null and just is not reduce vdev handle start rf vdev */
if (vdev_id != pdev_ptr->dbg_pkt_vdev_id) {
uint32_t ret = mac_start_rf_vdev_internal(pdev_id,
RF_PDEV_ID, vdev->rf_vdev_id, cfg);
if (!ret) {
iot_printf("rf vdev start success\n");
} else {
iot_printf("rf vdev start fail\n");
}
}
return 0;
}
uint32_t mac_set_vdev_cfg(pdevid_t pdev_id, vdevid_t vdev_id,
cfg_data_tlv *tlv)
{
uint32_t ret = 0;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_SET_VDEV_CFG;
msg->msg.data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->msg.data2 = tlv;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
ret = msg->msg.data1;
mac_free_msg_sync(msg);
out:
return ret;
}
uint32_t mac_set_vdev_cfg_internal(pdevid_t pdev_id, vdevid_t vdev_id,
cfg_data_tlv *tlv)
{
uint32_t ret = 0;
mac_vdev_t *vdev;
mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(PLC_PDEV_ID, RF_PDEV_ID,
PLC_DEFAULT_VDEV);
vdev = get_vdev_ptr(pdev_id, vdev_id);
if (vdev == NULL) {
ret = ERR_INVAL;
goto out;
}
switch (tlv->type) {
case PLC_VDEV_CFG_SET_STA_INFO:
{
PLC_VDEV_CFG_SET_STA_INFO_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_STA_INFO_STRUCT *)tlv;
vdev_set_proxy_tei(vdev, xtlv->proxy_tei);
vdev_set_logic_phase(vdev, xtlv->phase);
vdev_set_tei(vdev, xtlv->self_tei);
#if STATIC_POWER_SAVE
/* stop for static power manager */
mac_pm_stop(get_pdev_ptr(pdev_id));
#endif
/* disable ckq/testing mode period check spur */
if (xtlv->self_tei != PLC_TEI_INVAL) {
mac_sta_period_check_spur_ctl_by_other(false);
}
break;
}
case PLC_VDEV_CFG_ADD_D_SUB_STA:
case PLC_VDEV_CFG_DELETE_D_SUB_STA:
{
PLC_VDEV_CFG_D_SUB_STA_STRUCT *xtlv =
(PLC_VDEV_CFG_D_SUB_STA_STRUCT *)tlv;
tei_t tei = xtlv->sub_sta;
nid_t nid;
vdev_get_nid(vdev, &nid); //TODO:
mac_peer_t *peer = find_peer(vdev, nid, tei);
if (tlv->type == PLC_VDEV_CFG_DELETE_D_SUB_STA) {
if (peer) {
if (vdev->sub_peer_cnt > 0) {
vdev->sub_peer_cnt--;
} else {
iot_printf("sub peer cnt is reach min!!!\n");
}
/* del peer */
iot_printf("cur sub peer cnt:%d, del sub peer 0x%x, tei = %d\n",
vdev->sub_peer_cnt, peer, tei);
/* should not be self peer */
IOT_ASSERT(peer->is_self_peer == 0);
/* should not be bcast peer */
IOT_ASSERT(peer->is_bcast_peer == 0);
if (is_peer_empty(peer) == 0) {
peer->is_sub_peer = 0;
goto out;
}
mac_tei_map_clear((mac_tei_map_t *)vdev->sub_peer_bitmap,
peer->tei);
mac_peer_free(vdev, peer);
}
} else {
/* add peer */
iot_printf("try to add peer 0x%x:tei=%d in nid 0x%x\n", \
peer, tei, nid);
if (peer == NULL) {
ret = mac_peer_alloc(vdev, tei, 0, 0, 1, 0, &peer);
} else {
peer->is_sub_peer = 1;
}
mac_tei_map_set((mac_tei_map_t *)vdev->sub_peer_bitmap, peer->tei);
vdev->sub_peer_cnt++;
if (vdev->sub_peer_cnt >= PLC_PCO_MAX_D_SUB_STA) {
iot_printf("sub peer cnt is reach max!!!\n");
}
iot_printf("cur sub peer cnt:%d, add sub peer 0x%x, tei = %d\n", \
vdev->sub_peer_cnt, peer, tei);
}
break;
}
case PLC_VDEV_CFG_SET_BL_NID:
{
PLC_VDEV_CFG_SET_BL_NID_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_BL_NID_STRUCT *)tlv;
if (xtlv->cnt && xtlv->cnt <= PLC_BL_NID_LIST_MAX) {
vdev->nid_bl_list_cnt = xtlv->cnt;
os_mem_cpy(vdev->nid_bl_list, xtlv->nid,
sizeof(xtlv->nid[0]) * xtlv->cnt);
} else {
vdev->nid_bl_list_cnt = 0;
os_mem_set(vdev->nid_bl_list, 0, sizeof(vdev->nid_bl_list));
}
break;
}
case PLC_VDEV_CFG_SET_PREFER_NID:
{
PLC_VDEV_CFG_SET_PREFER_NID_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_PREFER_NID_STRUCT *)tlv;
vdev_set_nid(vdev, xtlv->nid);
vdev_set_proxy_tei(vdev, xtlv->proxy);
/* reset the current ppm settings as we need to sync up with new nid.
* Note that we don't reset current pdev ppm settings as we need to
* stay in current ppm to sync up with preferred nid.
*/
vdev_reset_ppm_sync(vdev);
mac_rf_vdev_reset_sync_nid(rf_vdev);
/* for same case, non-response detection package.
* if rx detect pkt on band1, need no response,
* at this time cvg will set a inval nid to mac,
* and mac will scan band immediately.
*/
if (xtlv->nid == PLC_NID_INVALID &&
PHY_PROTO_TYPE_GET() == PLC_PROTO_TYPE_SPG) {
/* scan band immediately */
mac_nid_ppm_reset_msg_handler();
}
break;
}
case PLC_VDEV_CFG_SET_FIXED_RATE:
{
PLC_VDEV_CFG_SET_FIXED_RATE_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_FIXED_RATE_STRUCT *)tlv;
vdev_set_fixed_rate(vdev, xtlv->enable);
vdev_set_fixed_rate_level(vdev, xtlv->rate_level);
break;
}
case PLC_VDEV_CFG_SET_TX_POWER_CAP:
{
PLC_VDEV_CFG_SET_TX_POWER_CAP_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_TX_POWER_CAP_STRUCT *)tlv;
if (xtlv->hplc_valid) {
mac_set_tx_power_cap(vdev, &xtlv->hplc_power, NULL, 0);
}
if (xtlv->rf_valid) {
mac_set_tx_power_cap(vdev, NULL, &xtlv->rf_power, 0);
}
break;
}
case PLC_VDEV_CFG_SET_NID_ONLY:
{
PLC_PDEV_CFG_SET_NID_ONLY_STRUCT *xtlv =
(PLC_PDEV_CFG_SET_NID_ONLY_STRUCT *)tlv;
vdev_set_nid(vdev, xtlv->nid);
break;
}
case PLC_VDEV_CFG_SET_TEI_ONLY:
{
PLC_PDEV_CFG_SET_TEI_ONLY_STRUCT *xtlv =
(PLC_PDEV_CFG_SET_TEI_ONLY_STRUCT *)tlv;
vdev_set_tei(vdev, xtlv->self_tei);
break;
}
case PLC_VDEV_CFG_DUMP_REQ:
{
mac_dump_buf_from_cvg();
break;
}
case PLC_VDEV_CFG_SET_NW_VALID:
{
#if STATIC_POWER_SAVE
/* stop for static power manager */
mac_pm_stop(get_pdev_ptr(pdev_id));
#endif
break;
}
case PLC_VDEV_CFG_SET_PM_SAVE_CFG:
{
#if STATIC_POWER_SAVE
PLC_VDEV_CFG_SET_PM_SAVE_CFG_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_PM_SAVE_CFG_STRUCT *)tlv;
req_stay_awake(MAC_PM_UPLAYER_DEMAND_MODULE_ID, !!xtlv->allow_sleep);
#endif
break;
}
case PLC_VDEV_CFG_CTL_CHECK_SPUR:
{
PLC_PDEV_CFG_CTL_CK_SPUR_STRUCT *xtlv =
(PLC_PDEV_CFG_CTL_CK_SPUR_STRUCT *)tlv;
nid_t my_nid;
tei_t tei = vdev_get_tei(vdev);
vdev_get_nid(vdev, &my_nid);
/* if associated, mac not response this evt */
if (!(PLC_TEI_IS_VALID(tei) && my_nid != PLC_NID_INVALID)) {
mac_sta_period_check_spur_ctl_by_other(xtlv->is_start);
}
break;
}
case PLC_VDEV_CFG_SET_RF_CHANNEL:
{
PLC_VDEV_CFG_SET_RF_CHANNEL_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_RF_CHANNEL_STRUCT *)tlv;
mac_rf_set_self_option_channel(xtlv->rf_option, xtlv->rf_channel);
/* stop rf scan timer */
mac_rf_scan_stop();
/* set channel selected */
mac_rf_scan_set_channel_selected(1);
break;
}
case PLC_VDEV_CFG_SET_FORCE_PHASE:
{
PLC_VDEV_CFG_SET_FORCE_PHASE_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_FORCE_PHASE_STRUCT *)tlv;
mac_vdev_set_force_phase(vdev, xtlv->enable, xtlv->phase);
break;
}
case PLC_VDEV_CFG_SET_STA_JOIN:
{
PLC_VDEV_CFG_SET_STA_JOIN_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_STA_JOIN_STRUCT *)tlv;
vdev->sta_joined = xtlv->join_flag;
break;
}
case PLC_VDEV_CFG_SET_HPLC_RF_ASYNC_TX:
{
#if HPLC_RF_ASYNC_TX
PLC_PDEV_CFG_SET_HPLC_RF_ASYNC_TX *xtlv =
(PLC_PDEV_CFG_SET_HPLC_RF_ASYNC_TX *)tlv;
mac_rf_set_hplc_rf_async_tx(xtlv->hplc_rf_async_tx);
#endif
break;
}
case PLC_VDEV_CFG_SET_NW_NEGO:
{
PLC_VDEV_CFG_SET_NW_NEGO_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_NW_NEGO_STRUCT *)tlv;
mac_sched_cco_set_nw_nego(vdev, xtlv->enable);
break;
}
case PLC_VDEV_CFG_SET_SEC_KEY:
{
PLC_VDEV_CFG_SET_SEC_KEY_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_SEC_KEY_STRUCT *)tlv;
vdev_set_sec_key(vdev, &xtlv->key_info);
break;
}
case PLC_VDEV_CFG_SET_FORCE_LINK:
{
PLC_VDEV_CFG_SET_FORCE_LINK_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_FORCE_LINK_STRUCT *)tlv;
if (xtlv->force_link_en) {
if (xtlv->force_rf_link) {
vdev->tx_rx_suspend = 1;
if (rf_vdev) {
rf_vdev->tx_rx_suspend = 0;
}
} else {
vdev->tx_rx_suspend = 0;
if (rf_vdev) {
rf_vdev->tx_rx_suspend = 1;
}
}
} else {
vdev->tx_rx_suspend = 0;
if (rf_vdev) {
rf_vdev->tx_rx_suspend = 0;
}
}
break;
}
case PLC_VDEV_CFG_SET_3PS_OPPOSITE:
{
PLC_VDEV_CFG_SET_3PS_OPPOSITE_STRUCT *xtlv =
(PLC_VDEV_CFG_SET_3PS_OPPOSITE_STRUCT *)tlv;
vdev->opposite_3ps = xtlv->opposite_3ps;
break;
}
default:
IOT_ASSERT(0);
}
out:
return ret;
}
uint32_t mac_get_vdev_cfg(pdevid_t pdev_id, vdevid_t vdev_id,
cfg_data_tlv *tlv)
{
uint32_t ret = 0;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_GET_VDEV_CFG;
msg->msg.data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->msg.data2 = tlv;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
ret = msg->msg.data1;
mac_free_msg_sync(msg);
out:
return ret;
}
uint32_t mac_get_vdev_cfg_internal(pdevid_t pdev_id, vdevid_t vdev_id,
cfg_data_tlv *tlv)
{
uint32_t ret = 0;
mac_vdev_t *vdev = get_vdev_ptr(pdev_id, vdev_id);
if (vdev == NULL) {
ret = ERR_INVAL;
goto out;
}
switch (tlv->type) {
case PLC_VDEV_CFG_GET_NID_PPM:
{
PLC_VDEV_CFG_NID_PPM_STRUCT *xtlv =
(PLC_VDEV_CFG_NID_PPM_STRUCT *)tlv;
xtlv->vaild_nid_cnt = mac_multi_sync_get_ppm_tbl(pdev_id,
(plc_ppm_status_t *)xtlv->ppm_tbl);
break;
}
default:
IOT_ASSERT(0);
}
out:
return ret;
}
uint32_t mac_stop_vdev(uint8_t pdev_id, uint8_t vdev_id)
{
uint32_t ret = 0;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_STOP_VDEV;
msg->msg.data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
ret = msg->msg.data1;
mac_free_msg_sync(msg);
out:
return ret;
}
uint32_t mac_stop_vdev_internal(uint8_t pdev_id, uint8_t vdev_id)
{
mac_vdev_t * vdev = get_vdev_ptr(pdev_id, vdev_id);
mac_pdev_t *pdev_ptr = (mac_pdev_t *)g_mac_pdev[pdev_id];
if (vdev == NULL)
return ERR_INVAL;
if (vdev->is_up == 0)
return ERR_OK;
/* set stop flag */
vdev->stop_flag = 1;
/* just is not reduce vdev handle */
if (vdev_id != pdev_ptr->dbg_pkt_vdev_id) {
uint32_t ret = mac_stop_rf_vdev_internal(pdev_id, RF_PDEV_ID,
vdev->rf_vdev_id);
if (!ret) {
iot_printf("rf vdev stop success\n");
} else {
iot_printf("rf vdev stop fail\n");
}
}
/* if this vdev not reduced, need init config and hw info */
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
/* stop zc colloct */
mac_zc_set_func_cmd(pdev_id, MAC_ZC_FUNC_CMD_COLLECT_STOP, NULL);
#if DEBUG_HWQ_SHCED_HANG
pdev_ptr->dbg_status = MAC_TX_HANG_STATUS_1;
#endif
/* stop current HW scheduler */
mac_sched_stop(vdev);
#if DEBUG_HWQ_SHCED_HANG
pdev_ptr->dbg_status = MACC_TX_HANG_STATUS_MAX;
#endif
/* TODO : stop hw tx rx */
mac_rx_all_ring_disable(pdev_ptr);
/* flush all tdma/csma queue */
mac_tx_flush_all_queue(&pdev_ptr->hwq_hdl, \
true, true);
/* stop check spur */
mac_check_spur_en(&pdev_ptr->mac_check_spur_ctxt, false);
mac_sta_period_check_spur_ctl_by_other(false);
}
vdev_del_all_peer(vdev);
/* clean up local nid and tei info */
os_mem_set(&vdev->start_cfg, 0, sizeof(vdev->start_cfg));
/* if this vdev not reduced, need init config and hw info */
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
if (mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) {
/* if not CCO */
vdev_reset_nid(vdev);
vdev_set_tei(vdev, PLC_TEI_INVAL);
vdev->l_phase1 = PLC_PHASE_ALL;
vdev->l_phase2 = PLC_PHASE_ALL;
vdev->l_phase3 = PLC_PHASE_ALL;
/* stop the mac scan */
mac_scan_stop(&pdev_ptr->scan);
#if STATIC_POWER_SAVE
/* clear power manager status */
phy_pkt_found_flag_clr();
#endif
#if K48_STA_MULTI_CHANNEL_SELECT_ENABLE
iot_mac_k48sta_scan_channel_stop(pdev_ptr);
#endif
}
else {
/* if CCo */
}
mac_beacon_reset(&vdev->bcn_ctx);
/* set default value for auto rate */
vdev_set_fixed_rate(vdev, !RATE_ADAPTION_ENABLE);
}
vdev->is_up = 0;
/* clean up black list nid array */
vdev->nid_bl_list_cnt = 0;
os_mem_set(vdev->nid_bl_list, 0, sizeof(vdev->nid_bl_list));
#if PLC_SUPPORT_DBG_PKT_MODE
/* recover to allow send dbg pkt in rx only period */
vdev_set_block_dbg_pkt_4_rx_only(vdev, false);
#endif
/* if this vdev not reduced, need init config and hw info */
if (!vdev->mac_vdev_cfg.is_reduced_vdev) {
uint32_t tmp_ts = 0;
uint32_t tmp_ntb = 0;
if (vdev->sta_joined) {
tmp_ts = iot_gp_timer_get_curr_ts();
tmp_ntb = mac_sched_get_ntb(NULL);
}
/* mac reinit */
mac_reinit(MAC_RST_REASON_COLD, PHY_PROTO_TYPE_GET(),
phy_band_id_get(), phy_mask_id_get(), mac_rf_get_self_option(),
mac_rf_get_self_channel());
if (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_CCO &&
vdev->sta_joined) {
tmp_ts = iot_gp_timer_get_curr_ts() - tmp_ts;
/* convert us to ntb */
tmp_ts *= 25;
/* fix hplc+rf test bed, PHY clock and network time sync case fail.
* even if the vdev is restarted, NTB needs to be maintained,
* otherwise the test case will fail
*/
mac_sched_sync_ntb(vdev, MAC_SCHED_GOLDEN_GAP,
tmp_ntb + tmp_ts);
}
/* sync ppm restart */
vdev_reset_ppm_sync(vdev);
/* reinit ppm */
mac_ppm_init(&vdev->mac_ppm, phy_get_cal_ppm_in_pib(), 0);
mac_scan_init(pdev_ptr, true);
/* reset power cap */
mac_fix_power_init(vdev);
if (g_phy_cpu_share_ctxt.tx_pwr_ctl_ena == 0) {
vdev->fixed_power_cap_flag = 0;
phy_pwr_adjust_set(0);
}
#if MAC_STREAM_TIMEOUT_SUPPORT
if(vdev->stream_timeout_timer)
{
os_stop_timer(vdev->stream_timeout_timer);
mac_clean_msg(MAC_MSG_TYPE_TIMER, MAC_MSG_ID_DEL_STREAM_TIMER);
}
#endif
#if CERT_WAR_TX_PWR == 1
vdev->cert_war_pwr = 0;
#endif
#if STATIC_POWER_SAVE
/* stop timer and deep sleep */
mac_pm_stop(pdev_ptr);
sleep(DEEP_SLEEP_LEVEL_1);
pdev_ptr->mac_pm.fc_ok_pm = 0;
#endif
mac_ppm_record_timer_stop(&vdev->mac_ppm);
}
vdev->sta_joined = 0;
vdev->tx_rx_suspend = 0;
vdev->opposite_3ps = 0;
if ((PLC_INV_DBG_PKT_MODE_VDEV_ID != pdev_ptr->dbg_pkt_vdev_id) \
&& (vdev_id != pdev_ptr->dbg_pkt_vdev_id)) {
mac_stop_vdev_internal(pdev_id, (uint8_t)pdev_ptr->dbg_pkt_vdev_id);
}
/* maby nid = 0 stream exist, so need wait all vdev free,
* can check peer and stream
*/
mac_check_peer_stream_desc();
if (vdev->sec_key) {
os_mem_set((uint8_t *)vdev->sec_key, 0, sizeof(mac_sec_key_t));
}
return 0;
}
void vdev_reset_ppm_sync(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
mac_ppm_reset_counter(&vdev->mac_ppm.ntb_record);
vdev_set_sync_proxy(vdev, PLC_TEI_INVAL);
vdev_reset_sync_nid(vdev);
#if HPLC_RF_DEV_SUPPORT
mac_pdev_t *pdev = g_mac_pdev[vdev->ref_pdev_id];
mac_rf_vdev_t *rf_vdev;
rf_vdev = get_rf_vdev_ptr(vdev->ref_pdev_id, pdev->mac_rf_pdev->rf_pdev_id,
vdev->rf_vdev_id);
mac_ppm_reset_counter(&rf_vdev->mac_rf_ppm);
#endif
}
/* find the vdev info, if no matching nid,
* return the first vdev that nid = 0
* return NULL if not found
*/
mac_vdev_t *find_vdev_by_nid(pdevid_t pid, nid_t nid)
{
uint32_t v_idx = 0;
mac_vdev_t *first_vdev = NULL, *vdev;
nid_t my_nid;
for (v_idx = 0; v_idx < MAX_VDEV_NUM; v_idx++)
{
vdev = g_mac_pdev[pid]->vdev[v_idx];
if (vdev) {
/* if the nid is set and match the request nid */
if (ERR_OK == vdev_get_nid(vdev, &my_nid)) {
if (my_nid == nid) {
return vdev;
} else {
/* NOTE: fix bug for beijin chaokongqi.
* Cvg will set nid to mac when receive beacon
* in beijin chaokongqi mode. So if the package is already
* hanging on Q, but it hasn't been sent out yet.
* At this time, cvg received a beacon
* and set the NID to mac. Mac can't get vdev
* in the complete interrupt, it will crash here.
*/
if (vdev->mac_vdev_cfg.is_reduced_vdev &&
nid == PLC_DBG_PKT_MODE_NID) {
return vdev;
}
continue;
}
} else {
/* if the vdev's nid is not set
* not matter CCo or STA, return the first vdev
* anyway, because all the packets need be uploaded
*/
if (NULL == first_vdev) {
first_vdev = vdev;
}
}
} // if (vdev)
} // for
return first_vdev;
}
/* associate a vdev and a peer */
uint32_t vdev_add_peer(mac_vdev_t *vdev, void *peer)
{
if (!vdev || !peer)
{
return ERR_INVAL;
}
mac_peer_t *tmp = (mac_peer_t *)peer;
if (tmp->is_self_peer) {
IOT_ASSERT(vdev->self_peer == NULL);
vdev->self_peer = tmp;
}
else if (tmp->is_bcast_peer) {
IOT_ASSERT(vdev->bcast_peer == NULL);
vdev->bcast_peer = tmp;
}
else
{
/* insert this peer before the head */
if (vdev->peer_list) {
iot_list_add_prev(&tmp->vdev_node, vdev->peer_list);
}
else {
vdev->peer_list = &tmp->vdev_node;
}
}
return ERR_OK;
}
uint32_t vdev_del_peer(mac_vdev_t *vdev, void *peer)
{
mac_peer_t *tmp = (mac_peer_t *)peer;
IOT_ASSERT(get_vdev_ptr(tmp->pdev_id, tmp->vdev_id) == vdev);
if (tmp->is_self_peer == 1) {
IOT_ASSERT(vdev->self_peer == tmp);
}
else if (tmp->is_bcast_peer == 1) {
IOT_ASSERT(vdev->bcast_peer == tmp);
}
else {
if (tmp->vdev_node.next == &tmp->vdev_node) {
vdev->peer_list = NULL;
}
else {
vdev->peer_list = tmp->vdev_node.next;
iot_list_del(&tmp->vdev_node);
}
}
return ERR_OK;
}
uint32_t vdev_del_all_peer(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
if (vdev->self_peer) {
mac_peer_free(vdev, vdev->self_peer);
}
if (vdev->bcast_peer) {
mac_peer_free(vdev, vdev->bcast_peer);
}
for(uint32_t i = 0; i < PLC_MAC_PEER_POOL_SIZE; i++){
if(vdev->peer_list == NULL){
break;
}
mac_peer_t *tmp = iot_list_entry(vdev->peer_list, \
mac_peer_t, vdev_node);
mac_peer_free(vdev, tmp);
}
mac_tei_map_reset((mac_tei_map_t *)vdev->sub_peer_bitmap);
#if 0 //TODO: will replace check logic
IOT_ASSERT(g_mac_desc_eng.used[PLC_MAC_STREAM_POOL] == 0);
/* vdev->self peer + vdev->bcast peer */
IOT_ASSERT(g_mac_desc_eng.used[PLC_MAC_PEER_POOL] == 2);
#endif
return ERR_OK;
}
uint32_t mac_vdev_sort_peer_list(mac_vdev_t *vdev, void *peer)
{
iot_list_head_t *entry = &((mac_peer_t *)peer)->vdev_node;
if(vdev == NULL || peer == NULL || \
vdev->peer_list == NULL || entry == NULL)
return 1;
if(((mac_peer_t *)peer)->is_bcast_peer || \
((mac_peer_t *)peer)->is_self_peer)
return 1;
/*
* 1. if peer is not head node,
* del this peer, and insert to head node before.
* 2. if peer is the head node,
* make the head node point the head node next node.
* the purpose is that make the head node point the oldest node.
*/
if(entry != vdev->peer_list)
{
//sort peer, newest on the tail
iot_list_del(entry);
iot_list_add_prev(entry, vdev->peer_list);
}
else
{
if(vdev->peer_list)
{
vdev->peer_list = vdev->peer_list->next;
}
}
#if DEBUG_STREAM_TIMEOUT
//printf the node
iot_list_head_t *entry1 = vdev->peer_list;
mac_peer_t *tmp2 = iot_list_entry(entry1, mac_peer_t, vdev_node);
iot_printf("%s, list %d,tei:%d, peer is %p, ntb:0x%x\n", __FUNCTION__,\
0, tmp2->tei,tmp2, tmp2->rate_info.last_rx_ts);
uint32_t i = 1;
iot_list_head_t *head = vdev->peer_list->next;
while(head != vdev->peer_list)
{
mac_peer_t *tmp1 = iot_list_entry(head, mac_peer_t, vdev_node);
iot_printf("%s, list %d,tei:%d, peer is %p, ntb:0x%x\n", __FUNCTION__,\
i, tmp1->tei, tmp1, tmp1->rate_info.last_rx_ts);
head = head->next;
i++;
}
#endif
return 0;
}
void mac_vdev_del_timeout_stream_internal(void *data, uint32_t judge_time)
{
mac_vdev_t *vdev = (mac_vdev_t *)data;
IOT_ASSERT(vdev);
uint32_t cur_ts = os_boot_time32();
iot_list_head_t *node_old = vdev->peer_list;
iot_list_head_t *tmp_node;
mac_peer_t *tmp_peer;
uint32_t cur_free_cnt, total_free_cnt;
tmp_node = node_old;
total_free_cnt = 0;
while (1) {
tmp_peer = iot_list_entry(tmp_node, mac_peer_t, vdev_node);
if (judge_time) {
if ((uint32_t)(cur_ts - tmp_peer->rate_info.last_rx_ts)
< MAC_RX_STREAM_TIMEOUT_MS) {
/* not timeout */
break;
}
}
cur_free_cnt = peer_del_all_stream(tmp_peer, DEL_RX_STREAM);
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_2)
iot_printf("%s, tei:%d, cnt:%d \n", __FUNCTION__,
tmp_peer->tei, cur_free_cnt);
#endif
/* updata the ntb and sort peer again */
mac_vdev_sort_peer_list(vdev, tmp_peer);
total_free_cnt += cur_free_cnt;
if (cur_free_cnt && !judge_time) {
break;
}
tmp_node = tmp_node->next;
if (tmp_node == node_old) {
if (!judge_time) {
/* all of peer stream not free, assert dump */
mac_stream_exhausted_dump(tmp_peer);
}
break;
}
}
iot_printf("del_timeout_str. judge:%d, cnt:%u\n",
judge_time, total_free_cnt);
mac_add_timeout_stream_del_cnt();
}
void mac_vdev_del_overflow_peer(mac_vdev_t *vdev)
{
if(!vdev || !vdev->peer_list) {
return;
}
iot_list_head_t *node = vdev->peer_list;
mac_peer_t *peer = NULL;
for (uint8_t i = 0; i < 2; i++) {
peer = iot_list_entry(node, mac_peer_t, vdev_node);
if (ERR_OK == mac_peer_del_overflow_peer(peer)) {
return;
}
node = node->next;
}
iot_printf("del overflow peer failed\n");
mac_add_overflow_peer_del_cnt(PEER_FAIL);
}
void mac_vdev_del_timeout_stream(timer_id_t timer_id, void *arg)
{
(void)timer_id;
mac_vdev_t *vdev = (mac_vdev_t *)arg;
if(vdev == NULL || vdev->peer_list == NULL) {
return;
}
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
return;
}
msg->type = MAC_MSG_TYPE_TIMER;
msg->id = MAC_MSG_ID_DEL_STREAM_TIMER;
msg->data1 = true;
msg->data2 = (void *)vdev;
mac_queue_msg(msg, MAC_MSG_QUEUE_LP);
}
/* get vdev's nid */
uint32_t IRAM_ATTR vdev_get_nid(mac_vdev_t *vdev, nid_t *nid)
{
if ((NULL == vdev) || (NULL == nid)) {
IOT_ASSERT(0);
return ERR_FAIL;
}
if (vdev->bcn_ctx.nid_inited) {
*nid = vdev->bcn_ctx.fc.nid;
return ERR_OK;
} else {
*nid = PLC_NID_INVALID;
return ERR_FAIL;
}
}
/* reset vdev's nid */
void vdev_reset_nid(mac_vdev_t *vdev)
{
if (vdev == NULL) {
IOT_ASSERT(0);
return;
}
vdev->bcn_ctx.nid_inited = 0;
vdev->bcn_ctx.fc.nid = PLC_NID_INVALID;
}
/* set vdev's nid */
void vdev_set_nid(mac_vdev_t *vdev, uint32_t nid)
{
mac_rf_pdev_t *rf_pdev = NULL;
mac_rf_vdev_t *rf_vdev = NULL;
if (vdev == NULL) {
IOT_ASSERT(0);
return;
}
rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
if (rf_pdev) {
rf_vdev = get_rf_vdev_ptr(vdev->ref_pdev_id, rf_pdev->rf_pdev_id,
vdev->rf_vdev_id);
}
nid = mac_mask_input_nid(nid);
/* reduced vdev, not set pdev and hw info */
if (vdev->mac_vdev_cfg.is_reduced_vdev) {
vdev->bcn_ctx.fc.nid = nid;
vdev->bcn_ctx.nid_inited = 1;
return;
}
/* clear old nid and free mem */
if (nid != PLC_NID_INVALID && vdev->bcn_ctx.fc.nid != PLC_NID_INVALID && \
nid != vdev->bcn_ctx.fc.nid && vdev->bcn_ctx.nid_inited == 1) {
iot_printf("clear old nid=0x%x\n", vdev->bcn_ctx.fc.nid);
/* stop current HW scheduler */
mac_sched_stop(vdev);
/* rf schedule stop */
mac_rf_sched_stop(rf_vdev);
/* flush all tdma/csma queue */
vdev->stop_flag = 1;
mac_tx_flush_all_queue(&g_mac_pdev[vdev->ref_pdev_id]->hwq_hdl, \
true, true);
vdev->stop_flag = 0;
if (rf_pdev) {
/* flush all tdma/csma rf queue */
mac_rf_tx_flush_all_queue(&rf_pdev->hwq_hdl);
}
/* del peer and stream */
vdev_del_all_peer(vdev);
vdev->bcn_ctx.nid_inited = 0;
vdev->bcn_ctx.fc.nid = PLC_NID_INVALID;
mac_config_nid(vdev, PLC_NID_INVALID);
}
if (nid != PLC_NID_INVALID && \
vdev->bcn_ctx.nid_inited == 0) {
vdev->bcn_ctx.fc.nid = nid;
vdev->bcn_ctx.nid_inited = 1;
mac_config_nid(vdev, nid);
iot_printf("set nid=0x%x\n", nid);
}
return;
}
uint32_t vdev_is_bl_nid(mac_vdev_t *vdev, uint32_t nid)
{
uint8_t i;
if (NULL == vdev) {
IOT_ASSERT(0);
return 0;
}
nid = mac_mask_input_nid(nid);
for (i = 0; i < vdev->nid_bl_list_cnt; i++) {
vdev->nid_bl_list[i] = mac_mask_input_nid(vdev->nid_bl_list[i]);
if (vdev->nid_bl_list[i] == nid)
return 1;
}
return 0;
}
uint32_t vdev_get_sync_nid(mac_vdev_t *vdev, nid_t *sync_nid)
{
if ((NULL == vdev) || (NULL == sync_nid)) {
IOT_ASSERT(0);
return ERR_FAIL;
}
if (vdev->sync_nid_inited) {
*sync_nid = mac_mask_input_nid(vdev->sync_nid);
return ERR_OK;
} else {
*sync_nid = PLC_NID_INVALID;
return ERR_FAIL;
}
}
void vdev_set_sync_nid(mac_vdev_t *vdev, uint32_t nid)
{
if (vdev == NULL) {
IOT_ASSERT(0);
return;
}
nid = mac_mask_input_nid(nid);
vdev->sync_nid = nid;
vdev->sync_nid_inited = true;
iot_printf("set sync nid=0x%x\n", nid);
}
void vdev_reset_sync_nid(mac_vdev_t *vdev)
{
if (vdev == NULL) {
IOT_ASSERT(0);
return;
}
vdev->sync_nid_inited = false;
vdev->sync_nid = PLC_NID_INVALID;
}
tei_t vdev_get_sync_proxy(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
return vdev->sync_proxy;
}
void vdev_set_sync_proxy(mac_vdev_t *vdev, tei_t proxy)
{
if (vdev == NULL) {
IOT_ASSERT(0);
return;
}
vdev->sync_proxy = proxy;
}
tei_t vdev_get_proxy_tei(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
return vdev->proxy_tei;
}
void vdev_set_proxy_tei(mac_vdev_t *vdev, tei_t proxy_tei)
{
IOT_ASSERT(vdev);
nid_t nid;
if (ERR_OK != vdev_get_nid(vdev, &nid)) {
return;
}
mac_peer_t *peer = NULL;
if (PLC_TEI_IS_VALID(proxy_tei)) {
if (PLC_TEI_IS_VALID(vdev->proxy_tei) && vdev->proxy_tei != proxy_tei) {
peer = find_peer(vdev, nid, vdev->proxy_tei);
if (peer != NULL) {
peer->is_proxy_peer = 0;
/* free old pco peer */
mac_peer_del_temp_peer(peer);
}
}
vdev->proxy_tei = proxy_tei;
peer = find_peer(vdev, nid, proxy_tei);
/* add proxy peer */
if (peer == NULL) {
mac_peer_alloc(vdev, proxy_tei, 0, 0, 0, 1, &peer);
} else {
peer->is_proxy_peer = 1;
}
iot_printf("add proxy peer tei:%d\n", \
proxy_tei);
}
return;
}
phase_t vdev_get_logic_phase(mac_vdev_t *vdev)
{
return vdev->l_phase1;
}
void vdev_set_logic_phase(mac_vdev_t *vdev, phase_t phase)
{
IOT_ASSERT(vdev);
if (vdev->l_phase1 != phase) {
vdev->l_phase1 = phase;
}
}
void vdev_set_ra_cb(mac_vdev_t * vdev, rate_control_func_t cb)
{
IOT_ASSERT(vdev);
vdev->ra_cb = cb;
}
void vdev_set_sta_cap_phase(uint32_t proto, mac_vdev_t *vdev, uint8_t phase)
{
IOT_ASSERT(vdev);
switch (proto) {
case PLC_PROTO_TYPE_SG:
vdev->bcn_ctx.sg_uniq_bc_str.sta_cap.phase = phase;
break;
case PLC_PROTO_TYPE_SPG:
vdev->bcn_ctx.spg_uniq_bc_str.sta_cap.phase = phase;
break;
default:
IOT_ASSERT(0);
break;
}
return;
}
uint32_t *vdev_get_bc_period_cnt_ptr(uint32_t proto, mac_vdev_t *vdev)
{
uint32_t *bc_ptr = NULL;
IOT_ASSERT(vdev);
switch (proto) {
case PLC_PROTO_TYPE_SG:
bc_ptr = \
&vdev->bcn_ctx.sg_uniq_bc_str.payload_header.bc_period_cnt;
break;
case PLC_PROTO_TYPE_SPG:
bc_ptr = \
&vdev->bcn_ctx.fc.bp_cnt;
break;
default:
IOT_ASSERT(0);
bc_ptr = NULL;
break;
}
return bc_ptr;
}
uint32_t vdev_get_bc_period_cnt(uint32_t proto, mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
uint32_t beacon_period_cnt = 0;
switch (proto) {
case PLC_PROTO_TYPE_SG:
beacon_period_cnt = \
vdev->bcn_ctx.sg_uniq_bc_str.payload_header.bc_period_cnt;
break;
case PLC_PROTO_TYPE_SPG:
beacon_period_cnt = \
vdev->bcn_ctx.fc.bp_cnt;
break;
default:
IOT_ASSERT(0);
break;
}
return beacon_period_cnt;
}
uint32_t vdev_set_fixed_rate(mac_vdev_t *vdev, uint8_t flag)
{
IOT_ASSERT(vdev);
vdev->fixed_rate_flag = !!flag;
/* for cert test WAR start */
if (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_CCO &&
mac_get_cert_test_flag()) {
/* disable swagc */
phy_swagc_set(false);
}
/* for cert test WAR end */
return 0;
}
uint32_t vdev_get_fixed_rate(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
return vdev->fixed_rate_flag;
}
uint32_t vdev_set_fixed_rate_level(mac_vdev_t *vdev, uint8_t rate_level)
{
IOT_ASSERT(vdev);
if (rate_level > PLC_RATE_ADAPT_RATE_HIGH) {
iot_printf("up layer set rate level:%d err, will use low level!\n",
rate_level);
rate_level = PLC_RATE_ADAPT_RATE_LOW;
}
vdev->rate_level = rate_level;
return 0;
}
uint32_t vdev_get_fixed_rate_level(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
return vdev->rate_level;
}
uint8_t mac_vdev_cfg_get_node_role(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
return (uint8_t)(vdev->mac_vdev_cfg.node_role);
}
uint32_t vdev_get_bc_period_ms(mac_vdev_t *vdev, uint32_t proto)
{
IOT_ASSERT(vdev);
/* TODO: for spg, may be different */
(void)proto;
return vdev->bcn_ctx.time_slot.bc_period;
}
uint32_t vdev_set_block_dbg_pkt_4_rx_only(mac_vdev_t *vdev, uint32_t block)
{
IOT_ASSERT(vdev);
mac_pdev_t *pdev = g_mac_pdev[vdev->ref_pdev_id];
uint8_t vdev_id;
mac_vdev_t *find_vdev;
for (vdev_id = 0; vdev_id < pdev->cur_vdev_num; vdev_id++) {
find_vdev = pdev->vdev[vdev_id];
if (find_vdev) {
find_vdev->block_dbg_pkt_4_rx_only = !!block;
}
}
return ERR_OK;
}
uint32_t vdev_get_block_dbg_pkt_4_rx_only(mac_vdev_t *vdev)
{
IOT_ASSERT(vdev);
return vdev->block_dbg_pkt_4_rx_only;
}
uint32_t mac_get_reduce_vdev_id(uint32_t pdev_id)
{
if (pdev_id >= MAX_PDEV_NUM) {
IOT_ASSERT(0);
}
return g_mac_pdev[pdev_id]->dbg_pkt_vdev_id;
}
void mac_vdev_war_rx_abort_init(void)
{
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
#if SUPPORT_SOUTHERN_POWER_GRID
uint8_t user_type = iot_oem_get_user_type();
/* WAR for guangxi spg cert */
if ((os_boot_time32() < 40000)
&& ((USER_TYPE_SOUTHEN_POWER_GRID_GX_NW21 == user_type)
|| (USER_TYPE_SOUTHEN_POWER_GRID_GUIZHOU == user_type))) {
pdev->rx_abort_rst_cnt = 0;
pdev->rx_abort_spg_war_cnt = 0;
} else
#endif
{
/* disable war */
pdev->rx_abort_rst_cnt = 255;
pdev->rx_abort_spg_war_cnt = 255;
}
}