594 lines
14 KiB
C
Executable File
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
|
|
} |