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

577 lines
17 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_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;
}