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

744 lines
25 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 "iot_config.h"
#include "mac_rf_tx_hw.h"
#if HW_PLATFORM == HW_PLATFORM_SIMU
#include "simulator_txrx.h"
#endif
#include "iot_errno.h"
#include "iot_io.h"
#include "iot_system.h"
#include "mac_pdev.h"
#include "mac_vdev.h"
#include "mac_rf_vdev.h"
#include "mac_desc_engine.h"
#include "mac_tx_hw.h"
#include "iot_bitops.h"
#include "mac_rf_hwq_mgr.h"
#include "mac_rf_tx_hw.h"
#include "mpdu_frame.h"
#include "sw_sched.h"
#include "iot_ftm_internal.h"
#include "hw_war.h"
#include "mac_status.h"
#include "mac_cert_test.h"
#if HPLC_RF_DEV_SUPPORT
#include "mac_rf_txq_hw.h"
#include "rf_tx_mpdu_desc.h"
#include "rf_tx_desc_reg_api.h"
#include "mac_rf_sched_hw.h"
/* check if the queue has pending desc
* 0 - means no desc pending
* others - means have desc pending
*/
uint32_t mac_rf_tx_hwq_mpdu_pending(mac_rf_queue_ctxt_t *tx_ctxt,
uint32_t hwq_id)
{
rf_tx_mpdu_start *mpdu;
rf_tx_dummy_node *dummy;
uint32_t tx_done = 1; /* init as 1 for warning */
for (dummy = tx_ctxt->cur_hdl_desc[hwq_id]; dummy;
dummy = (rf_tx_dummy_node *)dummy->next) {
/* check if any desc is not done */
if (dummy->desc_type == DESC_TYPE_TX_DUMMY) {
/* if dummy node desc */
continue;
} else if (dummy->desc_type == DESC_TYPE_TX_MPDU_START) {
/* if mpdu start desc */
mpdu = (rf_tx_mpdu_start *)dummy;
rf_tx_mpdu_end *end = mpdu->tx_status;
IOT_ASSERT(end);
tx_done = end->tx_done;
} else {
/* should not other desc currently */
IOT_ASSERT(0);
}
if (!tx_done) {
return 1;
}
}
return 0;
}
/* return 0 - means E_OK
* else - means not all resource recycled
* if disable_hwq set, its mean mac reinit, need flush all sw pkt and dummy,
* then stop hwq; else keep hwq status.
*/
uint32_t mac_rf_tx_flush_hwq(mac_rf_queue_ctxt_t *tx_ctxt, uint32_t qid,
uint8_t disable_hwq)
{
uint32_t is_enable, ret;
is_enable = mac_rf_txq_is_enable(qid);
if (tx_ctxt->q_depth[qid] == 0) {
IOT_ASSERT(is_enable == 0);
return ERR_OK;
}
if (is_enable) {
/* disable txq */
mac_rf_txq_force_disable(qid);
}
/* mark tx done for each desc */
rf_tx_mpdu_start *mpdu;
rf_tx_mpdu_end *end;
rf_tx_dummy_node *dummy;
rf_tx_dummy_node *last_node;
/* enq a dummy at hwq last position, then comp func can free all mpdu */
last_node = (rf_tx_dummy_node *)tx_ctxt->last_desc[qid];
if (last_node->desc_type != DESC_TYPE_TX_DUMMY) {
ret = mac_desc_get(&g_mac_desc_eng, PLC_TX_DUMMY_NODE_POOL,
(void**)&dummy);
IOT_ASSERT(ret == 0);
mac_rf_tx_mpdu_fill_dummy((rf_tx_dummy_node *)dummy);
mac_rf_tx_hw_mpdu(tx_ctxt, qid, (rf_tx_mpdu_start*)dummy);
}
for (dummy = tx_ctxt->cur_hdl_desc[qid]; dummy;
dummy = (rf_tx_dummy_node *)dummy->next)
{
/* check if any desc is not done */
if (dummy->desc_type == DESC_TYPE_TX_DUMMY) {
/* if dummy node desc */
dummy->tx_done = 1;
continue;
} else if (dummy->desc_type == DESC_TYPE_TX_MPDU_START) {
/* if mpdu start desc */
mpdu = (rf_tx_mpdu_start *)dummy;
end = mpdu->tx_status;
IOT_ASSERT(end);
/* mark done */
mpdu->notify_hw_tx_done = 1;
end->tx_done = 1;
end->tx_ok = 0;
/* sw filter */
end->tx_status = 1;
} else {
/* should not other desc currently */
IOT_ASSERT(0);
}
}
ret = mac_rf_tx_hw_mpdu_comp(qid);
/* after flush, hwq must only one dummy in it, and hwq is closed */
last_node = (rf_tx_dummy_node *)tx_ctxt->last_desc[qid];
if (last_node == NULL || last_node->desc_type != DESC_TYPE_TX_DUMMY ||
mac_rf_txq_is_enable(qid) || tx_ctxt->q_depth[qid] != 1) {
IOT_ASSERT(0);
}
/* recover hwq */
if (is_enable && disable_hwq == 0) {
/* enq dummy and enable hwq */
mac_rf_txq_enable(qid, tx_ctxt->last_desc[qid]);
} else {
/* flush dummy, and keep hwq closed */
mac_desc_free(&g_mac_desc_eng, PLC_TX_DUMMY_NODE_POOL,
tx_ctxt->last_desc[qid]);
tx_ctxt->last_desc[qid] = NULL;
tx_ctxt->cur_hdl_desc[qid] = NULL;
tx_ctxt->q_depth[qid] = 0;
}
return ret;
}
void mac_rf_tx_flush_bcsma_pending_queue(mac_rf_queue_ctxt_t *tx_ctxt)
{
IOT_ASSERT(tx_ctxt);
/* get swq type id */
uint32_t swq_id = mac_rf_q_get_swq_type(PLC_BCN_REGION_BCSMA,
LID_BCSMA_START, 0);
if (tx_ctxt->q_depth[swq_id] > RF_BCSMA_Q_WARNING_DEPTH) {
mac_rf_tx_flush_hwq(tx_ctxt, swq_id, 0);
iot_printf("mac rf flush bcsma pkt.\n");
}
}
uint32_t mac_rf_tx_flush_all_tdma_queue(mac_rf_queue_ctxt_t *tx_ctxt)
{
for (uint32_t i = 0; i < tx_ctxt->last_hwq_id; i++) {
/* look for every tdma queue */
if (!mac_rf_txq_is_csma(i)) {
/* tdma */
if (mac_rf_tx_hwq_mpdu_pending(tx_ctxt, i)) {
/* if pending desc */
mac_rf_tx_flush_hwq(tx_ctxt, i, 0);
}
}
}
return 0;
}
uint32_t mac_rf_tx_flush_all_queue(mac_rf_queue_ctxt_t *tx_ctxt)
{
mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(PLC_PDEV_ID, RF_PDEV_ID,
PLC_DEFAULT_VDEV);
if (mac_rf_sched_get_enable(rf_vdev)) {
iot_printf("%s, need stop sche\n");
IOT_ASSERT(0);
}
/* flush all hwq */
for (uint32_t i = 0; i <= tx_ctxt->last_hwq_id; i++) {
mac_rf_tx_flush_hwq(tx_ctxt, i, 1);
}
return 0;
}
uint32_t mac_rf_csma_bcn_flush(mac_rf_queue_ctxt_t *tx_ctxt)
{
uint32_t ret = 1;
#if ENA_RF_CSMA_BCN_HWQ
IOT_ASSERT(tx_ctxt);
/* get swq type id */
uint32_t swq_id = mac_rf_q_get_swq_type(PLC_BCN_REGION_CSMA,
LID_CSMA_CAP3, 0);
if (mac_rf_tx_hwq_mpdu_pending(tx_ctxt, swq_id)) {
/* if pending desc */
mac_rf_tx_flush_hwq(tx_ctxt, swq_id, 0);
iot_printf("mac rf flush csma bcn\n");
/* record flush csma bcn cnt */
mac_add_flush_tx_bcsma_cnt();
ret = 0;
}
/* if return 1 -> no pending packet.
* if return 0 -> packet flushed.
*/
#else
(void)tx_ctxt;
#endif
return ret;
}
void mac_rf_tx_mpdu_fill_pb_start(rf_tx_pb_start *pb, void *buf_addr,
uint32_t pb_seq, uint32_t msdu_start, uint32_t msdu_end, uint32_t proto)
{
IOT_ASSERT(pb);
pb->pb_buf_addr = (uint32_t)buf_addr;
#if SUPPORT_SMART_GRID
if (PLC_PROTO_TYPE_SG == proto)
{
sg_sof_pb_hdr_t *hdr =
(sg_sof_pb_hdr_t *)&pb->sof_pb_header; //pb header
hdr->mac_frame_end = msdu_end & 0x1;
hdr->mac_frame_start = msdu_start & 0x1;
hdr->seq = pb_seq & 0x3f;
} else
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
if (PLC_PROTO_TYPE_SPG == proto)
{
spg_sof_pb_hdr_t *hdr =
(spg_sof_pb_hdr_t *)&pb->sof_pb_header; //pb header
hdr->seq = pb_seq & 0x3f;
} else
#endif
{
//todo
}
(void)pb_seq;
(void)msdu_start;
(void)msdu_end;
(void)proto;
}
uint32_t mac_rf_tx_mpdu_form_pb(rf_tx_pb_start **pb_ptr,
iot_pkt_t *pkt_buf, uint32_t bitmap, uint32_t pb_sz)
{
uint32_t proto = PHY_PROTO_TYPE_GET();
rf_tx_pb_start *pb_start = NULL;
uint8_t send_pb_num = 1;
uint8_t pb_hdr_resv_crc_len = mac_get_pb_hdr_resv_crc_len(
FC_DELIM_SOF, proto);
uint32_t buf_len = iot_pkt_block_len(pkt_buf, IOT_PKT_BLOCK_DATA);
uint32_t all_pb_num = iot_ceil(buf_len, (pb_sz - pb_hdr_resv_crc_len));
for (uint32_t i = 0; i < all_pb_num; i++) {
if (!send_pb_num && 0 == (bitmap >> i))
break;
if (bitmap & (0x1 << i)) {
send_pb_num--;
if (pb_start == NULL) {
mac_desc_get(&g_mac_desc_eng, PLC_TX_PB_START_POOL,
(void**)&pb_start);
IOT_ASSERT(pb_start != NULL);
}
/*fill pb start desc*/
iot_printf("--rf send pb, ssn=%d\n", i);
mac_rf_tx_mpdu_fill_pb_start(pb_start,
iot_pkt_data(pkt_buf) + i * (pb_sz - pb_hdr_resv_crc_len),
i, (i == 0 ? 1 : 0), ((i == (all_pb_num - 1)) ? 1 : 0), proto);
}
}
*pb_ptr = pb_start;
return 0;
}
static void mac_rf_csma_tx_check()
{
#if ENA_RF_MULTI_CSMA_HWQ_WAR
if (g_fw_mode == MM_MODE) {
mac_dsr_set(MAC_RF_DSR_CSMA_TX_CHECK_ID);
} else {
ftm_dsr_set(MAC_RF_DSR_CSMA_TX_CHECK_ID);
}
#endif
}
uint32_t mac_rf_tx_hw_mpdu(mac_rf_queue_ctxt_t *tx_ctxt, uint32_t hwq_id,
rf_tx_mpdu_start *mpdu)
{
rf_tx_mpdu_start *last_desc = NULL;
if (tx_ctxt->cur_hdl_desc[hwq_id]) {
/* if enabled before, there must be valid last_desc */
/* attach the mpdu after the last desc */
last_desc = (rf_tx_mpdu_start*)tx_ctxt->last_desc[hwq_id];
IOT_ASSERT(last_desc);
void **ptr = (void**)&last_desc->next;
*ptr = mpdu;
/* trigger bbcpu */
mac_rf_csma_tx_check();
} else {
/* if queue disabled */
if (NULL == tx_ctxt->cur_hdl_desc[hwq_id]) {
/* if never enabled, it would be empty,
* so just set cur ptr
*/
tx_ctxt->cur_hdl_desc[hwq_id] = mpdu;
} else {
/* if have cur, it may be enabled before,
* so should have valid last_desc */
last_desc = (rf_tx_mpdu_start*)tx_ctxt->last_desc[hwq_id];
IOT_ASSERT(last_desc && (last_desc->next == NULL));
void **ptr = (void**)&last_desc->next;
*ptr = mpdu;
}
/* enable the queue*/
/* start from the enq mpdu */
mac_rf_txq_enable(hwq_id, tx_ctxt->cur_hdl_desc[hwq_id]);
}
/* mpdu may be a list */
for (rf_tx_mpdu_start *tmp = (rf_tx_mpdu_start *)mpdu;
tmp != NULL; tmp = tmp->next) {
last_desc = tmp;
tx_ctxt->q_depth[hwq_id]++;
}
tx_ctxt->last_desc[hwq_id] = (void*)last_desc;
/* NOTE: hplc2rf cert mode crash issue.
* the interval of hplc is smaller than rf tx.
* so if cert mode, not care q_depth.
*/
/* bcn Q depth should less than 3, 2 mpdu and 1 dummy */
if ((mac_get_cert_test_mode() == 0) &&
(hwq_id == MAC_RF_QUE_BCN) &&
(tx_ctxt->q_depth[hwq_id] > BCN_WARNING_DEPTH)) {
rf_tx_mpdu_start *cur_ptr =
(rf_tx_mpdu_start*)tx_ctxt->cur_hdl_desc[hwq_id];
uint16_t mpdu_hold_cnt = 0;
for (uint16_t i = 0; i < tx_ctxt->q_depth[hwq_id]; i++) {
IOT_ASSERT(cur_ptr);
uint32_t type = cur_ptr->desc_type;
uint32_t done = (type == DESC_TYPE_TX_MPDU_START) ?
cur_ptr->tx_status->tx_done :
((rf_tx_dummy_node*)cur_ptr)->tx_done;
iot_printf("cur rf node type = %d, done = %d\n", type, done);
if (done == 0 && type == DESC_TYPE_TX_MPDU_START) {
mpdu_hold_cnt++;
}
cur_ptr = cur_ptr->next;
}
/* NOTE: sometimes, tXdone event has occurred,
* but has not yet been processed.
*/
if (mpdu_hold_cnt > 1) {
IOT_ASSERT(0);
}
}
/* send the packet in hwq immediately */
mac_rf_txq_trigger_send(hwq_id);
return 0;
}
uint32_t mac_rf_tx_hw_mpdu_comp(uint32_t hwq_id)
{
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, RF_PDEV_ID);
mac_vdev_t *vdev;
mac_rf_vdev_t *rf_vdev;
rf_tx_mpdu_start *next_ptr;
rf_tx_mpdu_end *mpdu_ed;
rf_tx_dummy_node *dummy_node;
rf_tx_mpdu_start *current_mpdu = \
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id];
uint32_t need_trigger_swq = 0;
uint32_t ret = ERR_OK;
/* mac proto */
uint32_t proto = PHY_PROTO_TYPE_GET();
uint32_t delimiter_type;
void *fc;
mac_msdu_t *free_msdu;
#if RF_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1
/* log the enter of this functon */
iot_printf("rf hwq:%d tx_done\n", hwq_id);
#endif
while (current_mpdu) {
fc = mac_rf_tx_mpdu_st_get_phy_header(current_mpdu);
/*current node is mpdu*/
if (current_mpdu->desc_type == DESC_TYPE_TX_MPDU_START) {
mpdu_ed = current_mpdu->tx_status;
IOT_ASSERT(mpdu_ed);
vdev = find_vdev_by_nid(PLC_PDEV_ID, \
mac_get_nid_from_fc(proto, fc));
rf_vdev = get_rf_vdev_ptr(PLC_PDEV_ID, RF_PDEV_ID, vdev->rf_vdev_id);
IOT_ASSERT(vdev && rf_vdev);
if (mpdu_ed->tx_done == 0) {
/* if not done then back next time */
break;
}
/* if the last desc process done by HW,
* put a dummy desc after it, hw would keep
* polling at the last node
*/
if (current_mpdu->next == NULL) {
ret = mac_desc_get(&g_mac_desc_eng, \
PLC_TX_DUMMY_NODE_POOL, \
(void**)&dummy_node);
IOT_ASSERT(ret == 0);
/* init the dummy node */
if(rf_vdev->stop_flag == 1){
dummy_node->tx_done = 1;
}
dummy_node->desc_type = DESC_TYPE_TX_DUMMY;
/* en hwq */
mac_rf_tx_hw_mpdu(&rf_pdev->hwq_hdl, \
hwq_id, (rf_tx_mpdu_start*)dummy_node);
#if RF_MAC_TX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_1
iot_printf("rf dummy end\n");
#endif
/*
* dummy would generate TX INT, so no
* need to back again
* ret = ERR_AGAIN;
*/
if(rf_vdev->stop_flag == 0){
ret = ERR_OK;
break;
}
}
else {
/* check if we can free something */
next_ptr = (rf_tx_mpdu_start*)current_mpdu->next;
if (next_ptr->desc_type == DESC_TYPE_TX_MPDU_START) {
if (!next_ptr->tx_status->tx_done) {
ret = ERR_OK;
break;
}
}
else if (next_ptr->desc_type == DESC_TYPE_TX_DUMMY) {
dummy_node = (rf_tx_dummy_node*)next_ptr;
if (!dummy_node->tx_done) {
/*
* dummy would generate TX INT, so no
* need to back again
* ret = ERR_AGAIN;
*/
ret = ERR_OK;
break;
}
}
else {
IOT_ASSERT(0);
}
}
/* now we can free the mpdu */
#if RF_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1
/* log the every tx done mpdu */
rx_fc_msg_t rx_fc_msg = {0};
mac_rf_get_rx_frm_msg_from_fc(proto, fc, &rx_fc_msg);
if ((FC_DELIM_SOF == rx_fc_msg.delimiter) &&
current_mpdu->need_ack) {
/* unicast sof */
iot_printf("rf ++tx ok=0x%x,tx done=0x%x"
",ntb=%lu,dtei:%d,sackrlt:%d.",
mpdu_ed->tx_ok, mpdu_ed->tx_done, mpdu_ed->first_try_ts,
rx_fc_msg.dst_tei, mpdu_ed->rx_sack_ok);
} else {
/* other frame */
iot_printf("--rf tx done=0x%x"
",ntb=%lu,delim=%d.", mpdu_ed->tx_done,
mpdu_ed->first_try_ts, rx_fc_msg.delimiter);
}
if (mpdu_ed->total_retry_cnt) {
iot_printf("HW_R_C:%d", mpdu_ed->total_retry_cnt);
}
/* check tx abort */
if (mpdu_ed->tx_status) {
iot_printf("tx_abort:reason=%d", mpdu_ed->tx_status);
}
iot_printf("\n");
#endif /* RF_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1 */
delimiter_type = mac_get_delimi_from_fc(proto, fc);
switch (delimiter_type) {
case FC_DELIM_BEACON: {
/*set new cur_ptr*/
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id] = \
(void*)(current_mpdu->next);
/* bcn's pb buf is not freed currently */
if (!current_mpdu->pb_buf_reuse) {
if (current_mpdu->is_msdu) {
/* bcn should not set msdu type */
IOT_ASSERT(0);
}
else {
/* free the pb buf in mpdu way,
* in this condition, all pb
* share the same offset
*/
rf_tx_pb_start *pb = current_mpdu->pb;
if (pb) {
iot_pkt_t *pkt = \
(iot_pkt_t*)(pb->pb_buf_addr \
- current_mpdu->sw_buf_offset);
iot_pkt_free(pkt);
}
}
}
if(!current_mpdu->tx_desc_reuse)
{
/*free desc*/
ret = mac_desc_free(&g_mac_desc_eng, \
PLC_TX_PB_START_POOL, \
current_mpdu->pb);
IOT_ASSERT(ERR_OK == ret);
current_mpdu->pb = NULL;
ret = mac_desc_free(&g_mac_desc_eng, \
PLC_TX_MPDU_END_POOL, \
current_mpdu->tx_status);
IOT_ASSERT(ERR_OK == ret);
current_mpdu->tx_status = NULL;
ret = mac_desc_free(&g_mac_desc_eng, \
PLC_TX_MPDU_START_POOL, \
current_mpdu);
IOT_ASSERT(ERR_OK == ret);
}
/* hwq depth subtract 1 */
rf_pdev->hwq_hdl.q_depth[hwq_id]--;
break;
}
case FC_DELIM_SOF: {
free_msdu = NULL;
/*msdu comp*/
if (current_mpdu->is_msdu) {
/* if pb buf reuse, then msdu need be freed */
free_msdu = mac_rf_tx_hw_msdu_comp(hwq_id, current_mpdu,
rf_pdev);
need_trigger_swq = 1;
} else if (!current_mpdu->pb_buf_reuse) {
//TODO:need ftm to the same as mm
if (g_fw_mode != FTM_MODE) {
/* if pb buf is not continuous,
* use the following method
*/
rf_tx_pb_start *pb = current_mpdu->pb;
IOT_ASSERT(pb);
iot_pkt_t *pkt = (iot_pkt_t*) (pb->pb_buf_addr
- current_mpdu->sw_buf_offset);
iot_pkt_free(pkt);
} else {
/* free the pb buf in one pkt buf,
* only support ftm mode
*/
rf_tx_pb_start *pb = current_mpdu->pb;
IOT_ASSERT(pb);
iot_pkt_t *pkt = (iot_pkt_t*) (pb->pb_buf_addr
- current_mpdu->sw_buf_offset);
iot_pkt_free(pkt);
}
}
/*set new cur_ptr*/
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id] = \
(void*)(current_mpdu->next);
if(!current_mpdu->tx_desc_reuse)
{
/*free pb list*/
if (current_mpdu->pb != NULL) {
rf_tx_pb_start *pb = current_mpdu->pb;
mac_desc_free(&g_mac_desc_eng, \
PLC_TX_PB_START_POOL, pb);
current_mpdu->pb = NULL;
}
/*free mpdu_end*/
mac_desc_free(&g_mac_desc_eng, \
PLC_TX_MPDU_END_POOL, mpdu_ed);
current_mpdu->tx_status = NULL;
/*free tx_mpdu_start*/
if ( \
/* if msdu and not first mpdu, free it */
(current_mpdu->is_msdu && !current_mpdu->list_start) \
/* or if not msdu, free the mpdu */
|| !current_mpdu->is_msdu) {
mac_desc_free(&g_mac_desc_eng, \
PLC_TX_MPDU_START_POOL, current_mpdu);
}
}
if (free_msdu) {
mac_msdu_deinit(free_msdu);
}
/* no matter msdu or mpdu, at least a mpdu is processed */
rf_pdev->hwq_hdl.q_depth[hwq_id]--;
g_mt_ctxt->hplc2rf_ing = 0;
/* trigger another sw scheuler */
if (need_trigger_swq) {
if (g_fw_mode != FTM_MODE) {
/* FTM not enable SWQ currently */
mac_rf_swsch_trigger_tx(RF_PDEV_ID,
rf_vdev->rf_vdev_id);
}
}
break;
}
/*sw need send ack when cert mode */
case FC_DELIM_SACK:{
/*set new cur_ptr*/
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id] = \
(void*)(current_mpdu->next);
/* cert mpdu and end not free */
if(!current_mpdu->tx_desc_reuse) {
/*free desc*/
mac_desc_free(&g_mac_desc_eng, PLC_TX_MPDU_END_POOL, \
(rf_tx_mpdu_end*)current_mpdu->tx_status);
current_mpdu->tx_status = NULL;
mac_desc_free(&g_mac_desc_eng, PLC_TX_MPDU_START_POOL, \
current_mpdu);
}
rf_pdev->hwq_hdl.q_depth[hwq_id]--;
break;
}
case FC_DELIM_NNCCO:{
/*set new cur_ptr*/
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id] = \
(void*)(current_mpdu->next);
/* cert mpdu and end not free */
if(!current_mpdu->tx_desc_reuse) {
/*free desc*/
mac_desc_free(&g_mac_desc_eng, PLC_TX_MPDU_END_POOL, \
current_mpdu->tx_status);
current_mpdu->tx_status = NULL;
mac_desc_free(&g_mac_desc_eng, PLC_TX_MPDU_START_POOL, \
current_mpdu);
}
rf_pdev->hwq_hdl.q_depth[hwq_id]--;
break;
}
default: {
IOT_ASSERT(0);
break;
}
}
}
else if (current_mpdu->desc_type == DESC_TYPE_TX_DUMMY) {
/* tx dummy desc */
/*current node is dummy*/
dummy_node = (rf_tx_dummy_node*)current_mpdu;
if (dummy_node->tx_done == 0) {
ret = ERR_OK;
break;
}
if (dummy_node->next == 0) {
/* the dummy is the last frame, do nothing */
ret = ERR_OK;
break;
}
else {
/* if dummy is not the last frame */
next_ptr = (rf_tx_mpdu_start*)dummy_node->next;
/* should no two continuous dummy, so the next
* frame must be mpdu
*/
IOT_ASSERT(next_ptr->desc_type \
== DESC_TYPE_TX_MPDU_START);
if (!next_ptr->tx_status->tx_done) {
/* if the next frame of dummy is not done
* just back later
*/
ret = ERR_OK;
break;
}
else {
/* if the mpdu after dummy is done,
* free the dummy node
*/
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id] = \
(void*)dummy_node->next;
mac_desc_free(&g_mac_desc_eng, \
PLC_TX_DUMMY_NODE_POOL, dummy_node);
rf_pdev->hwq_hdl.q_depth[hwq_id]--;
#if RF_MAC_TX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_1
iot_printf("rf dummy freed\n");
#endif
}
}
}
else {
/* other desc type */
IOT_ASSERT(0);
}
/* next mpdu */
current_mpdu = \
rf_pdev->hwq_hdl.cur_hdl_desc[hwq_id];
} //while
return ret;
}
#endif /* HPLC_RF_DEV_SUPPORT */