757 lines
24 KiB
C
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;
|
|
}
|