/**************************************************************************** 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_pdev.h" #include "iot_errno.h" #if HW_PLATFORM == HW_PLATFORM_SIMU #include "simulator_txrx.h" #endif #include "mac_rx_hw.h" #include "mac_tx_hw.h" #include "plc_const.h" #include "mac_msg.h" #include "mac.h" #include "phy_chn.h" #include "iot_io.h" #include "iot_system.h" #include "hw_phy_init.h" #include "mac_status.h" #include "mac_tx_power.h" #include "mac_pm.h" #include "mac_init_api.h" #include "mac_channel.h" #include "mac_channel_tools.h" #include "mac_check_spur.h" #include "hw_phy_api.h" #include "mac_reset.h" #include "mac_cmn_hw.h" #include "mac_hw_tsfm.h" #include "mac_rf.h" mac_pdev_t* g_mac_pdev[MAX_PDEV_NUM]; static iot_mem_pool_t* g_mac_pdev_pool; extern uint32_t g_fw_mode; uint32_t mac_pdev_init() { if(!g_mac_pdev[0]) { /* create global pdev pool */ iot_mem_pool_new(PLC_MAC_PDEV_MID, MAX_PDEV_NUM, \ sizeof(mac_pdev_t), \ &g_mac_pdev_pool, 0); } /* init every pdev from the pool */ for (int i = 0; i < MAX_PDEV_NUM; i++) { if(!g_mac_pdev[i]){ /* alloc a pdev */ g_mac_pdev[i] = iot_mem_pool_alloc(g_mac_pdev_pool); g_mac_pdev[i]->pdev_id = (pdevid_t)i; g_mac_pdev[i]->dbg_pkt_vdev_id = PLC_INV_DBG_PKT_MODE_VDEV_ID; /* init vdev pool in the pdev */ if (iot_mem_pool_init(PLC_MAC_VDEV_MID, MAX_VDEV_NUM, sizeof(mac_vdev_t), &g_mac_pdev[i]->vdev_pool, 0) != 0) { return ERR_NOMEM; } g_mac_pdev[i]->cur_vdev_num = 0; g_mac_pdev[i]->switch_ctxt_in_mac_isr = 0; g_mac_pdev[i]->ena_ucast_hwretry = 0; /* enable/disable broadcast hwretry by macro */ mac_set_bcast_hwretry_cfg(g_mac_pdev[i], MAC_BCAST_HWRETRY_ENABLE); os_mem_set(g_mac_pdev[i]->vdev, 0, sizeof(mac_vdev_t*) * MAX_VDEV_NUM); os_mem_set(&g_mac_pdev[i]->mac_status, 0, sizeof(mac_status_t)); os_mem_set(&g_mac_pdev[i]->mac_pm, 0, sizeof(mac_pm_t)); g_mac_pdev[i]->mac_isr_rx_fc_ts_ntb = 0; #if DEBUG_CANNOT_SENDOUT_PKT /*create timer for cannot send out pkt*/ g_mac_pdev[i]->plc_tx_timer = \ os_create_timer(PLC_MAC_TX_HW_MID, true, \ mac_tx_hang_msg, NULL); #endif #if DEBUG_INVAILD_ADDR g_mac_pdev[i]->buf_addr = NULL; g_mac_pdev[i]->buf_len = 0; #endif #if (PLC_SUPPORT_CCO_ROLE && (DEBUG_CANNOT_SENDOUT_PKT || DBG_HW_DUMP)) IOT_PKT_GET(g_mac_pdev[i]->dump_pkt, 1024, 0, PLC_MAC_RX_HW_MID); IOT_ASSERT(g_mac_pdev[i]->dump_pkt); #endif mac_check_spur_init(&g_mac_pdev[i]->mac_check_spur_ctxt, \ MAC_CHECK_SPUR_NTB); mac_hw_tsfm_init((uint8_t)g_fw_mode, (uint8_t)i); /* first time init scan */ mac_scan_init(g_mac_pdev[i], false); } /* INT DSR support */ mac_set_pdev_tx_comp(g_mac_pdev[i], mac_tx_hw_mpdu_comp_dsr); if(g_fw_mode!=FTM_MODE) { mac_set_pdev_rx_cb(g_mac_pdev[i], mac_rx_hw_mpdu); } else { mac_set_pdev_rx_cb(g_mac_pdev[i], mac_rx_hw_mpdu_internal); } #if HW_PLATFORM == HW_PLATFORM_SIMU /* init simulator layer */ simulator_init_ex(&g_mac_pdev[i]->simu, g_mac_pdev[i], NULL, NULL, mac_tx_hw_mpdu_comp_dsr, NULL, NULL, mac_rx_hw_mpdu, WORKMODE_PLC); #else /* FPGA or chip */ mac_tx_hw_init(PHY_PROTO_TYPE_GET(), g_mac_pdev[i]); mac_rx_hw_init(g_fw_mode); #if K48_STA_MULTI_CHANNEL_SELECT_ENABLE iot_mac_k48sta_scan_channel_init(g_mac_pdev[i]); #endif #endif mac_pm_init(g_mac_pdev[i]); if (g_fw_mode != FTM_MODE) { /* init hwq & ring for each pdev */ mac_rx_ring_ctxt_init(&g_mac_pdev[i]->ring_hdl); #if HW_PLATFORM == HW_PLATFORM_SIMU simu_set_rx_ring_ptr(&g_mac_pdev[i]->simu, &g_mac_pdev[i]->ring_hdl.ring[0]); #endif mac_q_init(&g_mac_pdev[i]->hwq_hdl); /* put this after tx_hw init for the dbg mode setting */ /* init traffic default service */ /* BCN */ mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_BCN, \ PLC_PHASE_A, (lid_t)0)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_BCN, \ PLC_PHASE_B, (lid_t)0)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_BCN, \ PLC_PHASE_C, (lid_t)0)); /* CSMA */ mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_A, (lid_t)0)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_A, (lid_t)1)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_A, (lid_t)2)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_A, (lid_t)3)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_B, (lid_t)0)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_B, (lid_t)1)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_B, (lid_t)2)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_B, (lid_t)3)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_C, (lid_t)0)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_C, (lid_t)1)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_C, (lid_t)2)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_CSMA, \ PLC_PHASE_C, (lid_t)3)); /* BCSMA */ mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_BCSMA, \ PLC_PHASE_A, (lid_t)LID_BCSMA_START)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_BCSMA, \ PLC_PHASE_B, (lid_t)LID_BCSMA_START)); mac_q_alloc_hwq(&g_mac_pdev[i]->hwq_hdl, \ mac_q_get_swq_type(PLC_BCN_REGION_BCSMA, \ PLC_PHASE_C, (lid_t)LID_BCSMA_START)); } #if DBG_RX_ABORT_REASON_4 == 1 g_mac_pdev[i]->cont_rx_abort4_cnt = 0; #endif mac_multi_sync_init((uint8_t)i); #if (IOT_STA_CONTROL_MODE == IOT_STA_CONTROL_TYPE_STA) mac_channel_test_init(); #endif /* init rf pdev */ mac_rf_pdev_init((pdevid_t)i); } return 0; } /* get how many pdev mac supported * pdev_num_returned - the pointer returned about the number * return 0 for success and non-zero for failure. */ uint32_t mac_get_pdev_num(uint8_t *pdev_num_returned) { *pdev_num_returned = MAX_PDEV_NUM; return 0; } /* * mac_set_pdev_cfg - pull a msg to set a pdev's config * * pdev_id - which pdev to config * cfg_struct_ptr - the pointer to the param config structure * * return 0 for success and non-zero for failure. */ uint32_t mac_set_pdev_cfg(pdevid_t pdev_id, void *cfg_struct_ptr) { 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_PDEV_CFG; msg->msg.data1 = pdev_id; msg->msg.data2 = cfg_struct_ptr; mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP); ret = msg->msg.data1; mac_free_msg_sync(msg); out: return ret; } /* * mac_set_pdev_cfg_internal - set a pdev's config * * pdev_id - which pdev to config * cfg_struct_ptr - the pointer to the param config structure * * return 0 for success and non-zero for failure. */ uint32_t mac_set_pdev_cfg_internal(pdevid_t pdev_id, void *cfg_struct_ptr) { uint32_t ret = 0; cfg_data_tlv *tlv = (cfg_data_tlv *)cfg_struct_ptr; mac_pdev_t *pdev = g_mac_pdev[pdev_id]; switch (tlv->type) { case PLC_PDEV_CFG_SET_BAND: { PLC_PDEV_CFG_SET_BANDID_STRUCT *xtlv = \ (PLC_PDEV_CFG_SET_BANDID_STRUCT *)tlv; uint32_t curr_band_id; if (pdev == NULL) { ret = ERR_INVAL; goto out; } curr_band_id = phy_band_id_get(); uint32_t proto = PHY_PROTO_TYPE_GET(); if (PLC_PROTO_TYPE_SPG == proto && ENABLE_MULTIBAND) { if (xtlv->band_id == IOT_SUPPORT_TONE_32_120) { xtlv->band_id = IOT_SUPPORT_TONE_MULTI_BAND021; } } if (curr_band_id != xtlv->band_id) { iot_printf("%s proto:%d set band id=%d\n", __FUNCTION__, proto, xtlv->band_id); phy_band_id_to_set(xtlv->band_id); phy_mask_id_to_set( phy_band_to_tonemask_id_get((uint8_t)xtlv->band_id)); mac_new_phy_cfg_apply(); /* add this line for cert test may change * band later and use the curr_band_id */ curr_band_id = xtlv->band_id; /* clear mac status cnt */ mac_status_cnt_clr(); } else { iot_printf("%s already in band id %lu\n", __FUNCTION__, xtlv->band_id); } if (IOT_SUPPORT_TONE_231_490_CE == xtlv->band_id) { uint8_t hplc_power = MAC_TX_POWER_CE_DEFAULT; mac_set_tx_power_cap(pdev->vdev[0], &hplc_power, NULL, 0); } #if CPLC_IOT_CERT_ENABLE extern uint32_t mac_cert_test_band_cfg(uint8_t band_id); mac_cert_test_band_cfg(curr_band_id); #endif break; } case PLC_PDEV_CFG_SET_SWAGC: { PLC_PDEV_CFG_SET_SWAGC_STRUCT *xtlv = \ (PLC_PDEV_CFG_SET_SWAGC_STRUCT *)tlv; phy_swagc_set(!!(xtlv->ena)); iot_printf("mac swagc:%d\n", xtlv->ena); break; } case PLC_PDEV_CFG_SET_SCAN_BAND_TBL: { PLC_PDEV_CFG_BAND_RANGE_STRUCT *xtlv = (PLC_PDEV_CFG_BAND_RANGE_STRUCT *)tlv; if (pdev == NULL) { ret = ERR_INVAL; goto out; } mac_scan_set_band_info(PHY_PROTO_TYPE_GET(), xtlv->plc_scan_cnt, xtlv->plc_scan_tbl); break; } case PLC_PDEV_CFG_SET_RF_SCAN_TBL: { PLC_PDEV_CFG_RF_RANGE_STRUCT *xtlv = (PLC_PDEV_CFG_RF_RANGE_STRUCT *)tlv; if (pdev == NULL) { ret = ERR_INVAL; goto out; } mac_rf_scan_set_scan_tbl(xtlv->rf_cnt, (uint8_t *)xtlv->rf_scan_tbl); break; } default: IOT_ASSERT(0); } out: return ret; } uint32_t mac_get_pdev_cfg(uint8_t pdev_id, void *cfg_struct_ptr) { 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_PDEV_CFG; msg->msg.data1 = pdev_id; msg->msg.data2 = cfg_struct_ptr; mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP); ret = msg->msg.data1; mac_free_msg_sync(msg); out: return ret; } /* * mac_set_pdev_cfg_internal - set a pdev's config * * pdev_id - which pdev to config * cfg_struct_ptr - the pointer to the param config structure * * return 0 for success and non-zero for failure. */ uint32_t mac_get_pdev_cfg_internal(pdevid_t pdev_id, void *cfg_struct_ptr) { uint32_t ret = ERR_FAIL; cfg_data_tlv *tlv = (cfg_data_tlv *)cfg_struct_ptr; (void)pdev_id; switch (tlv->type) { case PLC_PDEV_CFG_GET_BAND_TBL: { PLC_PDEV_CFG_BAND_RANGE_STRUCT *xtlv = (PLC_PDEV_CFG_BAND_RANGE_STRUCT *)tlv; if (PLC_GET_SUPPORT_BAND == xtlv->is_scan_band) { xtlv->plc_scan_cnt = (uint8_t)mac_scan_get_support_band_tbl(PHY_PROTO_TYPE_GET(), PLC_SCAN_BAND_MAX_CNT, xtlv->plc_scan_tbl); if (xtlv->plc_scan_cnt) { ret = ERR_OK; } } else if (PLC_GET_SCAN_BAND == xtlv->is_scan_band) { xtlv->plc_scan_cnt = (uint8_t)mac_scan_get_band_info(PHY_PROTO_TYPE_GET(), PLC_SCAN_BAND_MAX_CNT, xtlv->plc_scan_tbl); if (xtlv->plc_scan_cnt) { ret = ERR_OK; } } else { xtlv->plc_scan_cnt = 0; ret = ERR_FAIL; } break; } default: IOT_ASSERT(0); } return ret; } void mac_set_pdev_tx_comp(mac_pdev_t *pdev, \ mac_tx_hw_comp_t tx_comp_cb) { IOT_ASSERT(pdev); pdev->tx_comp = tx_comp_cb; } void mac_set_pdev_rx_cb(mac_pdev_t *pdev, \ mac_rx_t rx_cb) { IOT_ASSERT(pdev); pdev->rx = rx_cb; } void mac_pdev_send_reset_war_msg(mac_pdev_t *pdev, uint32_t flag) { if (pdev == NULL) { return; } mac_msg_t *msg = mac_alloc_msg(); if (msg == NULL) { iot_printf("WAR reset msg req failed.\n"); IOT_ASSERT(0); return; } msg->type = MAC_MSG_TYPE_MAC; msg->id = MAC_MSG_ID_MAC_WARM_RESET_WAR; msg->data1 = flag; mac_queue_msg(msg, MAC_MSG_QUEUE_HP); } mac_pdev_t * IRAM_ATTR get_pdev_ptr(uint32_t pdev_id) { if (pdev_id >= MAX_PDEV_NUM) { IOT_ASSERT(0); return NULL; } return g_mac_pdev[pdev_id]; } void mac_tx_hang_msg(timer_id_t timer_id, void * arg) { (void)timer_id; (void)arg; mac_msg_t *msg = mac_alloc_msg(); if (msg == NULL) { iot_printf("send tx_hang msg failed.\n"); IOT_ASSERT(0); return; } msg->type = MAC_MSG_TYPE_MAC; msg->id = MAC_MSG_ID_MAC_DEBUG_TX_HANG; mac_queue_msg(msg, MAC_MSG_QUEUE_HP); } void mac_tx_hang_handle() { #if DEBUG_CANNOT_SENDOUT_PKT iot_printf("%s, phy hang\n", __FUNCTION__); mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID); mac_vdev_t *vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_DEFAULT_VDEV); uint8_t hwq_id; if ((mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) && !(vdev->bcn_ctx.sta.allow_reuse_ts && vdev->bcn_ctx.time_slot.allow_reuse)) { return; } pdev->plc_con_tx_timeout_cnt++; g_phy_cpu_share_ctxt.isr_cnt0 = mac_get_isr_cnt(); /* check time */ if (pdev->plc_con_tx_timeout_cnt <= TX_HANG_HANDLE_CNT) { phy_csma_ignore_cca(true); mac_add_csma_ignore_cca_cnt(); mac_dump_buf(MAC_DUMP_TYPE_10, NULL, 0, NULL, 0, NULL, 0, 0); phy_dbg_sts_print(); /* doing check spur operation */ uint32_t ret = mac_check_spur_for_txhang(); if (ret) { iot_printf("tx hang spur failed:%d\n!", ret); } } else { /*the second time, printf mac and phy info */ mac_phy_print_debug_info(); } for (hwq_id = MAC_QUE_CSMA_A_0; hwq_id <= MAC_QUE_BCSMA_C; hwq_id++) { mac_txq_trigger_send(hwq_id); } //TODO: to reset phy //mac_warm_reset_war(); #endif } void mac_set_bcast_hwretry_cfg(mac_pdev_t *pdev, uint8_t ena) { pdev->ena_bcast_hwretry = !!ena; } uint32_t mac_get_bcast_hwretry_cfg(mac_pdev_t *pdev) { return pdev->ena_bcast_hwretry; } void mac_rx_hang_handle(mac_pdev_t *pdev) { uint32_t role, tei, nid; role = mac_get_hw_role(); tei = mac_get_hw_tei(); nid = mac_get_hw_nid(); /* rx only mode enable */ mac_block_all_tx_ena(&pdev->hwq_hdl, true); mac_pre_phy_reinit(); /* 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()); mac_post_phy_reinit(0); mac_config_nid(NULL, nid); mac_config_tei(NULL, (uint16_t)tei); mac_config_role(NULL, (uint8_t)role); /* rx only mode disable */ mac_block_all_tx_ena(&pdev->hwq_hdl, false); return; }