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

594 lines
14 KiB
C
Executable File

/****************************************************************************
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_hwq_mgr.h"
#include "plc_utils.h"
#include "plc_protocol.h"
#include "mac_txq_hw.h"
#include "mac_desc_engine.h"
#include "iot_errno.h"
#include "iot_io.h"
#include "mac_tx_hw.h"
/* init the hwq ctxt */
void mac_q_init(mac_queue_ctxt_t *queue)
{
IOT_ASSERT(queue);
if(!mac_txq_is_dbg_mode())
{
for (uint32_t i = 0; i < MAX_MAC_QUE_NUM; i++)
{
queue->hwq_map[i] = (uint8_t)INV_MAC_HWQ_ID;
}
for (uint32_t i = 0; i < MAX_MAC_TXQ_NUM; i++)
{
queue->last_desc[i] = NULL;
queue->cur_hdl_desc[i] = NULL;
queue->q_depth[i] = 0;
}
queue->last_hwq_id = 0;
}
else
{
for (uint32_t i = 0; i < MAX_MAC_DCU_NUM; i++)
{
queue->hwq_map[i] = (uint8_t)INV_MAC_HWQ_ID;
}
for (uint32_t i = 0; i < MAX_MAC_DCU_NUM; i++)
{
queue->last_desc[i] = NULL;
queue->cur_hdl_desc[i] = NULL;
queue->q_depth[i] = 0;
}
queue->last_hwq_id = 0;
}
}
/* get the real hwq mapping id
* @mac_que - sw queue that designated
* return - the real hwq id that mapping to MAC HW if allocated
* INV_MAC_HWQ_ID if not allocated
*/
uint8_t mac_q_get_hwqid(mac_queue_ctxt_t *queue, mac_queue_t qtype)
{
IOT_ASSERT(queue && qtype < MAX_MAC_QUE_NUM);
if (!mac_txq_is_dbg_mode()) {
/* if sch mode */
return queue->hwq_map[qtype];
}
else {
uint8_t qid;
/* if dbg mode */
if (qtype > MAC_QUE_BCN_C) {
qid = 3;
}
else {
qid = 0;
}
return qid;
}
}
/* find the first swq type for given hwqid
* return -1 if not found
*/
uint32_t mac_q_find_1st_swq_type(mac_queue_ctxt_t *queue, \
uint8_t hwqid)
{
IOT_ASSERT(queue && hwqid < MAX_MAC_TXQ_NUM);
uint32_t i;
for (i = 0; i < MAX_MAC_QUE_NUM; i++)
{
if (queue->hwq_map[i] == hwqid)
{
break;
}
}
if (i != MAX_MAC_QUE_NUM) {
return i;
}
else {
return (uint32_t)(~0);
}
}
/* alloc a hwq from mac queue type */
uint8_t mac_q_alloc_hwq(mac_queue_ctxt_t *queue, mac_queue_t qtype)
{
IOT_ASSERT(queue && qtype < MAX_MAC_QUE_NUM);
uint8_t qid;
if (!mac_txq_is_dbg_mode()) {
/* check if already allocated,
* TODO: handle the hwq reuse case,
* that is multi-swq share the same hwq
*/
qid = mac_q_get_hwqid(queue, qtype);
IOT_ASSERT(qid == INV_MAC_HWQ_ID);
/* start alloc a new hwq */
qid = queue->last_hwq_id;
IOT_ASSERT(qid < MAX_MAC_TXQ_NUM);
}
else {
/* if dbg mode */
if (qtype > MAC_QUE_BCN_C) {
qid = 3;
}
else {
qid = 0;
}
}
switch (qtype)
{
case MAC_QUE_BCN_A:
case MAC_QUE_BCN_B:
case MAC_QUE_BCN_C:
case MAC_QUE_TDMA_A:
case MAC_QUE_TDMA_B:
case MAC_QUE_TDMA_C:
case MAC_QUE_NB_BCN_A:
case MAC_QUE_NB_BCN_B:
case MAC_QUE_NB_BCN_C:
{
/* for tdma queue, cap is not used, fill 0 */
mac_txq_cfg(qid, 0, 0);
break;
}
case MAC_QUE_CSMA_A_0:
case MAC_QUE_CSMA_B_0:
case MAC_QUE_CSMA_C_0:
{
mac_txq_cfg(qid, 0, 1);
break;
}
case MAC_QUE_CSMA_A_1:
case MAC_QUE_CSMA_B_1:
case MAC_QUE_CSMA_C_1:
{
mac_txq_cfg(qid, 1, 1);
break;
}
case MAC_QUE_CSMA_A_2:
case MAC_QUE_CSMA_B_2:
case MAC_QUE_CSMA_C_2:
{
mac_txq_cfg(qid, 2, 1);
break;
}
case MAC_QUE_CSMA_A_3:
case MAC_QUE_CSMA_B_3:
case MAC_QUE_CSMA_C_3:
{
mac_txq_cfg(qid, 3, 1);
break;
}
case MAC_QUE_BCSMA_A:
case MAC_QUE_BCSMA_B:
case MAC_QUE_BCSMA_C:
{
/* for SG, BCSMA only allow one LID, and
* this LID usually > 3, so the
* cap should be set higher priority,
* fill 3 here.
*/
mac_txq_cfg(qid, 3, 1);
break;
}
default:
IOT_ASSERT(0);
}
/* record the mapping, and increase the last id */
queue->hwq_map[qtype] = (uint8_t)qid;
queue->last_hwq_id++;
//alloc_done:
return qid;
}
uint32_t mac_get_bcn_region_type(lid_t lid)
{
if (lid <= LID_CSMA_CAP3) {
/* csma */
return PLC_BCN_REGION_CSMA;
}
else if (lid >= LID_BCSMA_START && lid <= LID_BCSMA_END) {
/* tdma or bcsma */
return PLC_BCN_REGION_BCSMA;
}
else if (lid >= LID_TDMA_START && lid <= LID_TDMA_END) {
/* tdma */
return PLC_BCN_REGION_TDMA;
}
else {
/* unknown lid type */
IOT_ASSERT(0);
return PLC_BCN_REGION_CSMA;
}
}
uint8_t mac_token_check(uint32_t bcn_region_type, lid_t lid, uint8_t is_rf)
{
token_num_t *token_bucket = NULL;
#if USE_SHARED_CSMA_TOKEN
lid = LID_CSMA_CAP0;
#endif
#if HPLC_RF_DEV_SUPPORT
if (is_rf) {
token_bucket = g_rf_mac_token_bucket;
} else {
token_bucket = g_mac_token_bucket;
}
#else
(void)is_rf;
token_bucket = g_mac_token_bucket;
#endif
switch (bcn_region_type) {
case PLC_BCN_REGION_CSMA:
{
switch (lid) {
case LID_CSMA_CAP0:
{
if (!token_bucket[CSMA0_TOKEN_BUCKET_IDX]) {
return ERR_NOMEM;
}
break;
}
case LID_CSMA_CAP1:
{
if (!token_bucket[CSMA1_TOKEN_BUCKET_IDX]) {
return ERR_NOMEM;
}
break;
}
case LID_CSMA_CAP2:
{
if (!token_bucket[CSMA2_TOKEN_BUCKET_IDX]) {
return ERR_NOMEM;
}
break;
}
case LID_CSMA_CAP3:
{
if (!token_bucket[CSMA3_TOKEN_BUCKET_IDX]) {
return ERR_NOMEM;
}
break;
}
default:
break;
}
break;
}
case PLC_BCN_REGION_BCSMA:
{
if (!token_bucket[BCSMA_TOKEN_BUCKET_IDX]) {
return ERR_NOMEM;
}
break;
}
case PLC_BCN_REGION_TDMA:
{
if (!token_bucket[TDMA_TOKEN_BUCKET_IDX]) {
return ERR_NOMEM;
}
break;
}
default:
break;
}
return ERR_OK;
}
void mac_token_alloc(uint32_t bcn_region_type, lid_t lid, uint8_t is_rf)
{
token_num_t *token_bucket = NULL;
#if USE_SHARED_CSMA_TOKEN
lid = LID_CSMA_CAP0;
#endif
#if HPLC_RF_DEV_SUPPORT
if (is_rf) {
token_bucket = g_rf_mac_token_bucket;
} else {
token_bucket = g_mac_token_bucket;
}
#else
(void)is_rf;
token_bucket = g_mac_token_bucket;
#endif
switch (bcn_region_type)
{
case PLC_BCN_REGION_CSMA:
{
switch (lid) {
case LID_CSMA_CAP0:
{
IOT_ASSERT(token_bucket[CSMA0_TOKEN_BUCKET_IDX]);
token_bucket[CSMA0_TOKEN_BUCKET_IDX]--;
break;
}
case LID_CSMA_CAP1:
{
IOT_ASSERT(token_bucket[CSMA1_TOKEN_BUCKET_IDX]);
token_bucket[CSMA1_TOKEN_BUCKET_IDX]--;
break;
}
case LID_CSMA_CAP2:
{
IOT_ASSERT(token_bucket[CSMA2_TOKEN_BUCKET_IDX]);
token_bucket[CSMA2_TOKEN_BUCKET_IDX]--;
break;
}
case LID_CSMA_CAP3:
{
IOT_ASSERT(token_bucket[CSMA3_TOKEN_BUCKET_IDX]);
token_bucket[CSMA3_TOKEN_BUCKET_IDX]--;
break;
}
default:
break;
}
break;
}
case PLC_BCN_REGION_BCSMA:
{
IOT_ASSERT(token_bucket[BCSMA_TOKEN_BUCKET_IDX]);
token_bucket[BCSMA_TOKEN_BUCKET_IDX]--;
break;
}
case PLC_BCN_REGION_TDMA:
{
IOT_ASSERT(token_bucket[TDMA_TOKEN_BUCKET_IDX]);
token_bucket[TDMA_TOKEN_BUCKET_IDX]--;
break;
}
default:
break;
}
}
void mac_token_free(uint32_t bcn_region_type, lid_t lid, uint8_t is_rf)
{
token_num_t *token_bucket = NULL;
#if USE_SHARED_CSMA_TOKEN
lid = LID_CSMA_CAP0;
#endif
#if HPLC_RF_DEV_SUPPORT
if (is_rf) {
token_bucket = g_rf_mac_token_bucket;
} else {
token_bucket = g_mac_token_bucket;
}
#else
(void)is_rf;
token_bucket = g_mac_token_bucket;
#endif
switch (bcn_region_type)
{
case PLC_BCN_REGION_CSMA:
{
switch (lid) {
case LID_CSMA_CAP0:
{
token_bucket[CSMA0_TOKEN_BUCKET_IDX]++;
break;
}
case LID_CSMA_CAP1:
{
token_bucket[CSMA1_TOKEN_BUCKET_IDX]++;
break;
}
case LID_CSMA_CAP2:
{
token_bucket[CSMA2_TOKEN_BUCKET_IDX]++;
break;
}
case LID_CSMA_CAP3:
{
token_bucket[CSMA3_TOKEN_BUCKET_IDX]++;
break;
}
default:
break;
}
break;
}
case PLC_BCN_REGION_BCSMA:
{
token_bucket[BCSMA_TOKEN_BUCKET_IDX]++;
break;
}
case PLC_BCN_REGION_TDMA:
{
token_bucket[TDMA_TOKEN_BUCKET_IDX]++;
break;
}
default:
break;
}
}
mac_queue_t mac_q_get_swq_type(uint32_t bcn_region_type, \
uint32_t phase, lid_t lid)
{
switch (bcn_region_type)
{
case PLC_BCN_REGION_BCN:
switch (phase)
{
case PLC_PHASE_A:
return MAC_QUE_BCN_A;
case PLC_PHASE_B:
return MAC_QUE_BCN_B;
case PLC_PHASE_C:
return MAC_QUE_BCN_C;
default:
IOT_ASSERT(0);
}
break;
case PLC_BCN_REGION_CSMA:
IOT_ASSERT(lid < 4 \
&& (phase <= PLC_PHASE_CNT) \
&& (phase != PLC_PHASE_ALL)
);
return MAC_QUE_CSMA_A_0 + (phase - 1) * 4 + lid;
break;
case PLC_BCN_REGION_TDMA:
IOT_ASSERT(lid >= 4 \
&& (phase <= PLC_PHASE_CNT) \
&& (phase != PLC_PHASE_ALL)
);
return MAC_QUE_TDMA_A + (phase - 1);
break;
case PLC_BCN_REGION_BCSMA:
IOT_ASSERT(lid >= 4);
return MAC_QUE_BCSMA_A + (phase - 1);
break;
case PLC_BCN_REGION_NBBCN:
return MAC_QUE_NB_BCN_A + (phase - 1);
default:
IOT_ASSERT(0);
}
/* should not reach here */
return MAX_MAC_QUE_NUM;
}
uint32_t mac_q_get_swqid_from_phase_lid(mac_queue_ctxt_t *queue, \
uint32_t phase, lid_t lid)
{
(void)queue;
uint32_t bcn_region_type;
mac_queue_t swq_id;
/* calulate hwqid */
if (lid <= LID_CSMA_CAP3) {
/* csma */
bcn_region_type = PLC_BCN_REGION_CSMA;
}
else if (lid >= LID_BCSMA_START && lid <= LID_BCSMA_END) {
/* tdma or bcsma */
bcn_region_type = PLC_BCN_REGION_BCSMA;
}
else if (lid >= LID_TDMA_START && lid <= LID_TDMA_END) {
/* tdma */
bcn_region_type = PLC_BCN_REGION_TDMA;
}
else {
/* unknown lid type */
bcn_region_type = PLC_BCN_REGION_CSMA;
IOT_ASSERT(0);
}
swq_id = mac_q_get_swq_type(bcn_region_type, \
phase, (lid_t)lid);
/* check if swq type is support */
if (swq_id == MAX_MAC_QUE_NUM)
{
/* swq type error */
IOT_ASSERT(0);
}
return swq_id;
}
uint32_t mac_q_create_hwqid_from_swqid(mac_queue_ctxt_t *queue, \
mac_queue_t swq_id)
{
uint32_t hwqid;
/* check if the hwq already enabled */
hwqid = mac_q_get_hwqid(queue, swq_id);
if (hwqid == INV_MAC_HWQ_ID) {
/* hw queue is not enabled, try to alloc it */
hwqid = mac_q_alloc_hwq(queue, swq_id);
}
return hwqid;
}
uint32_t mac_block_all_tx_ena(mac_queue_ctxt_t *tx_ctxt, uint32_t ena)
{
IOT_ASSERT(tx_ctxt);
ena = (ena == 0) ? 0 : 1;
if (tx_ctxt->is_block_all_tx == ena) {
return ERR_EXIST;
}
tx_ctxt->is_block_all_tx = (uint8_t)ena;
for (uint8_t qid = 0; qid < tx_ctxt->last_hwq_id; qid++) {
if (ena) {
/* disable all hwq to block hw tx */
mac_txq_enable(qid, NULL);
} else {
/* recover and ena hwq*/
if (tx_ctxt->q_depth[qid] != 0) {
IOT_ASSERT(tx_ctxt->cur_hdl_desc[qid]);
mac_txq_enable(qid, tx_ctxt->cur_hdl_desc[qid]);
}
}
}
return ERR_OK;
}
uint32_t mac_is_block_all_tx(mac_queue_ctxt_t *tx_ctxt)
{
IOT_ASSERT(tx_ctxt);
return tx_ctxt->is_block_all_tx;
}
uint8_t mac_get_csma_token_usage_rate()
{
uint16_t token_cnt;
token_cnt = 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] -
g_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX];
return (uint8_t)(token_cnt * 100 / PLC_MAC_CSMA_TOKEN_NUM);
}
uint8_t mac_get_rf_csma_token_usage_rate()
{
#if HPLC_RF_DEV_SUPPORT
uint16_t token_cnt;
token_cnt = RF_MAC_CSMA_TOKEN_NUM -
g_rf_mac_token_bucket[CSMA0_TOKEN_BUCKET_IDX] -
g_rf_mac_token_bucket[CSMA1_TOKEN_BUCKET_IDX] -
g_rf_mac_token_bucket[CSMA2_TOKEN_BUCKET_IDX] -
g_rf_mac_token_bucket[CSMA3_TOKEN_BUCKET_IDX];
return (uint8_t)(token_cnt * 100 / RF_MAC_CSMA_TOKEN_NUM);
#else
return 0;
#endif
}