/**************************************************************************** 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 "iot_config.h" #include "mac_desc_engine.h" #include "iot_errno.h" #include "mac_msdu.h" #include "mac_peer.h" #include "mac_stream.h" #include "rx_pb_reorder.h" #include "command_list.h" #include "iot_io_api.h" #include "mac_pdev.h" #include "iot_dbglog_api.h" #include "iot_dbglog_parser.h" /* 30 minutes period, uint 10 mimutes */ #define MAC_DESC_PERIOD_30_MIN 3 mac_desc_engine_t g_mac_desc_eng; token_num_t g_mac_token_bucket[TOKEN_BUCKET_IDX_MAX]; static uint8_t g_mac_desc_period_30_min_cnt = 0; #if HPLC_RF_DEV_SUPPORT token_num_t g_rf_mac_token_bucket[TOKEN_BUCKET_IDX_MAX]; #endif const mac_desc_pool_cfg_t g_def_desc_pool_cfg[MAX_PLC_DESC_POOL_NUM] = { /* PLC_MAC_MSDU_POOL */ { PLC_MAC_MSDU_POOL_SIZE + RF_MAC_MSDU_POOL_SIZE, sizeof(mac_msdu_t) }, /* PLC_MAC_PEER_POOL */ { PLC_MAC_PEER_POOL_SIZE + RF_MAC_PEER_POOL_SIZE, sizeof(mac_peer_t) }, /* PLC_MAC_STREAM_POOL */ { PLC_MAC_STREAM_POOL_SIZE + RF_MAC_STREAM_POOL_SIZE, sizeof(mac_stream_t)}, /* PLC_TX_MPDU_START_POOL */ { PLC_TX_MPDU_START_POOL_SIZE + RF_TX_MPDU_START_POOL_SIZE, sizeof(tx_mpdu_start) }, /* PLC_TX_MPDU_END_POOL */ { PLC_TX_MPDU_END_POOL_SIZE + RF_TX_MPDU_END_POOL_SIZE, sizeof(tx_mpdu_end) }, /* PLC_TX_PB_START_POOL */ { PLC_TX_PB_POOL_SIZE + RF_TX_PB_POOL_SIZE, sizeof(tx_pb_start) }, /* PLC_RX_PB_DESC_POOL */ { PLC_RX_PB_POOL_SIZE + RF_RX_PB_POOL_SIZE, sizeof(pb_buf_list_t) }, /*PLC_SCHED_CMD_LIST_POOL*/ { PLC_SCHED_CMD_LIST_POOL_SIZE + RF_SCHED_CMD_LIST_POOL_SIZE, sizeof(hw_sched_cmd_list_t) }, /* PLC_TX_DUMMY_POOL */ { PLC_TX_DUMMY_POOL_SIZE + RF_TX_DUMMY_POOL_SIZE, sizeof(tx_dummy_node) }, /*PLC_MAC_MSDU_FRAME_POOL*/ { PLC_MAC_MSDU_FRAME_POOL_SIZE + RF_MAC_MSDU_FRAME_POOL_SIZE, sizeof(mac_msdu_frame_t) }, }; uint32_t mac_desc_engine_init(mac_desc_engine_t *desc_eng, \ mac_desc_pool_cfg_t *cfg) { uint32_t ret; if (desc_eng == NULL) { return ERR_INVAL; } /* if cfg NULL, use default */ if (cfg == NULL) { cfg = (mac_desc_pool_cfg_t *)&g_def_desc_pool_cfg[0]; } { #if PLC_MEM_ALLOC_STAT uint32_t total_bytes = 0; #endif for (int i = 0; i < MAX_PLC_DESC_POOL_NUM; i++) { ret = iot_mem_pool_init(PLC_MAC_DESC_ENGINE_MID, cfg[i].desc_num, cfg[i].desc_size, &desc_eng->mem_pool[i], 0); IOT_ASSERT(ret == 0); desc_eng->used[i] = 0; desc_eng->mutex[i] = os_create_mutex(PLC_MAC_DESC_ENGINE_MID); desc_eng->free_num_min[i] = desc_eng->mem_pool[i].num; #if PLC_MEM_ALLOC_STAT { /* calculate the desc memory usage */ total_bytes += cfg[i].desc_num * cfg[i].desc_size; iot_printf("__desc__%d: num %d x size %d = %d bytes \n", \ i, cfg[i].desc_num, cfg[i].desc_size, cfg[i].desc_num * cfg[i].desc_size); } #endif } #if PLC_MEM_ALLOC_STAT iot_printf("totally: %d bytes\n", total_bytes); #endif #if PLC_MEM_ALLOC_STAT > 1 desc_eng->desc_req_cnt = 0; #endif } return 0; } void mac_desc_info_dump_force(mac_desc_engine_t *desc_eng) { iot_dbglog_input(PLC_MAC_DESC_ENGINE_MID, DBGLOG_ERR, IOT_MAC_DESC1_ID, 8, desc_eng->used[PLC_MAC_MSDU_POOL], (desc_eng->mem_pool[PLC_MAC_MSDU_POOL].num << 16 | desc_eng->free_num_min[PLC_MAC_MSDU_POOL]), desc_eng->used[PLC_MAC_PEER_POOL], (desc_eng->mem_pool[PLC_MAC_PEER_POOL].num << 16 | desc_eng->free_num_min[PLC_MAC_PEER_POOL]), desc_eng->used[PLC_MAC_STREAM_POOL], (desc_eng->mem_pool[PLC_MAC_STREAM_POOL].num << 16 | desc_eng->free_num_min[PLC_MAC_STREAM_POOL]), desc_eng->used[PLC_TX_MPDU_START_POOL], (desc_eng->mem_pool[PLC_TX_MPDU_START_POOL].num << 16 | desc_eng->free_num_min[PLC_TX_MPDU_START_POOL])); iot_dbglog_input(PLC_MAC_DESC_ENGINE_MID, DBGLOG_ERR, IOT_MAC_DESC2_ID, 8, desc_eng->used[PLC_TX_MPDU_END_POOL], (desc_eng->mem_pool[PLC_TX_MPDU_END_POOL].num << 16 | desc_eng->free_num_min[PLC_TX_MPDU_END_POOL]), desc_eng->used[PLC_TX_PB_START_POOL], (desc_eng->mem_pool[PLC_TX_PB_START_POOL].num << 16 | desc_eng->free_num_min[PLC_TX_PB_START_POOL]), desc_eng->used[PLC_RX_PB_DESC_POOL], (desc_eng->mem_pool[PLC_RX_PB_DESC_POOL].num << 16 | desc_eng->free_num_min[PLC_RX_PB_DESC_POOL]), desc_eng->used[PLC_SCHED_CMD_LIST_POOL], (desc_eng->mem_pool[PLC_SCHED_CMD_LIST_POOL].num << 16 | desc_eng->free_num_min[PLC_SCHED_CMD_LIST_POOL])); iot_dbglog_input(PLC_MAC_DESC_ENGINE_MID, DBGLOG_ERR, IOT_MAC_DESC3_ID, 4, desc_eng->used[PLC_TX_DUMMY_NODE_POOL], (desc_eng->mem_pool[PLC_TX_DUMMY_NODE_POOL].num << 16 | desc_eng->free_num_min[PLC_TX_DUMMY_NODE_POOL]), desc_eng->used[PLC_MAC_MSDU_FRAME_POOL], (desc_eng->mem_pool[PLC_MAC_MSDU_FRAME_POOL].num << 16 | desc_eng->free_num_min[PLC_MAC_MSDU_FRAME_POOL])); } void mac_desc_info_dump(mac_desc_engine_t *desc_eng) { if (++g_mac_desc_period_30_min_cnt >= MAC_DESC_PERIOD_30_MIN) { mac_desc_info_dump_force(desc_eng); g_mac_desc_period_30_min_cnt = 0; } } /* alloc a desc as requested type */ uint32_t mac_desc_get(mac_desc_engine_t *desc_eng, \ mac_desc_pool_type_t desc_type, \ void **desc_ptr) { if (desc_eng == NULL || desc_type >= MAX_PLC_DESC_POOL_NUM \ || desc_ptr == NULL) { IOT_ASSERT(0); return ERR_INVAL; } *desc_ptr = iot_mem_pool_alloc(&desc_eng->mem_pool[desc_type]); if (*desc_ptr == NULL) { #if DEBUG_RX_PB_CNT_NOT_ENOUGH mac_desc_info_dump_force(desc_eng); g_mac_desc_period_30_min_cnt = 0; #endif return ERR_NOMEM; } if (desc_eng->free_num_min[desc_type] > desc_eng->mem_pool[desc_type].free_num) { desc_eng->free_num_min[desc_type] = (uint16_t)desc_eng->mem_pool[desc_type].free_num; } /* TODO: for some type, need zero */ switch (desc_type) { case PLC_MAC_PEER_POOL: case PLC_MAC_STREAM_POOL: case PLC_RX_PB_DESC_POOL: case PLC_MAC_MSDU_FRAME_POOL: { /* init at mac_create_peer() */ /* mac_create_stream() */ /* pb_buf_list_init() */ /* mac_frame_list_init() */ break; } case PLC_TX_DUMMY_NODE_POOL: { tx_dummy_node *dummy = *desc_ptr; dummy->tx_done = 0; dummy->next = 0; break; } case PLC_SCHED_CMD_LIST_POOL: { /* no need to zero */ break; } default: { /* zero by default */ os_mem_set(*desc_ptr, 0, \ desc_eng->mem_pool[desc_type].align_block_word_size << 2); } } os_acquire_mutex(desc_eng->mutex[desc_type]); desc_eng->used[desc_type]++; os_release_mutex(desc_eng->mutex[desc_type]); #if PLC_MEM_ALLOC_STAT > 1 if ((++desc_eng->desc_req_cnt & DESC_STAT_DISPLAY_FREQ) \ == DESC_STAT_DISPLAY_FREQ) { uint32_t total, used; char c_str_buf[128] = { 0 }; int32_t idx = 0; for (int i = 0; i < MAX_PLC_DESC_POOL_NUM; i++) { total = desc_eng->mem_pool[i].num; used = total - desc_eng->mem_pool[i].free_num; idx += iot_snprintf(c_str_buf + idx, \ sizeof(c_str_buf) - idx, \ "d%d:%d/%d;", i, used, total); } iot_printf("%s\n", c_str_buf); } #endif return 0; } uint32_t mac_desc_free(mac_desc_engine_t *desc_eng, \ mac_desc_pool_type_t desc_type, void *desc_ptr) { uint32_t ret; if (desc_eng == NULL || desc_ptr == NULL \ || desc_type >= MAX_PLC_DESC_POOL_NUM) { IOT_ASSERT(0); return ERR_INVAL; } ret = iot_mem_pool_free(&desc_eng->mem_pool[desc_type], \ desc_ptr); if (ret == 0) { os_acquire_mutex(desc_eng->mutex[desc_type]); desc_eng->used[desc_type]--; os_release_mutex(desc_eng->mutex[desc_type]); } return ret; } void mac_token_bucket_init() { /* TDMA 1,BCSMA 1 */ g_mac_token_bucket[BCSMA_TOKEN_BUCKET_IDX] = PLC_BCSMA_TOKEN_NUM; g_mac_token_bucket[TDMA_TOKEN_BUCKET_IDX] = PLC_TDMA_TOKEN_NUM; /* TODO: we need to consider the tx/rx buffer cnt * also, sometimes the buffer maybe not enough * if the MSDU are the long buffer cnt * currently assume 3/4 MSDU_FRAME_POOL_SIZE */ /* 4 csma token buckets: 2:3:3:4 */ #define DIVISOR 12 IOT_ASSERT(PLC_MAC_CSMA_TOKEN_NUM >= DIVISOR); #if USE_SHARED_CSMA_TOKEN /* in shared case, all token shared csma0, resv csma3 */ g_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX] = \ (PLC_MAC_CSMA_TOKEN_NUM / DIVISOR) * 0; g_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] = \ (PLC_MAC_CSMA_TOKEN_NUM / DIVISOR) * 0; g_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX] = \ (PLC_MAC_CSMA_TOKEN_NUM / DIVISOR) * 0; g_mac_token_bucket[CSMA0_TOKEN_BUCKET_IDX] = \ PLC_MAC_CSMA_TOKEN_NUM - \ g_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX] - \ g_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] - \ g_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX]; #else g_mac_token_bucket[CSMA0_TOKEN_BUCKET_IDX] = \ (PLC_MAC_CSMA_TOKEN_NUM /DIVISOR)*2; g_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX] = \ (PLC_MAC_CSMA_TOKEN_NUM /DIVISOR)*3; g_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] = \ (PLC_MAC_CSMA_TOKEN_NUM /DIVISOR)*3; g_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX] = \ PLC_MAC_CSMA_TOKEN_NUM - \ g_mac_token_bucket[CSMA0_TOKEN_BUCKET_IDX] - \ g_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX] - \ g_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX]; #endif IOT_ASSERT(PLC_MAC_MSDU_FRAME_POOL_SIZE >= \ g_mac_token_bucket[CSMA0_TOKEN_BUCKET_IDX] + \ g_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX] + \ g_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] + \ g_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX] + \ g_mac_token_bucket[BCSMA_TOKEN_BUCKET_IDX] + \ g_mac_token_bucket[TDMA_TOKEN_BUCKET_IDX]); #if HPLC_RF_DEV_SUPPORT /* TDMA ,BCSMA */ g_rf_mac_token_bucket[BCSMA_TOKEN_BUCKET_IDX] = RF_BCSMA_TOKEN_NUM; g_rf_mac_token_bucket[TDMA_TOKEN_BUCKET_IDX] = RF_TDMA_TOKEN_NUM; #if USE_SHARED_CSMA_TOKEN /* in shared case, all token shared csma0, resv csma3 */ g_rf_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX] = 0; g_rf_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] = 0; g_rf_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX] = 0; g_rf_mac_token_bucket[CSMA0_TOKEN_BUCKET_IDX] = RF_MAC_CSMA_TOKEN_NUM - g_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX] - g_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] - g_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX]; #else /* USE_SHARED_CSMA_TOKEN */ /* TODO: add code */ IOT_ASSERT(0); #endif /* USE_SHARED_CSMA_TOKEN */ #endif /* HPLC_RF_DEV_SUPPORT */ } void mac_check_peer_stream_desc() { uint32_t peer_used = g_mac_desc_eng.used[PLC_MAC_PEER_POOL]; uint32_t stream_used = g_mac_desc_eng.used[PLC_MAC_STREAM_POOL]; /* vdev and reduce vdev need self/bcast peer, always need 4 peer */ if (peer_used > 4 || stream_used != 0) { uint32_t data_dump[3]; for (uint32_t vdev_id = 0; vdev_id < MAX_VDEV_NUM; vdev_id++) { mac_vdev_t *vdev = get_vdev_ptr(0, vdev_id); data_dump[vdev_id] = vdev->peer_cnt << 16 | vdev->stream_cnt; } iot_printf("%s, pr_u:%d, sr_u:%d, \n", \ __FUNCTION__, peer_used, stream_used); data_dump[2] = peer_used << 16 | stream_used; IOT_ASSERT_DUMP(0, data_dump, 3 * sizeof(uint32_t)); } return; }