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

757 lines
24 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 "mac_msdu.h"
#include "iot_errno.h"
#include "plc_mac_header.h"
#include "plc_protocol.h"
#include "plc_const.h"
#include "mac_desc_engine.h"
#include "hw_tonemap.h"
#include "mac_tx_power.h"
#include "phy_chn.h"
#include "mpdu_header.h"
#include "iot_bitops_api.h"
#include "iot_io.h"
#include "mac_tx_hw.h"
#include "iot_config.h"
#include "mac_stream.h"
#include "tx_desc_reg_api.h"
#include "rate_control.h"
#include "mac_cert_test.h"
#include "multi_nid_sync.h"
#if ENA_HW_SYNC_PPM_WAR
static uint8_t mac_msdu_is_force_swretry(mac_msdu_t *msdu)
{
return msdu->is_dbg_pkt;
}
#else /* ENA_HW_SYNC_PPM_WAR */
#define mac_msdu_is_force_swretry(msdu) (0)
#endif /* ENA_HW_SYNC_PPM_WAR */
uint32_t mac_msdu_init(mac_msdu_t *msdu, uint32_t buf_need_free,
void *stream, iot_pkt_t *msdu_buf, uint8_t retry_cnt) {
if (NULL == msdu) {
IOT_ASSERT(0);
return ERR_INVAL;
}
msdu->buf = msdu_buf;
msdu->buf_need_free = buf_need_free;
//msdu->next = NULL;
msdu->ref_mac_stream = stream;
msdu->send_bitmap = 0xffffffff; /*1 need send*/
msdu->hw_desc.mpdu_list.list_start = 1;
msdu->retry = 0;
msdu->in_hwq = 0;
msdu->retry_cnt = retry_cnt;
msdu->hw_retry_cnt = retry_cnt;
msdu->last_pos = 0;
msdu->rate_idx = MAX_RATE_IDX;
msdu->is_first_try_done = 0;
msdu->fix_rate = 0;
msdu->rd_retry_cnt = retry_cnt;
return 0;
}
uint8_t mac_frame_list_init(mac_msdu_frame_t * mac_frame_list,
iot_pkt_t *buf, uint8_t bcat, uint8_t phase, uint8_t l_phase,
uint8_t retry_cnt, uint8_t is_dbg_pkt, uint16_t is_tx_3phase,
uint8_t fix_rate, int8_t ppm_step, uint8_t ppm_step_type)
{
mac_frame_list->buf = buf;
mac_frame_list->is_bcast = bcat;
mac_frame_list->phase = phase;
mac_frame_list->l_phase = l_phase;
mac_frame_list->retry_cnt = retry_cnt;
mac_frame_list->next = NULL;
mac_frame_list->tx_3phase = is_tx_3phase;
mac_frame_list->is_dbg_pkt = !!is_dbg_pkt;
mac_frame_list->fix_rate = !!fix_rate;
mac_frame_list->ppm_step = ppm_step;
mac_frame_list->ppm_step_type = ppm_step_type;
return 0;
}
uint32_t mac_msdu_deinit(mac_msdu_t *msdu)
{
uint32_t ret;
IOT_ASSERT(msdu);
if (msdu->buf != NULL) {
iot_pkt_free_tx_done(msdu->buf, IOT_PKT_STATE_TX_FAIL);
msdu->buf = NULL;
}
ret = mac_desc_free(&g_mac_desc_eng,
PLC_MAC_MSDU_POOL,
msdu);
IOT_ASSERT(ret == 0);
return 0;
}
uint8_t mac_msdu_retry_cnt_get(uint8_t proto, void *data)
{
uint8_t retry_cnt = 0;
IOT_ASSERT(data);
switch(proto) {
case PLC_PROTO_TYPE_SG:
{
mac_header_t *mac_sg = (mac_header_t *)data;
if (MAC_HEADER_SHORT_VER == mac_sg->version) {
retry_cnt = 0;
} else {
retry_cnt = mac_sg->send_max_cnt;
}
break;
}
case PLC_PROTO_TYPE_SPG:
{
spg_mac_header_t *mac_spg = (spg_mac_header_t *)data;
if (SPG_MAC_HEADER_SHORT_VER == mac_spg->version) {
retry_cnt = 0;
} else {
retry_cnt = (uint8_t)mac_spg->send_max_cnt;
}
break;
}
default:
break;
}
return retry_cnt;
}
uint32_t mac_get_hdr_len(uint8_t proto, iot_pkt_t *msdu_buf)
{
IOT_ASSERT(msdu_buf);
uint8_t *data = iot_pkt_data(msdu_buf);
uint32_t mac_hdr_len = 0;
switch(proto) {
case PLC_PROTO_TYPE_SG:
{
#if SUPPORT_IEEE_1901
i1901_mac_header_t *i1901_mac = (i1901_mac_header_t *)data;
if (i1901_mac_hdr_var_is_valid(i1901_mac)) {
if (i1901_mac_hdr_var_addr_is_valid(i1901_mac)) {
mac_hdr_len = MAC_HDR_LEN_WITH_VAR_ADDR_I1901;
} else {
mac_hdr_len = MAC_HDR_LEN_WITH_VAR_I1901;
}
} else {
mac_hdr_len = MAC_HDR_LEN_NO_VAR_I1901;
}
#else
mac_header_t *sg_mac = (mac_header_t *)data;
if (HPLC_RF_DEV_SUPPORT && (MAC_HEADER_SHORT_VER == sg_mac->version)) {
mac_hdr_len = MAC_HDR_LEN_SHORT;
} else {
if (sg_mac->mac_exist_flag) {
mac_hdr_len = MAC_HDR_LEN_WITH_ADDR;
} else {
mac_hdr_len = MAC_HDR_LEN_NO_ADDR;
}
}
#endif
break;
}
case PLC_PROTO_TYPE_SPG:
{
spg_mac_header_t *spg_mac =
(spg_mac_header_t *)data;
if (HPLC_RF_DEV_SUPPORT &&
(SPG_MAC_HEADER_SHORT_VER == spg_mac->version)) {
mac_hdr_len = MAC_SINGLE_HOP_HDR_LEN_SPG;
} else {
if (spg_mac->mac_hdr_type) {
mac_hdr_len = sizeof(spg_mac_header_t);
} else {
mac_hdr_len = sizeof(spg_mac_header_t) +
sizeof(spg_mac_lheader_tail_t);
}
}
break;
}
default:
IOT_ASSERT(0);
break;
}
return mac_hdr_len;
}
void mac_msdu_frame_info_get(uint8_t proto, iot_pkt_t *msdu_buf,
uint8_t **pptr, uint16_t *msdu_len,
uint16_t *mac_hdr_len)
{
IOT_ASSERT(pptr);
uint8_t *data = iot_pkt_data(msdu_buf);
switch(proto) {
case PLC_PROTO_TYPE_SG:
{
#if SUPPORT_IEEE_1901
i1901_mac_header_t *i1901_mac = (i1901_mac_header_t *)data;
*msdu_len = i1901_mac->msdu_len;
#else
mac_header_t *sg_mac = (mac_header_t *)data;
if (HPLC_RF_DEV_SUPPORT && (MAC_HEADER_SHORT_VER == sg_mac->version)) {
mac_short_header_t *sg_short_mac = (mac_short_header_t *)data;
*msdu_len = sg_short_mac->msdu_len;
} else {
*msdu_len = sg_mac->msdu_len;
}
#endif
*mac_hdr_len = (uint16_t)mac_get_hdr_len(proto, msdu_buf);
data += *mac_hdr_len + *msdu_len;
break;
}
case PLC_PROTO_TYPE_SPG:
{
spg_mac_header_t *spg_mac =
(spg_mac_header_t *)data;
if (HPLC_RF_DEV_SUPPORT &&
(SPG_MAC_HEADER_SHORT_VER == spg_mac->version)) {
spg_mac_short_header_t *sg_s_mac = (spg_mac_short_header_t *)data;
*msdu_len = sg_s_mac->msdu_len;
} else {
*msdu_len = spg_mac->msdu_len;
}
*mac_hdr_len = (uint16_t)mac_get_hdr_len(proto, msdu_buf);
data += *mac_hdr_len + *msdu_len;
break;
}
default:
IOT_ASSERT(0);
break;
}
*pptr = data;
}
void mac_msdu_update_with_acked_ssn(mac_msdu_t *msdu, uint32_t tx_ok_pb_ssn)
{
IOT_ASSERT(msdu && tx_ok_pb_ssn < 32);
msdu->send_bitmap &= ~((uint32_t)(1 << tx_ok_pb_ssn));
return;
}
uint32_t mac_tx_msdu(mac_pdev_t *pdev,
mac_msdu_t *msdu,
uint32_t pb_sz, uint32_t pb_num_per_mpdu,
uint32_t mpdu_num_to_send,
uint32_t delimiter_type,
uint32_t nid, tei_t stei, tei_t dtei, uint32_t lid,
uint8_t is_bcast, phase_t phase, uint32_t proto,
uint32_t port, uint32_t tmi, uint32_t ext_tmi,
uint32_t rate_mode, uint32_t proto_single_band
) {
uint32_t tx_power;
iot_pkt_t *data_buf = msdu->buf;
tx_mpdu_start *tmp = NULL;
uint32_t pb_num = 0, pb_num_in_desc = 0;
uint32_t rest_pb_num_in_msdu;
uint32_t pb_num_to_send;
uint32_t msdu_len;
mac_queue_t swq_id = 0;
uint32_t hwqid;
uint32_t ret = 0;
uint32_t tmp_bitmap, cur_send_bitmap;
uint32_t i, j;
uint32_t list_start, list_end;
tx_pb_start *pb_list;
tx_mpdu_end *tx_status;
uint32_t need_ack = 0;
uint32_t pb_buf_reuse;
tx_mpdu_start *next;
uint32_t pb_mod;
uint32_t hw_band_id;
uint32_t sym_ppb, fl_ppb;
uint32_t hwretry_cnt = 0;
uint32_t pos;
uint32_t network = (PLC_PROTO_TYPE_SPG == proto)? 1:0;
mac_vdev_t *vdev = pdev->vdev[PLC_DEFAULT_VDEV];
#if DEBUG_SPG_PER_MSDU_MPDU_TX
uint32_t dbg_dump_buf[4] = {0};
#endif
(void)port;
(void)vdev;
{
/* get and check the pb's modulation */
ret = phy_get_pb_mod(proto, tmi, ext_tmi, &pb_mod);
IOT_ASSERT(ret == ERR_OK);
}
{
/* check the pbsz and tmi&etmi */
uint32_t tmp_pbsz;
ret = phy_get_pb_size(proto, tmi, ext_tmi, &tmp_pbsz);
IOT_ASSERT(ret == ERR_OK && tmp_pbsz == pb_sz);
}
/* get the pb head + crc + resv(for SPG) total len */
uint8_t pb_hdr_resv_crc_len = mac_get_pb_hdr_resv_crc_len(
delimiter_type, proto);
/* get default tx power */
tx_power = PHY_FULL_PWR_DBUV;
/*get msdu len && all pb num*/
msdu_len = iot_pkt_block_len(data_buf, IOT_PKT_BLOCK_DATA);
/*get rest pb num in msdu*/
if (msdu->send_bitmap == 0xffffffff) {
rest_pb_num_in_msdu = iot_ceil(msdu_len, (pb_sz - pb_hdr_resv_crc_len));
msdu->send_bitmap = 0xffffffff >> (32 - rest_pb_num_in_msdu);
}
else {
rest_pb_num_in_msdu = iot_bitops_cbs((uint8_t)msdu->send_bitmap)
+ iot_bitops_cbs((uint8_t)(msdu->send_bitmap >> 8))
+ iot_bitops_cbs((uint8_t)(msdu->send_bitmap >> 16))
+ iot_bitops_cbs((uint8_t)(msdu->send_bitmap >> 24));
}
if (dtei != PLC_TEI_BCAST) {
uint32_t sw_retry_cnt = 0;
/* uni-cast need ack */
need_ack = 1;
mac_cal_ucast_hw_sw_retry_cnt(pdev, msdu->is_first_try_done,
msdu->retry_cnt, msdu->hw_retry_cnt, rest_pb_num_in_msdu,
&hwretry_cnt, &sw_retry_cnt);
msdu->retry_cnt = sw_retry_cnt;
msdu->hw_retry_cnt = hwretry_cnt;
/* uni-cast tx power */
} else {
/* if bcast sof, use hw retry */
if (mac_get_bcast_hwretry_cfg(pdev)
&& !mac_msdu_is_force_swretry(msdu)) {
hwretry_cnt = msdu->retry_cnt;
}
}
#if DEBUG_SPG_PER_MSDU_MPDU_TX
if (PLC_PROTO_TYPE_SPG == proto) {
/* spg only support 136/520 pbsz tx.
* and when pbsz > 136, then use 520pbsz
*/
if (((136 == pb_sz) && (rest_pb_num_in_msdu > 1))
|| (rest_pb_num_in_msdu > PLC_MAX_PB_PER_MPDU)) {
dbg_dump_buf[0] = rest_pb_num_in_msdu;
dbg_dump_buf[1] = msdu->send_bitmap;
dbg_dump_buf[2] = pb_sz;
dbg_dump_buf[3] = msdu_len;
IOT_ASSERT_DUMP(0, dbg_dump_buf, 4);
}
}
#endif
/*get final mpdu num and final pb num*/
mpdu_num_to_send = min(iot_ceil(rest_pb_num_in_msdu, pb_num_per_mpdu),
mpdu_num_to_send);
#if DEBUG_SPG_PER_MSDU_MPDU_TX
if ((PLC_PROTO_TYPE_SPG == proto) && (mpdu_num_to_send > 1)) {
/* spg must be 1msdu send by 1mpdu */
dbg_dump_buf[0] = mpdu_num_to_send;
dbg_dump_buf[1] = rest_pb_num_in_msdu;
dbg_dump_buf[2] = pb_num_per_mpdu;
dbg_dump_buf[3] = mpdu_num_to_send;
IOT_ASSERT_DUMP(0, (uint32_t *)(&mpdu_num_to_send), 4);
}
#endif
pb_num_to_send = min(rest_pb_num_in_msdu,
pb_num_per_mpdu * mpdu_num_to_send);
#if DEBUG_SPG_PER_MSDU_MPDU_TX
if ((PLC_PROTO_TYPE_SPG == proto)
&& (pb_num_to_send > PLC_MAX_PB_PER_MPDU)) {
/* spg must be 1msdu send by 1mpdu */
dbg_dump_buf[0] = pb_num_to_send;
dbg_dump_buf[1] = rest_pb_num_in_msdu;
dbg_dump_buf[2] = pb_num_per_mpdu;
dbg_dump_buf[3] = mpdu_num_to_send;
IOT_ASSERT_DUMP(0, dbg_dump_buf, 4);
}
#endif
swq_id = mac_q_get_swqid_from_phase_lid(&pdev->hwq_hdl,
phase, (lid_t)lid);
/* construct all the mpdu desc */
for (i = 0; i < mpdu_num_to_send; i++) {
/*tmp pointer to mpdu start*/
if (i == 0) {
list_start = 1;
tmp = &msdu->hw_desc.mpdu_list;
pb_buf_reuse = 0;
}
else {
list_start = 0;
pb_buf_reuse = 1;
}
/*is next exist && cal pb_num*/
if (i != mpdu_num_to_send - 1) {
mac_desc_get(&g_mac_desc_eng, PLC_TX_MPDU_START_POOL,
(void**)&next);
IOT_ASSERT(next);
list_end = 0;
pb_num = pb_num_per_mpdu;
}
else {
next = NULL;
list_end = 1;
pb_num = pb_num_to_send - (pb_num_per_mpdu * i);
IOT_ASSERT(pb_num <= pb_num_per_mpdu && pb_num);
}
pb_num_in_desc = pb_num;
/*get the bitmap && update msdu send_bitmap*/
tmp_bitmap = msdu->send_bitmap;
if (
#if CPLC_IOT_CERT_SUPPORT
mac_get_cert_test_flag() ||
#endif
(ENABLE_PER_PB_RETRY == 0)) {
j = 0;
while(pb_num) {
for(; j < 32; j += 8){
ret = iot_bitops_ffs((uint8_t)(tmp_bitmap >> j));
if (ret) {
pos = (ret + j - 1);
tmp_bitmap &= (~(0x01 << pos));
pb_num--;
break;
}
}
if (j == 32 && pb_num != 0) {
IOT_ASSERT(0);
}
}
/* for msdu retry */
if (msdu->retry_cnt) {
msdu->retry_cnt--;
}
} else {
(void)j;
uint32_t max_ssn = iot_ceil(msdu_len, (pb_sz - pb_hdr_resv_crc_len));
uint8_t wrap_around = 0;
if (msdu->is_first_try_done) {
if (msdu->last_pos == max_ssn) {
pos = 0;
} else {
pos = msdu->last_pos + 1;
}
} else {
pos = 0;
msdu->is_first_try_done = 1;
}
for (; pb_num && tmp_bitmap;) {
for (; pos <= max_ssn && pb_num; pos++) {
if ((0x1 << pos) & tmp_bitmap) {
tmp_bitmap &= (~(0x01 << pos));
pb_num--;
msdu->last_pos = pos;
if (!tmp_bitmap && pb_num) {
/* unlikely happen */
iot_printf("not enough pb to send? rest pb - %d\n",
pb_num);
IOT_ASSERT(0);
break;
}
}
}
if (pos > max_ssn) {
/* wrap around to the 1st pb of this mpdu */
pos = 0;
wrap_around = 1;
}
}
if (wrap_around || (0 == tmp_bitmap)) {
if (msdu->retry_cnt) {
/* every time sending to tip of msdu,
* or last mpdu to send, means a try */
msdu->retry_cnt--;
}
}
}
cur_send_bitmap = tmp_bitmap ^ msdu->send_bitmap;
#if PLC_MAC_TX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1
iot_printf("---send_bitmap=0x%x/0x%x,HW_R_C=%d, ntb:%lu\n",
cur_send_bitmap, msdu->send_bitmap, hwretry_cnt,
mac_sched_get_ntb(NULL));
#endif
/*fill pb_list for mpdu*/
mac_tx_mpdu_form_pb_list(&pb_list,
data_buf, pb_num_per_mpdu, cur_send_bitmap, pb_sz, proto);
/*fill mpdu end*/
mac_desc_get(&g_mac_desc_eng, PLC_TX_MPDU_END_POOL,
(void**)&tx_status);
IOT_ASSERT(tx_status);
hw_band_id = phy_proto_band_to_hw_band(proto_single_band);
/*fill macinfo*/
sym_ppb = phy_get_symppb_from_table(hw_band_id,
tmi, ext_tmi);
fl_ppb = phy_get_flppb_from_table(hw_band_id,
tmi, ext_tmi);
if (sym_ppb == 0 || fl_ppb == 0) {
iot_printf("%s,sym_ppb or fl_ppb = 0,proto_band:%d,tx_band:%d,"
"tmi:%d, exttmi:%d\n",
__FUNCTION__, phy_band_id_get(), hw_band_id,
tmi, ext_tmi);
IOT_ASSERT(0);
return ERR_FAIL;
}
mac_tx_mpdu_fill_macinfo(tmp,
swq_id, pb_num_in_desc, 0,
need_ack, sym_ppb,
fl_ppb, 0,
pb_hdr_resv_crc_len,
hwretry_cnt, list_start, list_end,
tx_status, pb_list,
next, pb_buf_reuse,
(uint32_t)iot_pkt_data(data_buf)-(uint32_t)data_buf, 1,
0, 0, 0, 0);
/*fill phyinfo*/
mac_tx_mpdu_fill_phyinfo(tmp,
HW_DESC_TX_PORT_PLC, tx_power, msdu->tx_3phase?PLC_PHASE_ALL:phase,
hw_band_id, HW_DESC_PPDU_MODE_HYBRID_1FCSYM,
0, pb_mod, rate_mode
);
/*fill fc*/
mac_tx_mpdu_fill_fcinfo(tmp, proto, pb_num_in_desc, phase,
delimiter_type, network, nid, 0, tmi, ext_tmi, dtei, stei,
(uint8_t)lid, is_bcast, msdu->retry, 0, 0, 0, NULL);
/* for dbg pkt */
if (msdu->is_dbg_pkt) {
mac_tx_set_mpdu_ppm(tmp, proto, delimiter_type,
(msdu->ppm_step_type == MAC_PPM_STEP_TYPE_TX)
? (uint8_t)msdu->ppm_step : (uint8_t)(msdu->retry_cnt + 1),
(msdu->ppm_step_type == MAC_PPM_STEP_TYPE_TX));
}
tmp = next;
}
/* calulate hwqid */
hwqid = mac_q_create_hwqid_from_swqid(&pdev->hwq_hdl,
swq_id);
if (msdu->is_dbg_pkt && (msdu->ppm_step_type == MAC_PPM_STEP_TYPE_TXRX)) {
mac_multi_sync_apply_new_ppm_step(pdev->pdev_id, PLC_DBG_PKT_MODE_NID,
msdu->ppm_step);
}
mac_add_swq_to_hwq_cnt();
/* enqueue to hwq */
msdu->in_hwq = 1;
return mac_tx_hw_mpdu(&pdev->hwq_hdl,
hwqid, &msdu->hw_desc.mpdu_list);
}
/* TODO:this file need move to msdu.c */
/* return need free msdu */
mac_msdu_t *mac_tx_hw_msdu_comp(uint32_t hwq_id,
tx_mpdu_start *current_mpdu, mac_pdev_t *pdev, uint32_t is_phy_comp)
{
uint8_t pkt_state = IOT_PKT_STATE_UNKNOWN;
uint32_t pb_ssn, mask;
uint32_t mpdu_sack_bitmap;
tx_pb_start *pbstart;
uint8_t is_msdu_free;
mac_msdu_t *msdu = pdev->hwq_hdl.cur_msdu_ptr[hwq_id];
IOT_ASSERT(current_mpdu);
/*get mac_msdu addr*/
if (current_mpdu->list_start) {
IOT_ASSERT(msdu == NULL);
msdu = (mac_msdu_t*)current_mpdu;
pdev->hwq_hdl.cur_msdu_ptr[hwq_id] = current_mpdu;
}
/* for peer's rate info */
mac_stream_t *stream = msdu->ref_mac_stream;
mac_peer_t *peer = NULL;
if (stream && stream->peer) {
peer = stream->peer;
is_msdu_free = 0;
} else {
is_msdu_free = 1;
/* force msdu all mpdu tx done */
if (!current_mpdu->list_end) {
current_mpdu->next->tx_status->tx_done = 1;
}
}
#if FORCE_MAX_SW_RETRY
current_mpdu->tx_status->sack_bitmap = 0;
current_mpdu->tx_status->tx_ok = 0;
#endif
if (is_phy_comp && msdu && !msdu->retry) {
mac_add_msdu_tx_cnt();
}
/* if sw retry broadcast */
if (!mac_is_unicast(PHY_PROTO_TYPE_GET(),
mac_tx_mpdu_start_get_fc_ptr(current_mpdu), 0)) {
mac_add_mpdu_tx_broadcast_cnt();
if (mac_get_bcast_hwretry_cfg(pdev)
&& !mac_msdu_is_force_swretry(msdu)) {
/* hw retry for bcast */
current_mpdu->tx_status->tx_ok = 1;
current_mpdu->tx_status->sack_bitmap =
(1 << (current_mpdu->pb_num)) - 1;
} else {
/* if sw retry for bcast, we need to clear sack bitmap */
current_mpdu->tx_status->tx_ok = 1;
current_mpdu->tx_status->sack_bitmap = 0;
}
if (msdu->retry_cnt) {
msdu->retry = 1;
}
}
else
{
//tx unicast cnt
void *fc = mac_tx_mpdu_start_get_fc_ptr(current_mpdu);
mac_vdev_t *vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_DEFAULT_VDEV);
mac_add_mpdu_tx_unicast_cnt(vdev->proxy_tei ==
mac_get_fc_dtei(phy_proto_type_get(), fc));
}
/*use the sack_bitmap for retry*/
IOT_ASSERT(current_mpdu->tx_status);
if (!current_mpdu->tx_status->tx_ok) {
if (peer) {
/* record no sack continue */
ra_add_no_sack_cnt(&peer->rate_info);
}
current_mpdu->tx_status->sack_bitmap = 0;
if (
#if CPLC_IOT_CERT_SUPPORT
mac_get_cert_test_flag() ||
#endif
(ENA_ALWAYS_SET_RETRY_BIT)) {
/* if msdu retry, set this retry to 1 for every mpdu */
msdu->retry = 1;
}
}
else{
if (peer) {
/* rx ok, so clear the cnt */
ra_clr_no_sack_cnt(&peer->rate_info);
}
if (
#if CPLC_IOT_CERT_SUPPORT
mac_get_cert_test_flag() ||
#endif
(ENABLE_PER_PB_RETRY == 0)) {
mask = (1 << (current_mpdu->pb_num));
mask -= 1;
if (((current_mpdu->tx_status->sack_bitmap) & mask) != mask) {
/* for msdu retry, if any pb failed, set retry = 1 for
* all mpdu in this msdu, this would have bad
* performance if the drop rate is high
*/
/* not all pb rx, think we never tx this mpdu,
* so retry all pb of this mpdu one more time
*/
current_mpdu->tx_status->sack_bitmap = 0;
msdu->retry = 1;
}
} else {
if (msdu->retry == 0 &&
((current_mpdu->tx_status->sack_bitmap) &
((1 << (current_mpdu->pb_num)) - 1))!= 0) {
/* if one pb successful, all the rest pbs are all retry */
msdu->retry = 1;
}
}
}
/*update bitmap*/
if (msdu) {
if (current_mpdu->pb_list != NULL) {
mpdu_sack_bitmap = current_mpdu->tx_status->sack_bitmap;
pbstart = current_mpdu->pb_list;
for (uint8_t i = 0; i < PLC_SG_MAX_PB_NUM; i++) {
if (pbstart == NULL) {
break;
}
if (i >= current_mpdu->pb_num) {
iot_printf("pb list node num:%d >= pb num:%d\n", i,
current_mpdu->pb_num);
IOT_ASSERT(0);
}
if (mpdu_sack_bitmap & (0x1 << i)) {
pb_ssn = mac_tx_pb_start_get_pb_ssn(PHY_PROTO_TYPE_GET(),
pbstart);
/* TODO: extract the retry logic to hal layer */
mac_msdu_update_with_acked_ssn(msdu, pb_ssn);
}
pbstart = mac_tx_pb_start_get_next_pb(pbstart);
}
#if DEBUG_SSN
iot_printf("--msdu:ssn%d,sack:0x%x,send:0x%x,retry=%d\n",
pb_ssn, sack_bitmap, send_bitmap,
current_mpdu->fc.sg_fc.vf.sof.retry);
#endif
}
}
if (!current_mpdu->tx_status->is_phyerr &&
!current_mpdu->tx_status->is_macerr) {
mask = (1 << (current_mpdu->pb_num)) - 1;
if ((((current_mpdu->tx_status->sack_bitmap) & mask) == mask)) {
pkt_state = IOT_PKT_STATE_TX_OK_RX_OK;
} else {
pkt_state = IOT_PKT_STATE_TX_OK_RX_UNKNOWN;
}
} else {
pkt_state = IOT_PKT_STATE_TX_FAIL;
}
if (current_mpdu->list_end)
{
IOT_ASSERT(msdu && msdu->buf && msdu->in_hwq);
if (msdu->send_bitmap == 0) {
/* all pb sent ok, time to free the buf */
if (msdu->buf_need_free == 1) {
iot_pkt_free_tx_done(msdu->buf, pkt_state);
}
msdu->buf = NULL;
}
else{
if(msdu->retry_cnt == 0) {
if (msdu->buf_need_free == 1) {
iot_pkt_free_tx_done(msdu->buf, pkt_state);
}
msdu->buf = NULL;
}
}
pdev->hwq_hdl.cur_msdu_ptr[hwq_id] = NULL;
msdu->in_hwq = 0;
if (is_msdu_free) {
return msdu;
}
}
return NULL;
}