755 lines
24 KiB
C
Executable File
755 lines
24 KiB
C
Executable File
/****************************************************************************
|
|
|
|
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 "rx_pb_reorder.h"
|
|
#include "iot_errno.h"
|
|
#include "iot_io.h"
|
|
#include "mac_data_api.h"
|
|
#include "mac_desc_engine.h"
|
|
#include <math.h>
|
|
#include "hw_tonemap.h"
|
|
#include "mac_stream.h"
|
|
#include "mac_vdev.h"
|
|
#include "mac_peer.h"
|
|
#include "mac_data.h"
|
|
|
|
#include "mac_rx_hw.h"
|
|
#include "phy_bb.h"
|
|
#include "mpdu_header.h"
|
|
|
|
#include "iot_dbglog_api.h"
|
|
#include "iot_dbglog_parser.h"
|
|
|
|
#if ENA_ALWAYS_SET_RETRY_BIT == 0
|
|
#include "mac_cert_test.h"
|
|
#endif
|
|
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
#include "rf_hw_tonemap.h"
|
|
#include "mac_rf_rx_buf_ring.h"
|
|
#endif
|
|
|
|
inline uint32_t pb_buf_list_init(pb_buf_list_t *pb,
|
|
uint32_t msdu_st,
|
|
uint32_t msdu_ed,
|
|
uint32_t ssn,
|
|
iot_pkt_t *pb_buf)
|
|
{
|
|
pb->msdu_end = msdu_ed;
|
|
pb->msdu_start = msdu_st;
|
|
pb->next = NULL;
|
|
pb->pb_buf = pb_buf;
|
|
pb->ssn = ssn;
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t reorder_buf_init(
|
|
reorder_msdu_buf_t *msdu, \
|
|
void *stream /* refer stream */
|
|
)
|
|
{
|
|
(void)stream;
|
|
/* temp solution */
|
|
if (!msdu /*|| !stream*/)
|
|
{
|
|
return ERR_INVAL;
|
|
}
|
|
msdu->pb_rdy_cnt = 0;
|
|
msdu->pb_total_cnt = INV_PB_TOTAL_CNT;
|
|
pb_buf_list_init(&msdu->pb_list, \
|
|
0, 0, 0, NULL);
|
|
msdu->pb_alloc_cnt = 1;
|
|
msdu->is_reused = 0;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t reorder_buf_free(reorder_msdu_buf_t *msdu)
|
|
{
|
|
uint32_t pb_buf_cnt = 1;
|
|
pb_buf_list_t *entry = msdu->pb_list.next;
|
|
pb_buf_list_t *tmp = entry;
|
|
|
|
if(msdu->pb_list.pb_buf){
|
|
iot_pkt_free(msdu->pb_list.pb_buf);
|
|
}
|
|
|
|
for(;pb_buf_cnt <= msdu->pb_alloc_cnt;){
|
|
if(tmp == NULL){
|
|
break;
|
|
}
|
|
entry = tmp->next;
|
|
if(tmp->pb_buf){
|
|
iot_pkt_free(tmp->pb_buf);
|
|
}
|
|
os_mem_set(tmp, 0, sizeof(pb_buf_list_t));
|
|
mac_desc_free(&g_mac_desc_eng, \
|
|
PLC_RX_PB_DESC_POOL,tmp);
|
|
tmp = entry;
|
|
pb_buf_cnt++;
|
|
}
|
|
IOT_ASSERT(pb_buf_cnt == msdu->pb_alloc_cnt && tmp == NULL);
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t reorder_buf_free_pb_list(reorder_msdu_buf_t *msdu)
|
|
{
|
|
uint32_t pb_buf_cnt = 1;
|
|
pb_buf_list_t *entry = msdu->pb_list.next;
|
|
pb_buf_list_t *tmp = entry;
|
|
|
|
for(;pb_buf_cnt < msdu->pb_alloc_cnt;){
|
|
if(tmp == NULL){
|
|
break;
|
|
}
|
|
entry = tmp->next;
|
|
if(tmp->pb_buf){
|
|
iot_pkt_free(tmp->pb_buf);
|
|
}
|
|
tmp->next = NULL;
|
|
mac_desc_free(&g_mac_desc_eng, \
|
|
PLC_RX_PB_DESC_POOL,tmp);
|
|
tmp = entry;
|
|
pb_buf_cnt++;
|
|
}
|
|
IOT_ASSERT(pb_buf_cnt == msdu->pb_alloc_cnt && tmp == NULL);
|
|
msdu->pb_alloc_cnt = 1;
|
|
msdu->pb_list.next = NULL;
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t reorder_buf_init_first_pb(
|
|
reorder_msdu_buf_t *msdu, \
|
|
uint32_t pkt_size, /* msdu buf len */
|
|
void *stream, /* refer stream */
|
|
uint32_t msdu_st,
|
|
uint32_t msdu_ed,
|
|
uint32_t ssn,
|
|
/* must be the msdu_start pb if not null,
|
|
* to optimize the memory usage,
|
|
* we can use the same pb buf if
|
|
* the msdu len is smaller than
|
|
* the pb size
|
|
*/
|
|
iot_pkt_t *pb_buf
|
|
)
|
|
{
|
|
(void)stream;
|
|
if (!msdu)
|
|
{
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
if (pb_buf) {
|
|
if (ssn != 0 || msdu_st != 1) {
|
|
/* must be the first pb */
|
|
return ERR_INVAL;
|
|
}
|
|
rx_buf_hdr_t *hdr = \
|
|
(rx_buf_hdr_t *)iot_pkt_data(pb_buf);
|
|
IOT_ASSERT(hdr->pb_st.msdu_start
|
|
&& hdr->pb_ed.rx_pb_crc_err == 0
|
|
/* && hdr->mpdu_st.fc.sg_fc.vf.sof.retry == 0 */
|
|
);
|
|
msdu->pb_rdy_cnt = 1;
|
|
if (pkt_size) {
|
|
msdu->pb_total_cnt =
|
|
(uint32_t)iot_ceil(pkt_size, \
|
|
iot_pkt_data_len(pb_buf));
|
|
}
|
|
else {
|
|
msdu->pb_total_cnt = INV_PB_TOTAL_CNT;
|
|
}
|
|
}
|
|
else {
|
|
msdu->pb_rdy_cnt = 0;
|
|
msdu->pb_total_cnt = INV_PB_TOTAL_CNT;
|
|
}
|
|
|
|
pb_buf_list_init(&msdu->pb_list, \
|
|
msdu_st, msdu_ed, ssn, pb_buf);
|
|
msdu->pb_alloc_cnt = 1;
|
|
msdu->is_reused = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* flush the reorder buf
|
|
* reset the msdu's counter
|
|
* and free all the pb_bufs,
|
|
* but keep the pb_buf_list allocated for fast allocation.
|
|
* usually called when a new msdu's pb received
|
|
*/
|
|
uint32_t reorder_buf_flush(reorder_msdu_buf_t *msdu)
|
|
{
|
|
uint32_t pb_buf_cnt = 0;
|
|
if (!msdu) {
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
pb_buf_list_t *pb = &msdu->pb_list;
|
|
do {
|
|
if (pb->pb_buf) {
|
|
iot_pkt_free(pb->pb_buf);
|
|
pb->pb_buf = NULL;
|
|
}
|
|
pb_buf_cnt++;
|
|
pb = pb->next;
|
|
} while (pb);
|
|
if (pb_buf_cnt != msdu->pb_alloc_cnt) {
|
|
*(uint32_t *)(msdu + 1) = pb_buf_cnt;
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)msdu, \
|
|
sizeof(*msdu)/sizeof(uint32_t) + 1);
|
|
}
|
|
|
|
msdu->pb_rdy_cnt = 0;
|
|
msdu->pb_total_cnt = INV_PB_TOTAL_CNT;
|
|
return ERR_OK;
|
|
}
|
|
|
|
#if DEBUG_PKT_OVERFLOW
|
|
//TODO:for debug iot_pkt set newtail assert bug, and put off later
|
|
typedef struct _dump_buf {
|
|
uint32_t p_data;
|
|
uint32_t p_end;
|
|
uint32_t buf_len;
|
|
uint32_t resv_len;
|
|
uint8_t fc[16];
|
|
}dump_buf_t;
|
|
#endif
|
|
/* release the msdu */
|
|
uint32_t reorder_buf_release(reorder_msdu_buf_t *msdu)
|
|
{
|
|
nid_t nid;
|
|
void *fc = NULL;
|
|
rx_buf_hdr_t *hdr;
|
|
|
|
if (!msdu) {
|
|
return ERR_INVAL;
|
|
}
|
|
IOT_ASSERT(msdu->pb_rdy_cnt == msdu->pb_total_cnt \
|
|
&& msdu->pb_rdy_cnt <= msdu->pb_alloc_cnt);
|
|
|
|
mac_peer_t *peer = NULL;
|
|
mac_stream_t *stream = NULL;
|
|
mac_vdev_t *vdev = NULL;
|
|
iot_pkt_t *msdu_buf, *pb_buf;
|
|
uint32_t proto = PHY_PROTO_TYPE_GET();
|
|
|
|
uint32_t pb_hdr_resv_crc_len = mac_get_pb_hdr_resv_crc_len(FC_DELIM_SOF,
|
|
proto);
|
|
pb_buf_list_t *pb = &msdu->pb_list;
|
|
pb_buf = pb->pb_buf;
|
|
stream = container_of(msdu, mac_stream_t, msdu.rx.reorder_buf);
|
|
if (pb_buf == NULL) {
|
|
mac_add_rx_msdu_null_first_pb_cnt();
|
|
if (stream && stream->peer) {
|
|
vdev = get_vdev_ptr(stream->peer->pdev_id, stream->peer->vdev_id);
|
|
vdev_get_nid(vdev, &nid);
|
|
iot_printf("msdu rx null pb, nid%d, tei%d, lid%d, "
|
|
"msdu_null_first_pb_cnt=%u\n", \
|
|
nid, \
|
|
stream->peer->tei, \
|
|
stream->lid, mac_get_rx_msdu_null_first_pb_cnt());
|
|
}
|
|
#if !WAR_BUGID757_EN
|
|
IOT_ASSERT(0);
|
|
#endif
|
|
reorder_buf_flush(msdu);
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
uint32_t pb_sz = PB_SIZE_INV, ret, msdu_pad_len, pb_buf_aval_len, i = 0;
|
|
int8_t snr = INVALID_SNR;
|
|
uint8_t phase = PLC_PHASE_ALL;
|
|
uint32_t req_buf_len;
|
|
uint8_t rssi = INV_RSSI;
|
|
int8_t rf_rssi = INV_RSSI_RF;
|
|
uint8_t channel_id = 0;
|
|
/* get rx message from fc */
|
|
rx_fc_msg_t msg = {0};
|
|
|
|
if (!stream->is_rf) {
|
|
hdr = (rx_buf_hdr_t *)iot_pkt_data(pb_buf);
|
|
IOT_ASSERT(hdr->pb_st.msdu_start && (hdr->pb_ed.rx_pb_crc_err == 0));
|
|
|
|
fc = mac_rx_mpdu_st_get_fc_addr(&hdr->mpdu_st);
|
|
|
|
if (hdr->pb_st.first_pb) {
|
|
/* get the default snr if only one pb */
|
|
snr = mac_rx_mpdu_st_get_avg_snr(&hdr->mpdu_st);
|
|
phase = mac_rx_mpdu_st_get_rx_phase(&hdr->mpdu_st);
|
|
rssi = PHY_RSSI_FROM_RMI_GAIN(
|
|
mac_rx_mpdu_st_get_adc_power(&hdr->mpdu_st),
|
|
mac_rx_mpdu_st_get_agc_gain_entry(&hdr->mpdu_st));
|
|
if (rssi != INV_RSSI) {
|
|
rssi = min(MAX_RSSI, rssi);
|
|
rssi = max(MIN_RSSI, rssi);
|
|
}
|
|
}
|
|
|
|
mac_get_rx_frm_msg_from_fc(proto, fc, &msg);
|
|
|
|
ret = phy_get_pb_size(proto, msg.tmi, msg.tmi_ext, &pb_sz);
|
|
IOT_ASSERT(0 == ret);
|
|
if (pb_sz == PB_SIZE_INV) {
|
|
iot_printf("pb_sz err,tmi=%d,ex_tmi=%d\n", msg.tmi, msg.tmi_ext);
|
|
return ERR_INVAL;
|
|
}
|
|
} else {
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
rf_rx_buf_hdr_t *rf_hdr;
|
|
rf_hdr = (rf_rx_buf_hdr_t *)iot_pkt_data(pb_buf);
|
|
IOT_ASSERT(rf_hdr->pb_ed.rx_pb_crc_err == 0);
|
|
|
|
fc = mac_rf_rx_mpdu_st_get_phr_addr(&rf_hdr->mpdu_st);
|
|
|
|
snr = mac_rf_rx_mpdu_st_get_avg_snr(&rf_hdr->mpdu_st);
|
|
rf_rssi = mac_rf_rx_mpdu_st_get_rssi(&rf_hdr->mpdu_st);
|
|
if (rssi != INV_RSSI_RF) {
|
|
rf_rssi = min(MAX_RSSI_RF, rf_rssi);
|
|
rf_rssi = max(MIN_RSSI_RF, rf_rssi);
|
|
}
|
|
mac_get_rx_frm_msg_from_fc(proto, fc, &msg);
|
|
pb_sz = phy_rf_get_pbsz(msg.rf_pb_sz_idx);
|
|
#else
|
|
(void)rf_rssi;
|
|
/* if not support rf, stream->is_rf must be 0 */
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)msdu, sizeof(*msdu));
|
|
#endif
|
|
}
|
|
|
|
/* aval len for first pb */
|
|
pb_buf_aval_len = iot_pkt_data_len(pb_buf) \
|
|
+ iot_pkt_tail_len(pb_buf);
|
|
msdu_pad_len = (pb_sz) * msdu->pb_total_cnt;
|
|
req_buf_len = RX_FWD_RESV_LEN
|
|
+ (pb_sz - pb_hdr_resv_crc_len) * msdu->pb_total_cnt;
|
|
|
|
if (((pb_buf_aval_len - sizeof(rx_buf_hdr_t)) >= ((req_buf_len) - \
|
|
RX_FWD_RESV_LEN)) && (sizeof(rx_buf_hdr_t) >= RX_FWD_RESV_LEN)) {
|
|
/* pb buf could be reused as msdu buf because the len is enough,
|
|
* as long as header size is adequate and no need to copy
|
|
*/
|
|
/* skip the written rx buf header
|
|
* before this, the data pointer is at 0 offset
|
|
*/
|
|
uint8_t *pkt = iot_pkt_pull(pb_buf, sizeof(rx_buf_hdr_t));
|
|
if (pkt == NULL) {
|
|
IOT_ASSERT(0);
|
|
return ERR_FAIL;
|
|
}
|
|
iot_pkt_set_tail(pb_buf, pkt + pb_sz - pb_hdr_resv_crc_len);
|
|
msdu_buf = pb_buf;
|
|
msdu->is_reused = 1;
|
|
}
|
|
else {
|
|
/* if the left space for the first pb is not enough
|
|
* we have to try to alloc a new msdu buf
|
|
*/
|
|
IOT_PKT_GET(msdu_buf, req_buf_len, RX_FWD_RESV_LEN, PLC_MAC_RX_MID);
|
|
if (!msdu_buf) {
|
|
uint32_t bufsz;
|
|
uint32_t freenum[IOT_PKT_POOL_MAX] = {0};
|
|
uint32_t totalnum;
|
|
iot_printf("no buf for msdu 0x%x forming, msdu dropped.\n", msdu);
|
|
uint8_t j;
|
|
for (j = 0; j < IOT_PKT_POOL_MAX; j++) {
|
|
iot_pkt_pktpool_status(j, &bufsz, freenum + j, &totalnum);
|
|
}
|
|
|
|
mac_pdev_t *pdev_t = g_mac_pdev[PLC_PDEV_ID];
|
|
rx_buf_ring_t *ring0 = &pdev_t->ring_hdl.ring[0];
|
|
uint32_t ring0_dp = (ring0->read_idx <<16 & 0xffff0000) | \
|
|
(ring0->write_idx & 0xffff);
|
|
rx_buf_ring_t *ring1 = &pdev_t->ring_hdl.ring[1];
|
|
uint32_t ring1_dp = (ring1->read_idx <<16 & 0xffff0000) | \
|
|
(ring1->write_idx & 0xffff);
|
|
|
|
iot_printf("req_buf_len:%d, pb_sz:%d, cnt:%d, free0:%d, free1:%d"\
|
|
"free2:%d, free3:%d,free4:%d, free5:%d, ring0 w:%d, r:%d, "\
|
|
"ring1 w:%d, r:%d\n",req_buf_len, pb_sz, msdu->pb_total_cnt,\
|
|
freenum[0], freenum[1], freenum[2], freenum[3], freenum[4],\
|
|
freenum[5], ring0->write_idx, ring0->read_idx, \
|
|
ring1->write_idx, ring1->read_idx);
|
|
|
|
uint32_t * dump_buf_addr = (uint32_t *)pb_buf - 11;
|
|
*dump_buf_addr = req_buf_len;
|
|
*(dump_buf_addr + 1) = pb_sz;
|
|
*(dump_buf_addr + 2) = msdu->pb_total_cnt;
|
|
*(dump_buf_addr + 3) = freenum[0];
|
|
*(dump_buf_addr + 4) = freenum[1];
|
|
*(dump_buf_addr + 5) = freenum[2];
|
|
*(dump_buf_addr + 6) = freenum[3];
|
|
*(dump_buf_addr + 7) = freenum[4];
|
|
*(dump_buf_addr + 8) = freenum[5];
|
|
*(dump_buf_addr + 9) = ring0_dp;
|
|
*(dump_buf_addr + 10) = ring1_dp;
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)dump_buf_addr, \
|
|
(pb_buf_aval_len/sizeof(uint32_t))+12);
|
|
//IOT_ASSERT(0);
|
|
return ERR_FAIL;
|
|
}
|
|
msdu->is_reused = 0;
|
|
}
|
|
uint8_t *dest = iot_pkt_data(msdu_buf);
|
|
uint32_t copy_bytes = pb_sz - pb_hdr_resv_crc_len;
|
|
do {
|
|
if (msdu->is_reused && i == 0) {
|
|
/* skip the first node if reused */
|
|
i++;
|
|
pb = pb->next;
|
|
continue;
|
|
}
|
|
|
|
if (pb->pb_buf) {
|
|
dest = iot_pkt_put(msdu_buf, copy_bytes);
|
|
IOT_ASSERT(dest && pb->ssn == i);
|
|
os_mem_cpy(dest + i * copy_bytes, \
|
|
iot_pkt_data(pb->pb_buf) + sizeof(rx_buf_hdr_t), \
|
|
copy_bytes);
|
|
iot_pkt_free(pb->pb_buf);
|
|
pb->pb_buf = NULL;
|
|
}
|
|
else {
|
|
#if ENABLE_PER_PB_RETRY
|
|
/* pb_buf should be exist for per pb case */
|
|
iot_printf("pb ssn%d buf not enough\n", i);
|
|
IOT_ASSERT(0);
|
|
#endif
|
|
return ERR_FAIL;
|
|
}
|
|
i++;
|
|
pb = pb->next;
|
|
} while (pb && i < msdu->pb_total_cnt);
|
|
/* copy mac_rx_info_t */
|
|
mac_rx_info_t *rx_info = (mac_rx_info_t *)(dest - sizeof(mac_rx_info_t));
|
|
/* todo: mac_convert_fc_rf_to_hplc() */
|
|
os_mem_cpy(rx_info->fc, fc, sizeof(rx_info->fc));
|
|
/* for sof frame, this value is set to 0 by default */
|
|
rx_info->delta_ntb = 0;
|
|
if (snr != INVALID_SNR) {
|
|
rx_info->phy.snr = snr;
|
|
}
|
|
else {
|
|
/* no last pb's snr info, should
|
|
* not happen
|
|
* TODO: check if this could save from the lower layer
|
|
*/
|
|
rx_info->phy.snr = snr;
|
|
}
|
|
rx_info->phy.phase = phase;
|
|
rx_info->phy.is_rf = stream->is_rf;
|
|
if (rx_info->phy.is_rf) {
|
|
rx_info->phy.rssi = rf_rssi;
|
|
} else {
|
|
rx_info->phy.rssi = PHY_RSSI_DBUV_TO_DBM(rssi);
|
|
}
|
|
rx_info->phy.band_id = (uint8_t)phy_band_id_get();
|
|
rx_info->phy.channel_id = channel_id;
|
|
|
|
/* set tail ptr to msdu pad len */
|
|
|
|
#if DEBUG_PKT_OVERFLOW
|
|
//TODO:for debug iot_pkt set newtail assert bug, and put off later
|
|
if(((uint8_t *)(iot_pkt_data(msdu_buf) + req_buf_len - RX_FWD_RESV_LEN) < \
|
|
msdu_buf->data) || \
|
|
((uint8_t *)(iot_pkt_data(msdu_buf) + req_buf_len - RX_FWD_RESV_LEN) > \
|
|
msdu_buf->end))
|
|
{
|
|
iot_printf("tail err! data:%p, end:%p, buf_len:%d, resv_len:%d\n",
|
|
iot_pkt_data(msdu_buf), \
|
|
iot_pkt_block_ptr(msdu_buf, IOT_PKT_BLOCK_END),\
|
|
req_buf_len, RX_FWD_RESV_LEN);
|
|
dump_buf_t dump_buf;
|
|
dump_buf.p_data = (uint32_t)iot_pkt_data(msdu_buf);
|
|
dump_buf.p_end = (uint32_t)iot_pkt_block_ptr(msdu_buf, IOT_PKT_BLOCK_END);
|
|
dump_buf.buf_len = req_buf_len;
|
|
dump_buf.resv_len = RX_FWD_RESV_LEN;
|
|
//for debug pbsize = 0
|
|
os_mem_cpy(dump_buf.fc, fc, sizeof(dump_buf.fc));
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)&dump_buf, 4);
|
|
}
|
|
#endif
|
|
|
|
dest = iot_pkt_set_tail(msdu_buf, \
|
|
iot_pkt_data(msdu_buf) + req_buf_len - RX_FWD_RESV_LEN);
|
|
IOT_ASSERT(dest);
|
|
|
|
/* upload to upper layer */
|
|
#if PLC_MAC_RX_DEBUG_LOG
|
|
iot_printf("msdu pad len %d formed with %d PBs\n", \
|
|
msdu_pad_len, \
|
|
msdu->pb_total_cnt);
|
|
iot_dbglog_input(PLC_MAC_REORDER_MID, DBGLOG_INFO_LVL_2,
|
|
IOT_MAC_PLD_INFO, 2, \
|
|
msdu_pad_len, \
|
|
msdu->pb_total_cnt);
|
|
#else
|
|
(void)msdu_pad_len;
|
|
#endif
|
|
//IOT_ASSERT(stream && stream->peer && get_vdev_ptr(stream->peer->pdev_id,
|
|
// stream->peer->vdev_id));
|
|
if (stream && stream->peer)
|
|
{
|
|
peer = stream->peer;
|
|
vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
|
|
if (vdev) {
|
|
mac_data_rx_msdu(vdev, msdu_buf);
|
|
}
|
|
}
|
|
else {
|
|
iot_pkt_free(msdu_buf);
|
|
}
|
|
|
|
/* TODO: release desc every release to save some STA's memory here,
|
|
* but CCO could ignore this to save some cpu cycle
|
|
*/
|
|
reorder_buf_free_pb_list(msdu);
|
|
|
|
/* after release, do some clean job */
|
|
if (msdu->is_reused) {
|
|
/* for reuse case, don't free the first pb
|
|
* as upper layer to free it,
|
|
* but set pb_buf list to NULL to avoid double free when flush
|
|
* other pb already freed when copy done
|
|
*/
|
|
if (msdu->pb_list.pb_buf) {
|
|
msdu->pb_list.pb_buf = NULL;
|
|
}
|
|
}
|
|
msdu->pb_rdy_cnt = 0;
|
|
msdu->pb_total_cnt = INV_PB_TOTAL_CNT;
|
|
|
|
if (peer && peer->is_bcast_peer && !stream->is_tx
|
|
&& !msdu->is_reused) {
|
|
/* if bcast peer, release the stream to save some memory */
|
|
mac_stream_free(peer, stream);
|
|
}
|
|
|
|
mac_peer_del_temp_peer(peer);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/*
|
|
* insert to exist msdu reorder structure
|
|
*/
|
|
uint32_t reorder_buf_insert(reorder_msdu_buf_t *msdu,
|
|
iot_pkt_t *pb_buf, uint32_t ssn, uint32_t msdu_start,
|
|
uint32_t msdu_end, uint32_t is_retry, uint32_t pbsz)
|
|
{
|
|
pb_buf_list_t *pb, *tmp, *tmp_next;
|
|
mac_stream_t *stream;
|
|
rx_buf_hdr_t *hdr, *tmp_hdr;
|
|
uint32_t ret, i, dup = 0;
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
rf_rx_buf_hdr_t *rf_hdr, *tmp_rf_hdr;
|
|
#endif
|
|
|
|
if (!msdu || !pb_buf || ssn == INV_PB_SSN \
|
|
|| msdu_start > 1 || msdu_end > 1) {
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
stream = container_of(msdu, mac_stream_t, msdu.rx.reorder_buf);
|
|
|
|
hdr = (rx_buf_hdr_t *)iot_pkt_data(pb_buf);
|
|
if (!stream->is_rf) {
|
|
IOT_ASSERT(hdr->pb_ed.rx_pb_crc_err == 0);
|
|
} else {
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
rf_hdr = (rf_rx_buf_hdr_t *)hdr;
|
|
IOT_ASSERT(rf_hdr->pb_ed.rx_pb_crc_err == 0);
|
|
#else
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)stream, sizeof(*stream));
|
|
#endif
|
|
/* check rf rx */
|
|
#if HPLC_RF_MPDU_SINGLE_PB
|
|
if (!msdu_end || !msdu_start || ssn) {
|
|
iot_printf("[WARN]rf rx msdu_end:%d, msdu_start:%d, ssn:%d\n",
|
|
msdu_end, msdu_start, ssn);
|
|
msdu_end = 1;
|
|
msdu_start = 1;
|
|
ssn = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pbsz != msdu->pbsz || (is_retry == 0 && ssn == 0)) {
|
|
/* if pbsz changed */
|
|
reorder_buf_flush(msdu);
|
|
}
|
|
|
|
if (msdu_end) {
|
|
if ((INV_PB_TOTAL_CNT != msdu->pb_total_cnt) && \
|
|
(msdu->pb_total_cnt != (ssn + 1))) {
|
|
/* rx diff pb cnt msdu(bcast msdu), flush old msdu*/
|
|
reorder_buf_flush(msdu);
|
|
}
|
|
/* update total cnt if msdu end */
|
|
msdu->pb_total_cnt = ssn + 1;
|
|
}
|
|
|
|
/* find the place to insert */
|
|
for (i = 0, tmp = &msdu->pb_list, tmp_next = tmp->next;
|
|
i <= ssn; i++, tmp = tmp->next, tmp_next = tmp->next) {
|
|
if (tmp->ssn == ssn) {
|
|
/* insert */
|
|
/* check crc */
|
|
if (tmp->pb_buf) {
|
|
if (!stream->is_rf) {
|
|
hdr = (rx_buf_hdr_t *)iot_pkt_data(pb_buf);
|
|
tmp_hdr = (rx_buf_hdr_t *)iot_pkt_data(tmp->pb_buf);
|
|
if (mac_rx_pb_end_get_pb_crc(&hdr->pb_ed)
|
|
== mac_rx_pb_end_get_pb_crc(&tmp_hdr->pb_ed)) {
|
|
/* dup pb received */
|
|
/* free the old pb buf */
|
|
iot_pkt_free(tmp->pb_buf);
|
|
tmp->pb_buf = NULL;
|
|
dup = 1;
|
|
} else {
|
|
/* we should flush, as the new pb arrived */
|
|
reorder_buf_flush(msdu);
|
|
}
|
|
} else {
|
|
#if HPLC_RF_DEV_SUPPORT
|
|
rf_hdr = (rf_rx_buf_hdr_t *)hdr;
|
|
tmp_rf_hdr = (rf_rx_buf_hdr_t *)iot_pkt_data(tmp->pb_buf);
|
|
if (mac_rf_rx_pb_end_get_pb_crc(&rf_hdr->pb_ed)
|
|
== mac_rf_rx_pb_end_get_pb_crc(&tmp_rf_hdr->pb_ed)) {
|
|
/* dup pb received */
|
|
/* free the old pb buf */
|
|
iot_pkt_free(tmp->pb_buf);
|
|
tmp->pb_buf = NULL;
|
|
dup = 1;
|
|
} else {
|
|
/* we should flush, as the new pb arrived */
|
|
reorder_buf_flush(msdu);
|
|
}
|
|
#else
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)stream, sizeof(*stream));
|
|
#endif
|
|
}
|
|
}
|
|
/* update the current pb */
|
|
tmp->msdu_end = msdu_end;
|
|
tmp->msdu_start = msdu_start;
|
|
tmp->pb_buf = pb_buf;
|
|
|
|
break;
|
|
}
|
|
else {
|
|
if (tmp->ssn != INV_PB_SSN) {
|
|
/* check the tmp's ssn, it should be seq */
|
|
IOT_ASSERT(tmp->ssn == i);
|
|
}
|
|
else {
|
|
/* if tmp's ssn is not inited, init it here */
|
|
tmp->ssn = i;
|
|
}
|
|
}
|
|
|
|
if (i != ssn && !tmp_next) {
|
|
/* allocate a new pb_list if not reach end
|
|
* but pb_list not enough
|
|
*/
|
|
ret = mac_desc_get(&g_mac_desc_eng,
|
|
PLC_RX_PB_DESC_POOL, (void **)&pb);
|
|
if (ret) {
|
|
/* TODO: clean process? */
|
|
IOT_ASSERT_DUMP(0, &ssn, 1);
|
|
return ERR_NOMEM;
|
|
}
|
|
msdu->pb_alloc_cnt++;
|
|
/* init the new pb_buf_list */
|
|
pb_buf_list_init(pb, 0, 0, i + 1, NULL);
|
|
tmp->next = pb;
|
|
tmp_next = pb;
|
|
}
|
|
}
|
|
|
|
if (!dup) {
|
|
msdu->pb_rdy_cnt++;
|
|
if (msdu->pb_rdy_cnt > msdu->pb_alloc_cnt) {
|
|
iot_printf("pb rdy %d > pb alloc %d\n", msdu->pb_rdy_cnt,
|
|
msdu->pb_alloc_cnt);
|
|
IOT_ASSERT(0);
|
|
}
|
|
msdu->pbsz = pbsz;
|
|
}
|
|
|
|
if (msdu->pb_rdy_cnt > msdu->pb_total_cnt) {
|
|
#if ENABLE_PER_PB_RETRY
|
|
/* per pb retry should not get more pb */
|
|
iot_printf("pb_rdy_cnt:%d > pb_total_cnt:%d\n", \
|
|
msdu->pb_rdy_cnt, msdu->pb_total_cnt);
|
|
#if ENA_ALWAYS_SET_RETRY_BIT == 0
|
|
#if CPLC_IOT_CERT_SUPPORT
|
|
if (!mac_get_cert_test_flag())
|
|
#endif
|
|
{
|
|
iot_dbglog_input(PLC_MAC_REORDER_MID, DBGLOG_ERR,
|
|
IOT_MAC_PB_CNT_ID, 3, \
|
|
msdu->pb_rdy_cnt, msdu->pb_total_cnt, msdu->pb_alloc_cnt);
|
|
#if SUPPORT_SOUTHERN_POWER_GRID
|
|
reorder_msdu_dbg_t msdu_dbg[4];
|
|
for (i = 0, tmp = &msdu->pb_list; (i < 4) && tmp;
|
|
i++, tmp = tmp->next) {
|
|
msdu_dbg[i].ssn = tmp->ssn;
|
|
msdu_dbg[i].msdu_end = tmp->msdu_end;
|
|
msdu_dbg[i].msdu_start = tmp->msdu_start;
|
|
msdu_dbg[i].resv0 = 0;
|
|
os_mem_cpy(msdu_dbg[i].desc, iot_pkt_data(tmp->pb_buf), 64);
|
|
}
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)msdu_dbg, (i * \
|
|
sizeof(reorder_msdu_dbg_t)) / sizeof(uint32_t));
|
|
#else //SUPPORT_SOUTHERN_POWER_GRID
|
|
/* remove assert. HW BUGID:757
|
|
* 1. first/second pb not receive in msdu0(>=3pb. eg: pb = 3),
|
|
* before receive this msdu1(=2pb).
|
|
* and maybe hw pbbuf overlap, so pb_total_cnt not assigned.
|
|
* eg: msdu0 3pb. just 3rd(ssn = 2) rx successed.
|
|
* pb_rdy_cnt = 1. pb_total_cnt = INV_PB_TOTAL_CNT.
|
|
* 2. first receive msdu1, just received 2nd pb.
|
|
* but not received 1st pb, so go to msdu rx null pb(line260),
|
|
* and return, not post to uplayer.
|
|
* and msdu rx null pb(line260),not clear pb_rdy_cnt/pb_total_cnt.
|
|
* eg: msdu1 2pb. just 2nd(ssn = 1) rx successed.
|
|
* pb_rdy_cnt = 2. pb_total_cnt = 2.
|
|
* 3. secend/more time receive msdu1, receive first pb.
|
|
* crash here.
|
|
* eg: msdu1 2pb. 1st(ssn = 0) rx successed.
|
|
* pb_rdy_cnt = 3. pb_total_cnt = 2.
|
|
* so remove assert, make pb_rdy_cnt=pb_total_cnt(line670),
|
|
* and post to uplayer. if 2/3 step not same msdu,
|
|
* msdu crc can check out and free.
|
|
*/
|
|
#if !WAR_BUGID757_EN
|
|
IOT_ASSERT(0);
|
|
#endif
|
|
#endif
|
|
}
|
|
#endif //ENA_ALWAYS_SET_RETRY_BIT == 0
|
|
#endif //ENABLE_PER_PB_RETRY
|
|
msdu->pb_rdy_cnt = msdu->pb_total_cnt;
|
|
}
|
|
#if PLC_MAC_RX_DEBUG_LOG
|
|
iot_printf("pbcnt:%d/%d\n", msdu->pb_rdy_cnt, msdu->pb_total_cnt);
|
|
#endif
|
|
if (msdu->pb_rdy_cnt == msdu->pb_total_cnt) {
|
|
reorder_buf_release(msdu);
|
|
}
|
|
return ERR_OK;
|
|
}
|