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

1454 lines
48 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_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_desc_engine.h"
#include "iot_bitops.h"
#include "mac_hwq_mgr.h"
#include "hw_phy_init.h"
#include "mac_isr.h"
#include "hw_tonemap.h"
#include "sw_sched.h"
#include "phy_chn.h"
#include "mac_crc.h"
#include "mpdu_header.h"
#include "mac_desc_engine.h"
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#include "iot_plc_led.h"
#include "mac_rawdata_hw.h"
#include "mac_cfg.h"
#include "rate_control.h"
#include "mac_cert_test.h"
#include "mac_tx_power.h"
#include "chip_reg_base.h"
#include "mac_sched_hw.h"
#include "hw_war.h"
#include "phy_txrx_pwr.h"
#include "tx_desc_reg_api.h"
#include "phy_perf.h"
#include "mac_sched.h"
#include "mac_hplc_ext_api.h"
#include "mac_hplc_ext.h"
/*
* mpdu
*/
/* check if the queue has pending desc
* 0 - means no desc pending
* others - means have desc pending
*/
uint32_t mac_tx_hwq_mpdu_pending(
mac_queue_ctxt_t *tx_ctxt, \
uint32_t hwq_id)
{
tx_mpdu_start *mpdu;
tx_mpdu_end *end;
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 = (tx_dummy_node *)dummy->next)
{
/* check if any desc is not done */
if (dummy->desc_type == DESC_TYPE_TX_DUMMY)
{
/* if dummy node desc */
//tx_done = dummy->tx_done;
continue;
}
else
if (dummy->desc_type == DESC_TYPE_TX_MPDU_START) {
/* if mpdu start desc */
mpdu = (tx_mpdu_start *)dummy;
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_tx_flush_hwq(mac_queue_ctxt_t *tx_ctxt, uint32_t qid,
uint8_t disable_hwq)
{
uint32_t is_enable, ret;
is_enable = mac_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_txq_enable(qid, NULL);
}
/* mark tx done for each desc */
tx_mpdu_start *mpdu;
tx_mpdu_end *end;
tx_dummy_node *dummy;
tx_dummy_node *last_node;
/* enq a dummy at hwq last position, then comp func can free all mpdu */
last_node = (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);
dummy->desc_type = DESC_TYPE_TX_DUMMY;
mac_tx_hw_mpdu(tx_ctxt, qid, (tx_mpdu_start*)dummy);
}
for (dummy = tx_ctxt->cur_hdl_desc[qid]; \
dummy; \
dummy = (tx_dummy_node *)dummy->next)
{
#if DBG_MAC_HWQ_FLUSH
iot_printf("hwq[qid].desc=%d, tx_done=%d\n",
qid, dummy->desc_type, dummy->tx_done);
iot_dbglog_input(PLC_MAC_TX_HW_MID, DBGLOG_WARN, IOT_MAC_TX_HW_FLUSH,
3, qid, dummy->desc_type, dummy->tx_done);
#endif
/* check if any desc is not done */
if (dummy->desc_type == DESC_TYPE_TX_DUMMY)
{
/* if dummy node desc */
dummy->tx_done = 1;
}
else if (dummy->desc_type == DESC_TYPE_TX_MPDU_START)
{
/* if mpdu start desc */
mpdu = (tx_mpdu_start *)dummy;
end = mpdu->tx_status;
IOT_ASSERT(end);
/* mark done */
end->tx_done = 1;
end->tx_ok = 0;
end->is_filtered = 1;
end->mac_event_id = 1;
}
else
{
/* should not other desc currently */
IOT_ASSERT(0);
}
}
ret = mac_tx_hw_mpdu_comp(qid, 0);
/* after flush, hwq must only one dummy in it, and hwq is closed */
last_node = (tx_dummy_node *)tx_ctxt->last_desc[qid];
if (last_node == NULL || last_node->desc_type != DESC_TYPE_TX_DUMMY || \
mac_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_txq_enable(qid, tx_ctxt->last_desc[qid]);
} else {
/* flush dummy, ane 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;
}
uint32_t mac_tx_flush_bcsma_pending_queue(mac_queue_ctxt_t *tx_ctxt)
{
uint32_t ret = 1;
IOT_ASSERT(tx_ctxt);
/* get swq type id */
for (uint32_t phase = PLC_PHASE_A; phase <= PLC_PHASE_CNT; phase++) {
uint32_t swq_id = mac_q_get_swq_type(PLC_BCN_REGION_BCSMA, phase,
LID_BCSMA_START);
if (tx_ctxt->q_depth[swq_id] > BCSMA_Q_WARNING_DEPTH) {
ret = mac_tx_flush_hwq(tx_ctxt, swq_id, false);
iot_printf("mac phase:%d flush bcsma pkt.\n", phase);
/* record flush tx bcsma cnt */
mac_add_flush_tx_bcsma_cnt();
}
}
/* if return 1 -> do not flush hwq.
* if return 0 -> already flush hwq
*/
return ret;
}
uint32_t mac_tx_flush_all_tdma_queue(mac_queue_ctxt_t *tx_ctxt)
{
for (uint32_t i = 0; i < tx_ctxt->last_hwq_id; i++)
{
/* look for every tdma queue */
if (!mac_txq_is_csma(i)) {
/* tdma */
if (mac_tx_hwq_mpdu_pending(tx_ctxt, i))
{
/* if pending desc */
mac_tx_flush_hwq(tx_ctxt, i, 0);
}
}
}
return 0;
}
uint32_t mac_tx_flush_all_queue(mac_queue_ctxt_t *tx_ctxt, \
uint32_t is_all_csma, uint32_t is_all_tdma)
{
extern mac_pdev_t* g_mac_pdev[];
mac_pdev_t *pdev = g_mac_pdev[PLC_PDEV_ID];
mac_vdev_t *vdev = pdev->vdev[0];
for (uint32_t i = 0; i <= tx_ctxt->last_hwq_id; i++)
{
if (vdev->stop_flag) {
/* if stop, need flush all */
mac_tx_flush_hwq(tx_ctxt, i, vdev->stop_flag);
continue;
}
/* look for every queue */
if ((mac_txq_is_csma(i) && is_all_csma) \
|| (!mac_txq_is_csma(i) && is_all_tdma))
{
/* check if packets exist, flush */
if (mac_tx_hwq_mpdu_pending(tx_ctxt, i))
{
/* if pending desc */
mac_tx_flush_hwq(tx_ctxt, i, 0);
}
}
}
return 0;
}
void mac_tx_csma_dump()
{
mac_queue_ctxt_t *tx_ctxt = &(g_mac_pdev[PLC_PDEV_ID]->hwq_hdl);
uint32_t hwq_id, type;
uint32_t dump[9] = {0};
uint8_t idx = 0, *p = (uint8_t *)dump, *q = (uint8_t *)&dump[3];
uint8_t dummy_cnt, csma_cnt;
for (hwq_id = MAC_QUE_CSMA_A_0; hwq_id <= MAC_QUE_CSMA_C_3;
hwq_id++, idx++) {
if (tx_ctxt->q_depth[hwq_id] > 255) {
p[idx] = 255;
} else {
p[idx] = (uint8_t)tx_ctxt->q_depth[hwq_id];
}
tx_mpdu_start *cur_ptr = (tx_mpdu_start*)tx_ctxt->cur_hdl_desc[hwq_id];
dummy_cnt = 0;
csma_cnt = 0;
for (uint16_t j = 0; (j < tx_ctxt->q_depth[hwq_id]) && (j < 10) &&
(cur_ptr != NULL); j++) {
IOT_ASSERT(cur_ptr);
type = cur_ptr->desc_type;
if (type == DESC_TYPE_TX_DUMMY) {
if (((tx_dummy_node*)cur_ptr)->tx_done) {
dummy_cnt++;
if (dummy_cnt > 0x0F) {
dummy_cnt = 0x0F;
}
}
} else {
if (cur_ptr->tx_status->tx_done) {
csma_cnt++;
if (csma_cnt > 0x0F) {
csma_cnt = 0x0F;
}
}
}
cur_ptr = cur_ptr->next;
}
q[idx] = csma_cnt | (dummy_cnt << 4);
}
iot_printf("%s, msdu_tx_cnt:%lu, 0x%08x, 0x%08x, 0x%08x, 0x%08x, "
"0x%08x, 0x%08x\n", __FUNCTION__,
mac_get_msdu_tx_cnt(), dump[0], dump[1], dump[2], dump[3],
dump[4], dump[5]);
iot_dbglog_input(PLC_MAC_STATUSE_MID, DBGLOG_ERR,
IOT_MAC_STATUS13_ID, 7, mac_get_msdu_tx_cnt(),
dump[0], dump[1], dump[2], dump[3], dump[4], dump[5]);
dump[0] = mac_get_tx_msdu_comp_trigger_cnt();
dump[1] = mac_get_send_msdu_cnt();
dump[2] = mac_get_swq_to_hwq_cnt();
dump[3] = g_phy_cpu_share_ctxt.tx_td_start_status;
dump[4] = g_phy_cpu_share_ctxt.tx_td_start_cnt;
dump[5] = g_phy_cpu_share_ctxt.tx_td_fc_done_cnt;
dump[6] = mac_get_csma_ignore_cca_cnt();
dump[7] = g_phy_cpu_share_ctxt.phy_tx_abort_cnt;
iot_printf("tx_sts_dump. %u, %u, %u, 0x%08x, %u, %u, %u, %u\n",
dump[0], dump[1], dump[2], dump[3], dump[4],
dump[5], dump[6], dump[7]);
iot_dbglog_input(PLC_MAC_STATUSE_MID, DBGLOG_ERR,
IOT_MAC_STATUS16_ID, 8,
dump[0], dump[1], dump[2], dump[3], dump[4],
dump[5], dump[6], dump[7]);
}
uint32_t mac_tx_hw_mpdu(mac_queue_ctxt_t *tx_ctxt, uint32_t hwq_id,
tx_mpdu_start *mpdu)
{
#ifdef TX_BUF_DUMP
mem_dump((uint32_t *)mpdu->pb_list->pb_buf_addr, 16);
#endif
tx_mpdu_start *last_desc = NULL;
uint32_t is_csma;
if (mac_txq_is_enable(hwq_id))
{
/* if enabled before, there must be valid last_desc */
/* attach the mpdu after the last desc */
last_desc = (tx_mpdu_start*)tx_ctxt->last_desc[hwq_id];
IOT_ASSERT(last_desc);
void **ptr = (void**)&last_desc->next;
*ptr = (void*)mpdu;
}
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] = (void*)mpdu;
}
else {
/* if have cur, it may be enabled before,
* so should have valid last_desc */
last_desc = (tx_mpdu_start*)tx_ctxt->last_desc[hwq_id];
IOT_ASSERT(last_desc && (last_desc->next == NULL));
void **ptr = (void**)&last_desc->next;
*ptr = (void*)mpdu;
}
if (mac_is_block_all_tx(tx_ctxt) == 0 &&
mpdu->desc_type != DESC_TYPE_TX_DUMMY) {
/* enable the queue if not dummy */
/* start from the enq mpdu */
mac_txq_enable(hwq_id, tx_ctxt->cur_hdl_desc[hwq_id]);
}
}
/* mpdu may be a list */
for (tx_mpdu_start *tmp = mpdu;
tmp != NULL; tmp = tmp->next) {
#if DEBUG_SSN
if (tmp->desc_type != DESC_TYPE_TX_DUMMY && tmp->pb_list) {
sg_sof_pb_hdr_t* pbh =
(sg_sof_pb_hdr_t*) &tmp->pb_list->sof_pb_header;
iot_printf("--ssn=%d,h=%d,e=%d\n", pbh->seq, pbh->mac_frame_start,
pbh->mac_frame_end);
}
#endif
last_desc = tmp;
tx_ctxt->q_depth[hwq_id]++;
}
tx_ctxt->last_desc[hwq_id] = (void*)last_desc;
/* flush hwq for block hw tx */
if (mac_is_block_all_tx(tx_ctxt) &&
mpdu->desc_type != DESC_TYPE_TX_DUMMY) {
IOT_ASSERT(mac_txq_is_enable(hwq_id) == 0);
mac_tx_flush_hwq(tx_ctxt, hwq_id, false);
}
/* dbg for tdma can not tx */
if (hwq_id == MAC_QUE_BCN_A || hwq_id == MAC_QUE_BCN_B ||
hwq_id == MAC_QUE_BCN_C) {
if (tx_ctxt->q_depth[MAC_QUE_BCN_A] > 3 ||
tx_ctxt->q_depth[MAC_QUE_BCN_B] > 3 ||
tx_ctxt->q_depth[MAC_QUE_BCN_C] > 3 ) {
mac_dump_sched_dbg();
}
}
/* bcn Q depth should less than 3, 2 mpdu and 1 dummy */
if ((hwq_id == MAC_QUE_BCN_A || hwq_id == MAC_QUE_BCN_B ||
hwq_id == MAC_QUE_BCN_C) &&
tx_ctxt->q_depth[hwq_id] > BCN_WARNING_DEPTH) {
tx_mpdu_start *cur_ptr = (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 : ((tx_dummy_node*)cur_ptr)->tx_done;
iot_printf("cur 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) {
#if DEBUG_CANNOT_SENDOUT_PKT
//debug beacon can not send out
phy_dbg_sts_print();
mac_dump_buf(MAC_DUMP_TYPE_2, g_phy_cpu_share_ctxt.tx_fc,
FC_LEN/sizeof(uint32_t), (uint32_t *)RGF_HWQ_BASEADDR,
108, NULL, 0, true);
#else
IOT_ASSERT(0);
#endif
}
}
/* send the packet in hwq immediately */
mac_txq_trigger_send(hwq_id);
is_csma = mac_txq_is_csma(hwq_id);
if (is_csma) {
/* To make the false alarm of RX FC,
* we need to adjust the threshold of
* packet detection.
* Here we use TX hw queue depth as a
* reference. CSMA WARN as the base
*/
uint32_t cur_hwq_depth = min(tx_ctxt->q_depth[hwq_id],
CSMA_Q_WARNING_DEPTH);
uint32_t false_alarm = phy_get_periodic_fc_err_num();
if (cur_hwq_depth > CSMA_Q_NORMAL_DEPTH &&
false_alarm > CSMA_RX_FALSE_ALARM_THD) {
phy_pkt_thd_set(
(uint8_t) (cur_hwq_depth * 100 / CSMA_Q_WARNING_DEPTH));
}
}
#if DEBUG_CANNOT_SENDOUT_PKT
/* TODO: here just do csma check spur.
* mabey need do tdma check spur.
*/
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
if (is_csma) {
if (pdev->plc_tx_timer && !pdev->plc_tx_st) {
os_start_timer(pdev->plc_tx_timer, TX_HANG_CHECK_TIME_MS);
pdev->plc_tx_st = PLC_DEBUG_NORMAL_ST;
pdev->plc_debug_cnt = 0;
}
if (tx_ctxt->q_depth[hwq_id] > CSMA_Q_WARNING_DEPTH) {
// WAR if qny csma queue depth > threshold
phy_csma_ignore_cca(true);
}
}
#endif
return 0;
}
uint8_t mac_crc_set_fc_swcrc(uint32_t proto, tx_mpdu_start *cur_mpdu)
{
uint8_t ret = ERR_OK;
IOT_ASSERT(cur_mpdu);
void *fc = mac_tx_mpdu_start_get_fc_ptr(cur_mpdu);
switch (proto)
{
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
{
frame_control_t *sg_fc = \
(frame_control_t *)fc;
if (phy_get_tx_fc_swcrc_cfg())
{
sg_fc->vf.bcn.fccs = \
mac_crc_get_fc_swcrc(proto, sg_fc);
}
break;
}
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
{
spg_frame_control_t *spg_fc = \
(spg_frame_control_t *)fc;
if (phy_get_tx_fc_swcrc_cfg())
{
uint32_t fccs = \
mac_crc_get_fc_swcrc(proto, spg_fc);
spg_fc->vf.bcn.fccs[0] = fccs & 0xFF;
spg_fc->vf.bcn.fccs[1] = (fccs >> 8) & 0xFF;
spg_fc->vf.bcn.fccs[2] = (fccs >> 16) & 0xFF;
}
break;
}
#endif
#if SUPPORT_GREEN_PHY
case PLC_PROTO_TYPE_GP:
{
hpav_frame_control *gp_fc = \
(hpav_frame_control *)fc;
if (phy_get_tx_fc_swcrc_cfg())
{
uint32_t fccs = \
mac_crc_get_fc_swcrc(proto, gp_fc);
gp_fc->fccs_av.fccs_av0 = fccs & 0xFF;
gp_fc->fccs_av.fccs_av1 = (fccs >> 8) & 0xFF;
gp_fc->fccs_av.fccs_av2 = (fccs >> 16) & 0xFF;
}
break;
}
#endif
default:
ret = ERR_NOSUPP;
break;
}
return ret;
}
uint8_t mac_crc_set_pb_swcrc(uint32_t proto, tx_pb_start *cur_pb_st, \
uint8_t delimite, uint32_t pb_sz)
{
uint32_t crc = 0;
IOT_ASSERT(cur_pb_st);
switch (proto)
{
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
break;
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
break;
#endif
#if SUPPORT_GREEN_PHY
case PLC_PROTO_TYPE_GP:
break;
#endif
default:
return ERR_NOSUPP;
}
if (phy_get_tx_pb_swcrc_cfg())
{
crc = mac_crc_get_pb_swcrc(proto, &cur_pb_st->sof_pb_header, \
(uint8_t *)cur_pb_st->pb_buf_addr, pb_sz, delimite);
cur_pb_st->sw_pb_crc = crc;
}
return ERR_OK;
}
uint16_t mac_tx_cal_fl(uint8_t is_bcast, uint8_t rate_id,
uint32_t proto_band_id, uint32_t tmi, uint32_t extmi, uint32_t pb_num)
{
uint32_t fl_ppb;
if (rate_id > MAC_BB_MAX_RATE) {
IOT_ASSERT(0);
return 0;
}
/* sw cfg fc frame len */
if (proto_band_id < IOT_SUPPORT_TONE_MULTI_BAND021) {
if (mac_get_fc_fl_cfg_status()) {
uint32_t hw_band_id = phy_proto_band_to_hw_band(proto_band_id);
fl_ppb = phy_get_flppb_from_table(hw_band_id, tmi, extmi);
return (uint16_t)(is_bcast ? \
((fl_ppb * pb_num + mac_get_tx_cifs()) / 10) : \
((fl_ppb * pb_num + mac_get_tx_rifs() + \
mac_get_tx_cifs() + \
mac_rx_get_delim(rate_id, hw_band_id)) / 10));
}
} else {
/*Note: proto_band_id must be the actual band id */
IOT_ASSERT(0);
}
return 0;
}
void mac_tx_mpdu_fill_pb_start(tx_pb_start *pb,
tx_pb_start *next, void *buf_addr, uint32_t pb_seq,
uint32_t msdu_start, uint32_t msdu_end, uint32_t proto
)
{
(void)msdu_end;
(void)msdu_start;
IOT_ASSERT(pb);
pb->next_pb = next;
pb->pb_buf_addr = (uint32_t)buf_addr;
#if SUPPORT_SMART_GRID
if (PLC_PROTO_TYPE_SG == proto)
{
#if SUPPORT_IEEE_1901
i1901_sof_pb_hdr_t *hdr = (i1901_sof_pb_hdr_t *)&pb->sof_pb_header;
hdr->mac_frame_end = msdu_end & 0x1;
hdr->mac_frame_start = msdu_start & 0x1;
hdr->seq = pb_seq & 0x3f;
#else
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;
#endif
} 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
#if SUPPORT_GREEN_PHY
if (PLC_PROTO_TYPE_GP == proto)
{ /* green phy */
gp_sof_pb_hdr_t *hdr =
(gp_sof_pb_hdr_t *)&pb->sof_pb_header; //pb header
hdr->ssn = pb_seq & 0x3f;
hdr->vpf = 0;
hdr->mmqf = 0;
hdr->mfbf = 0;
hdr->opsf = 0;
hdr->mfbo = 0;
} else
#endif
{
//todo
}
}
uint32_t mac_tx_mpdu_form_pb_list(tx_pb_start **pb_list, \
iot_pkt_t *pkt_buf, uint32_t pb_num_per_mpdu, \
uint32_t bitmap, uint32_t pb_sz, uint32_t proto
)
{
tx_pb_start *pb_start = NULL;
tx_pb_start *tmp = NULL;
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));
#if DEBUG_SPG_PER_MSDU_MPDU_TX && IOT_MP_SUPPORT
if (PLC_PROTO_TYPE_SPG == proto) {
if ((136 == pb_sz) && (all_pb_num > 1)) {
IOT_ASSERT_DUMP(0, &all_pb_num, 1);
}
}
#endif
for (uint32_t i = 0; i < all_pb_num; i++) {
if (0 == pb_num_per_mpdu || 0 == (bitmap >> i))
break;
if (bitmap & (0x1 << i)) {
pb_num_per_mpdu--;
if (pb_start == NULL) {
mac_desc_get(&g_mac_desc_eng, PLC_TX_PB_START_POOL, \
(void**)&tmp);
IOT_ASSERT(tmp != NULL);
pb_start = tmp;
}
/*is next pb exist*/
if (pb_num_per_mpdu != 0 && 0 != (bitmap >> (i + 1))) {
mac_desc_get(&g_mac_desc_eng, PLC_TX_PB_START_POOL, \
(void**)&tmp->next_pb);
IOT_ASSERT(tmp->next_pb);
}
else {
tmp->next_pb = NULL;
}
/*fill pb start desc*/
#if DEBUG_SSN
iot_printf("--send:0x%x,ssn=%d\n",bitmap,i);
#endif
mac_tx_mpdu_fill_pb_start(tmp, tmp->next_pb, 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);
mac_crc_set_pb_swcrc(proto, tmp, \
FC_DELIM_SOF, pb_sz);
tmp = tmp->next_pb;
}
}
if (tmp != NULL) {
iot_printf("bitmap=0x%x, pb_num_per_mpdu=%d, all_pb_num=%d"
"buf_len=%d\n",
bitmap, pb_num_per_mpdu, all_pb_num, buf_len);
IOT_ASSERT(0);
}
*pb_list = pb_start;
return 0;
}
void mac_tx_mpdu_fill_total_len(tx_mpdu_start *mpdu, uint32_t len)
{
mpdu->total_bytes = len;
}
void mac_tx_mpdu_fill_proto(tx_mpdu_start *mpdu, uint32_t proto)
{
mpdu->proto_type = proto;
}
/* transform tx phase to led req */
static inline uint8_t mac_trans_tx_phase2led_req(uint32_t phase)
{
switch(phase){
case PLC_PHASE_A:
return IOT_PLC_LED_REQ_PLC_TX_PHASE_A;
break;
case PLC_PHASE_B:
return IOT_PLC_LED_REQ_PLC_TX_PHASE_B;
break;
case PLC_PHASE_C:
return IOT_PLC_LED_REQ_PLC_TX_PHASE_C;
break;
default:
IOT_ASSERT(0);
break;
}
return 0;
}
void mac_tx_led_control(void *mpdu)
{
tx_mpdu_start *mpdu_st = (tx_mpdu_start *)mpdu;
if (mpdu_st) {
uint8_t tx_phase = (uint8_t)(mpdu_st->tx_phase & 0x3);
if (PLC_PHASE_ALL == tx_phase) {
iot_plc_led_request(mac_trans_tx_phase2led_req(PLC_PHASE_A));
iot_plc_led_request(mac_trans_tx_phase2led_req(PLC_PHASE_B));
iot_plc_led_request(mac_trans_tx_phase2led_req(PLC_PHASE_C));
} else {
iot_plc_led_request(mac_trans_tx_phase2led_req(tx_phase));
}
}
return;
}
#if ENA_WAR_421_DEBUG
uint32_t g_war_421_cnt = 0;
uint32_t g_is_check_phy_rx = 1;
#endif
uint32_t mac_tx_hw_mpdu_comp_dsr(uint32_t hwq_id)
{
return mac_tx_hw_mpdu_comp(hwq_id, 1);
}
uint32_t mac_tx_hw_mpdu_comp(uint32_t hwq_id, uint32_t is_phy_comp)
{
extern mac_pdev_t* g_mac_pdev[];
mac_pdev_t *pdev = g_mac_pdev[PLC_PDEV_ID];
mac_vdev_t *vdev;
tx_mpdu_start *next_ptr;
tx_pb_start *pb_to_free;
tx_pb_start *pb_start;
tx_mpdu_end *mpdu_ed;
tx_dummy_node *dummy_node;
tx_mpdu_start *current_mpdu = \
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 PLC_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1
/* log the enter of this functon */
iot_printf("hwq:%d tx_done", hwq_id);
iot_dbglog_input(PLC_MAC_TX_MID, DBGLOG_INFO_LVL_2, IOT_MAC_TX_DONE_ID, 1,
hwq_id);
if (current_mpdu && current_mpdu->desc_type == DESC_TYPE_TX_MPDU_START) {
iot_printf(",phase:%d", current_mpdu->tx_phase);
}
#endif
#if DEBUG_NID_ERR
if ((mac_get_cert_test_mode() != CERT_TEST_CMD_NOT_RX)
&& (g_phy_cpu_share_ctxt.nid_err_cnt != 0)) {
uint32_t dbg_dump_buf[2];
dbg_dump_buf[0] = g_phy_cpu_share_ctxt.cur_nid;
dbg_dump_buf[1] = g_phy_cpu_share_ctxt.config_nid;
IOT_ASSERT_DUMP(0, dbg_dump_buf, 2);
}
#endif
#if DEBUG_CANNOT_SENDOUT_PKT
if(pdev->plc_tx_timer && pdev->plc_tx_st && mac_txq_is_csma(hwq_id))
{
os_stop_timer(pdev->plc_tx_timer);
pdev->plc_tx_st = PLC_DEBUG_INIT_ST;
if (pdev->plc_con_tx_timeout_cnt > 0) {
pdev->plc_con_tx_timeout_cnt = 0;
phy_csma_ignore_cca(0);
}
}
#endif
while (current_mpdu) {
fc = mac_tx_mpdu_start_get_fc_ptr(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);
if (mpdu_ed->tx_done == 0) {
/* if not done then back next time */
break;
}
mac_fc_i1901_to_sg(PHY_PROTO_TYPE_GET(), fc);
vdev = find_vdev_by_nid(PLC_PDEV_ID,
mac_get_nid_from_fc(proto, fc));
IOT_ASSERT(vdev);
/* record the tx time */
vdev->last_tx_ntb = (uint32_t)mpdu_ed->first_try_ts;
#if ENA_WAR_421_DEBUG
if (vdev->is_up) {
if (vdev->last_rx_ntb == 0 && g_is_check_phy_rx) {
/* if not receiving any frame after boot up */
if (g_war_421_cnt++ > 100) {
/* every 100 packet, logging */
phy_dbg_sts_print();
g_war_421_cnt = 0;
}
} else {
g_is_check_phy_rx = 0;
}
}
#endif
/* LED control hook */
mac_tx_led_control(current_mpdu);
/* 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(vdev->stop_flag == 1){
dummy_node->tx_done = 1;
}
dummy_node->desc_type = DESC_TYPE_TX_DUMMY;
/* en hwq */
mac_tx_hw_mpdu(&pdev->hwq_hdl, \
hwq_id, (tx_mpdu_start*)dummy_node);
#if PLC_MAC_TX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_1
iot_printf("dummy end\n");
iot_dbglog_input(PLC_MAC_TX_HW_MID, \
DBGLOG_INFO_LVL_1, IOT_MAC_TX_HW_DUMMY_END_ID, 0);
#endif
/*
* dummy would generate TX INT, so no
* need to back again
* ret = ERR_AGAIN;
*/
if(vdev->stop_flag == 0){
ret = ERR_OK;
break;
}
}
else {
/* check if we can free something */
next_ptr = (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 = (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 PLC_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1
/* log the every tx done mpdu */
delimiter_type = mac_get_delimi_from_fc(proto,
fc);
if ((FC_DELIM_SOF == delimiter_type) && current_mpdu->need_ack) {
/* unicast sof */
iot_printf("\n++tx ok=0x%x,tx done=0x%x"
",ntb=%lu,sack=%lu"
",fl=%d.", mpdu_ed->tx_ok, mpdu_ed->tx_done,
mpdu_ed->first_try_ts, mpdu_ed->sack_timestamp,
(*(frame_control_t*) fc).vf.sof.frame_len);
iot_dbglog_input(PLC_MAC_TX_MID, DBGLOG_INFO_LVL_2,
IOT_MAC_TXDONE_OK_ID, 2, mpdu_ed->tx_ok,
mpdu_ed->tx_done);
iot_dbglog_input(PLC_MAC_TX_MID, DBGLOG_INFO_LVL_2,
IOT_MAC_TXDONE_TS_ID, 2,
mpdu_ed->first_try_ts,
mpdu_ed->sack_timestamp);
#if ENA_WAR_244
if (g_phy_cpu_share_ctxt.sack_miss_cnt
|| g_phy_cpu_share_ctxt.sack_err_occur_cnt) {
iot_printf("sack:miss=0x%x-err=0x%x.",
g_phy_cpu_share_ctxt.sack_miss_cnt,
g_phy_cpu_share_ctxt.sack_err_occur_cnt);
iot_dbglog_input(PLC_MAC_TX_MID, DBGLOG_INFO_LVL_2,
IOT_MAC_TXDONE_SACK_ID, 2,
g_phy_cpu_share_ctxt.sack_miss_cnt,
g_phy_cpu_share_ctxt.sack_err_occur_cnt);
}
#endif
} else {
/* other frame */
iot_printf("\n--tx done=0x%x"
",ntb=%lu,delim=%d.", mpdu_ed->tx_done,
mpdu_ed->first_try_ts, delimiter_type);
}
if (mpdu_ed->total_retry_cnt) {
iot_printf("HW_R_C:%d, st1:0x%x, st2:0x%x, st3:0x%x, st4:0x%x,"
"st5:0x%x, st6:0x%x, st7:0x%x.",
mpdu_ed->total_retry_cnt,
mpdu_ed->try_status_01.retry_time_offset,
mpdu_ed->try_status_02.retry_time_offset,
mpdu_ed->try_status_03.retry_time_offset,
mpdu_ed->try_status_04.retry_time_offset,
mpdu_ed->try_status_05.retry_time_offset,
mpdu_ed->try_status_06.retry_time_offset,
mpdu_ed->try_status_07.retry_time_offset);
}
/* check tx abort */
if (mpdu_ed->is_phyerr) {
iot_printf("tx_abort:reason=%d, "
"desc_sym:%d, fc: 0x%x, 0x%x, 0x%x, 0x%x, "
"udrun_cnt:%d, pb_num:%d", mpdu_ed->phyerr_id,
mac_tx_mpdu_start_get_symppb(current_mpdu),
pdev->fc_hw[0], pdev->fc_hw[1], pdev->fc_hw[2],
pdev->fc_hw[3], pdev->mac_underrun_cnt,
current_mpdu->pb_num);
iot_dbglog_input(PLC_MAC_TX_HW_MID, DBGLOG_WARN,
IOT_MAC_TX_ABORT_ID, 1,
mpdu_ed->phyerr_id);
}
iot_printf("\n");
#if DEG_TX_ABORT
phy_get_tx_abort_info();
#endif
#endif /* PLC_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1 */
//tx mpdu cnt
mac_add_mpdu_tx_cnt();
delimiter_type = \
mac_get_delimi_from_fc(proto, fc);
if (mac_is_unicast(proto, fc, 0)) {
if(!(mpdu_ed->tx_ok)) {
/* not receive ack cnt */
mac_add_tx_no_ack_cnt(vdev->proxy_tei == \
mac_get_fc_dtei(phy_proto_type_get(), fc));
}
else {
/*receive ack , but pb all err*/
if (!current_mpdu->tx_status->sack_bitmap) {
mac_add_tx_unicast_all_pb_err_cnt(vdev->proxy_tei == \
mac_get_fc_dtei(phy_proto_type_get(), fc));
}
}
}
switch (delimiter_type) {
case FC_DELIM_BEACON: {
/*set new cur_ptr*/
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
*/
tx_pb_start *pb = current_mpdu->pb_list;
uint32_t pb_cnt = 0;
while (pb) {
pb_cnt++;
iot_pkt_t *pkt = \
(iot_pkt_t*)(pb->pb_buf_addr \
- current_mpdu->sw_buf_offset);
iot_pkt_free(pkt);
pb = pb->next_pb;
}
IOT_ASSERT(current_mpdu->pb_num == pb_cnt);
}
}
if(!current_mpdu->tx_desc_reuse)
{
/*free desc*/
ret = mac_desc_free(&g_mac_desc_eng, \
PLC_TX_PB_START_POOL, \
current_mpdu->pb_list);
IOT_ASSERT(ERR_OK == ret);
current_mpdu->pb_list = 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 */
pdev->hwq_hdl.q_depth[hwq_id]--;
break;
}
case FC_DELIM_SOF: {
#if MAC_TIMESTAMPING
mac_pdev_t *pdev_t = g_mac_pdev[PLC_PDEV_ID];
uint32_t tx_timestamp = current_mpdu->tx_status->first_try_local_ts;
uint32_t fl = current_mpdu->fc.sg_fc.vf.sof.frame_len;
iot_printf("loopback time = %dus, dsr_to_isr_time = %dus, "
"phy_pld_interrupt = %d, rx_timestamp = %d, rx_dsr_time = %d, "
"tx_hung_time = %d, tx_timestamp = %d, frame_length = %d\n",
(pdev_t->mac_tx_sw_ntb - pdev_t->mac_rx_ntb)/25,
(pdev_t->mac_rx_ntb - pdev_t->mac_isr_ntb)/25,
g_phy_cpu_share_ctxt.phy_pld_int_ntb, pdev_t->mac_rx_timestamp,
pdev_t->mac_rx_ntb, pdev_t->mac_tx_sw_ntb,tx_timestamp, fl
);
#endif
free_msdu = NULL;
/*msdu comp*/
if (current_mpdu->is_msdu) {
/* if pb buf reuse, then msdu need be freed */
free_msdu = mac_tx_hw_msdu_comp(hwq_id, current_mpdu,
pdev, is_phy_comp);
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) {
uint8_t cnt = 0;
uint32_t pb_num = mac_get_sof_pbnum(proto, fc);
/* if pb buf is not continuous,
* use the following method
*/
tx_pb_start *pb = NULL;
for (pb = current_mpdu->pb_list; pb != NULL;
pb = pb->next_pb) {
iot_pkt_t *pkt = (iot_pkt_t*) (pb->pb_buf_addr
- current_mpdu->sw_buf_offset);
iot_pkt_free(pkt);
cnt++;
}
if (cnt != pb_num) {
iot_printf("%d!=%d\n", cnt, pb_num);
IOT_ASSERT(0);
}
} else {
/* free the pb buf in one pkt buf,
* only support ftm mode,
* pb num 1-4
*/
tx_pb_start *pb = current_mpdu->pb_list;
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*/
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_list != NULL) {
pb_start = current_mpdu->pb_list;
pb_to_free = pb_start->next_pb;
while (pb_to_free != NULL) {
pb_start->next_pb = pb_to_free->next_pb;
mac_desc_free(&g_mac_desc_eng, \
PLC_TX_PB_START_POOL, pb_to_free);
pb_to_free = pb_start->next_pb;
}
mac_desc_free(&g_mac_desc_eng, \
PLC_TX_PB_START_POOL, pb_start);
current_mpdu->pb_list = 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 */
pdev->hwq_hdl.q_depth[hwq_id]--;
/* trigger another sw scheuler */
if (need_trigger_swq) {
if(g_fw_mode!=FTM_MODE)
{
/* FTM not enable SWQ currently */
mac_swsch_trigger_tx(0, vdev->vdev_id);
mac_add_tx_msdu_comp_trigger_cnt();
}
}
break;
}
/*sw need send ack when cert mode */
case FC_DELIM_SACK:{
if (mac_get_cert_test_mode()) {
/*set new cur_ptr*/
pdev->hwq_hdl.cur_hdl_desc[hwq_id] = \
(void*)(current_mpdu->next);
pdev->hwq_hdl.q_depth[hwq_id]--;
} else {
/*set new cur_ptr*/
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, \
(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);
}
pdev->hwq_hdl.q_depth[hwq_id]--;
}
break;
}
case FC_DELIM_NNCCO:{
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1)
void *fc = mac_tx_mpdu_start_get_fc_ptr(current_mpdu);
#if ENA_WAR_NNCCO_FEAT == 1
fc = g_phy_cpu_share_ctxt.tx_fc;
#else
fc = g_phy_ctxt.indep.nn_cco_fc;
#endif
iot_printf("NNCCO tx - st:%d,dur:%d,nid:0x%x"
",tx_ts:%lu\n",
mac_get_nncco_protect_region_offset(proto, fc),
mac_get_nncco_protect_dur(proto, fc),
mac_get_nncco_received_nid(proto, fc),
mpdu_ed->first_try_ts);
#endif
/*set new cur_ptr*/
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);
}
pdev->hwq_hdl.q_depth[hwq_id]--;
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_2)
iot_printf("[mac_check_dbg], phase1:%lu, phase2:%lu, phase3:%lu\n",\
pdev->hwq_hdl.q_depth[6], \
pdev->hwq_hdl.q_depth[10], \
pdev->hwq_hdl.q_depth[14]);
#endif
break;
}
case I1901_RTS_CTS: {
pdev->hwq_hdl.cur_hdl_desc[hwq_id] =
(void*)(current_mpdu->next);
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);
}
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 = (tx_dummy_node*)current_mpdu;
if (dummy_node->tx_done == 0) {
if (mac_txq_is_dbg_mode()) {
/* dummy not done, should not happen in dbg mode */
IOT_ASSERT(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 = (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
*/
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);
pdev->hwq_hdl.q_depth[hwq_id]--;
#if PLC_MAC_TX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_1
iot_printf("dummy freed\n");
iot_dbglog_input(PLC_MAC_TX_HW_MID, \
DBGLOG_INFO_LVL_1, IOT_MAC_TX_HW_DUMMY_FREE_ID, 0);
#endif
}
}
}
else {
/* other desc type */
IOT_ASSERT(0);
}
/* next mpdu */
current_mpdu = \
pdev->hwq_hdl.cur_hdl_desc[hwq_id];
} //while
#if ENA_WAR_440
mac_set_tx_underflow_cnt(g_phy_cpu_share_ctxt.tx_underflow_cnt);
#endif
return ret;
}
void mac_handle_timeout_tx_abort()
{
#if WAR_TIMEOUT_TX_ABORT
g_phy_cpu_share_ctxt.timeout_tx_abort_cnt++;
iot_printf("phy tx abort can't clear! phy_tx_abort_cnt:%d\n",\
g_phy_cpu_share_ctxt.timeout_tx_abort_cnt);
g_phy_cpu_share_ctxt.timeout_tx_abort_flag = false;
#endif
}
void IRAM_ATTR mac_check_timeout_tx_abort()
{
#if WAR_TIMEOUT_TX_ABORT
uint32_t value = 0;
if(g_phy_cpu_share_ctxt.timeout_tx_abort_flag)
{
value |= 1 << MAC_DSR_CHECK_TX_ABORT_ID;
if (value) {
/* deliver the DSR events to mac task context */
os_set_task_event_with_v_from_isr(p_mac_glb->task_h, value);
}
}
#endif
}
uint32_t mac_cal_fd_and_preamble_time(uint32_t bandid, uint32_t tmi)
{
uint32_t preamble_time = 0;
uint32_t fd_time = DEFAULT_PHY_TX_FD_TIME;
if (tmi > SG_TMI_MAX) {
IOT_ASSERT(0);
}
if (tmi == SG_TMI_MAX) {
preamble_time = (uint32_t)(phy_sg_emcs_pream_num_get(bandid) * 40.96);
} else {
preamble_time = (uint32_t)(phy_sg_bmcs_pream_num_get(bandid) * 40.96);
}
return fd_time + preamble_time;
}
void mac_tx_fill_extsackinfo(uint32_t proto, void *fc, uint32_t delimiter, \
uint32_t nid, uint32_t ext_type, uint8_t *addr, uint16_t stei, uint8_t sn)
{
(void)sn;
switch (proto) {
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
{
/* nid share the same place for SG */
frame_control_t *sg_fc = (frame_control_t *)fc;
if (delimiter != FC_DELIM_SACK) {
IOT_ASSERT(0);
}
sg_fc->delimiter_type = delimiter;
if (ext_type == SACK_EXT_TYPE_SEARCH) {
IOT_ASSERT(addr != NULL);
sg_fc->nid = 0;
os_mem_cpy(&sg_fc->vf.search.mac_addr, addr, IOT_MAC_ADDR_LEN);
sg_fc->vf.search.stei = PLC_TEI_CTRL;
sg_fc->vf.search.ext_type = ext_type;
}
if (ext_type == SACK_EXT_TYPE_SYNC) {
sg_fc->nid = nid;
sg_fc->vf.sync.stei = stei;
sg_fc->vf.sync.ext_type = ext_type;
}
break;
}
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
{
spg_frame_control_t *spg_fc = (spg_frame_control_t *)fc;
if (delimiter != FC_DELIM_SACK) {
IOT_ASSERT(0);
}
spg_fc->delimiter_type = (uint8_t)delimiter;
if (ext_type == SACK_EXT_TYPE_SEARCH) {
IOT_ASSERT(addr != NULL);
spg_fc->snid = 0;
os_mem_cpy(&spg_fc->vf.search.mac_addr, addr, IOT_MAC_ADDR_LEN);
spg_fc->vf.search.stei = PLC_TEI_CTRL;
spg_fc->vf.search.ext_type = ext_type;
spg_fc->vf.search.sn = sn;
spg_fc->vf.search.version = SPG_STANDARD_VERSION;
}
if (ext_type == SACK_EXT_TYPE_SYNC) {
spg_fc->snid = (uint8_t)nid;
spg_fc->vf.sync.stei = stei;
spg_fc->vf.sync.ext_type = ext_type;
spg_fc->vf.sync.sn = sn;
spg_fc->vf.sync.version = SPG_STANDARD_VERSION;
}
break;
}
#endif
default:
break;
}
return;
}