744 lines
25 KiB
C
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 */
|