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

1725 lines
69 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 "mac_rx_hw.h"
#include "mac_pdev.h"
#include "mpdu_frame.h"
#include "iot_errno.h"
#include "iot_pkt.h"
#include "iot_io.h"
#include "iot_system.h"
#include "plc_protocol.h"
#include "hw_tonemap.h"
#include "mac_vdev.h"
#include "mac_stream.h"
#include "mac_peer.h"
#include "mac_isr.h"
#include "mac_sched_hw.h"
#include "plc_const.h"
#include "phy_chn.h"
#include "phy_phase.h"
#include "mpdu_header.h"
#include "mac_rx_reg.h"
#include "mac_msg.h" /* for msg send */
#include "mac.h" /* for msg id */
#include "plc_mpdu_header.h" /* for frame_control_t */
#include "mac_sched.h"
#include "mac_cert_test.h"
#include "mac_rawdata_hw.h"
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#include "iot_plc_led.h"
#include "mac_ppm_scan.h"
#include "chip_reg_base.h"
#include "mac_reset.h"
#include "iot_system_api.h"
#include "mac_crc.h"
#include "mac_channel.h"
#include "hw_war.h"
#include "mac_hplc_ext.h"
#include "mac_hplc_ext_api.h"
#include "mac_check_spur_sta.h"
#if MAC_TIMESTAMPING
#include "mac_sys_reg.h"
#include "hw_reg_api.h"
#endif
#include "multi_nid_sync.h"
#include "phy_multi_ppm.h"
#include "mac_cmn_hw.h"
#include "iot_oem_api.h"
static bool_t mac_rx_check_pb_st_ssn_valid(uint32_t proto, uint32_t pbsz,
uint32_t pb_num, rx_pb_start *pb_st)
{
bool_t is_valid = true;
uint32_t msdu_pl_max;
switch (proto) {
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
msdu_pl_max = (PB_SIZE_520 - SG_SOF_PB_HDR_CRC_LEN) \
* PLC_SG_MAX_PB_NUM;
if ((((pbsz - SG_SOF_PB_HDR_CRC_LEN) * pb_st->ssn) > msdu_pl_max)
|| (pb_st->msdu_start && (pb_st->ssn != 0))
|| (!pb_st->msdu_start && (pb_st->ssn == 0))) {
is_valid = false;
}
break;
#endif
#if SUPPORT_SOUTHERN_POWER_GRID
case PLC_PROTO_TYPE_SPG:
/* for spg, msdu_start & msdu_end invalid */
if (pb_st->ssn >= min(PLC_SPG_MAX_PB_NUM, pb_num)){
is_valid = false;
}
break;
#endif
#if SUPPORT_GREEN_PHY
//add code
#endif
default:
(void)msdu_pl_max;
(void)pbsz;
(void)pb_num;
(void)pb_st;
break;
}
return is_valid;
}
/* return. 0 - check fc crc ok, 1 - check fc crc error */
static uint8_t mac_rx_check_fccs(rx_attention *att, rx_mpdu_start *mpdu_st)
{
uint8_t is_fccs_err = 0;
#if ENA_SW_FCCRC_CHECK
rx_fc_msg_t rx_fc = {0};
mac_get_rx_frm_msg_from_fc(mac_rx_mpdu_st_get_rx_proto(mpdu_st),
mac_rx_mpdu_st_get_fc_addr(mpdu_st), &rx_fc);
uint32_t sw_crc = mac_crc_get_fc_swcrc(mac_rx_mpdu_st_get_rx_proto(mpdu_st),
mac_rx_mpdu_st_get_fc_addr(mpdu_st));
if (sw_crc != rx_fc.fccs) {
is_fccs_err = 1;
}
if (!!mac_rx_att_get_is_fcserr(att) ^ !!is_fccs_err) {
mac_add_rx_fc_err_no_match_cnt();
iot_printf("fccs:hw-%d-0x%08x, sw-%d-0x%08x\n",
mac_rx_att_get_is_fcserr(att), rx_fc.fccs,
is_fccs_err, sw_crc);
}
#else
(void)mpdu_st;
#endif
if (mac_rx_att_get_is_fcserr(att) || is_fccs_err) {
mac_add_rx_fc_err_cnt();
is_fccs_err = 1;
}
return is_fccs_err;
}
uint32_t mac_filter_bcn_by_band(uint32_t proto, uint32_t proto_band_id)
{
/* spg not care detect beacon */
if (PLC_PROTO_TYPE_SPG == proto \
&& proto_band_id != phy_proto_single_band_id_get()) {
return ERR_INVAL;
}
return ERR_OK;
}
static uint32_t mac_get_org_dtei(uint32_t proto,
rx_pb_start *pb_st, rx_pb_end *pb_ed, uint8_t *data)
{
uint32_t org_dtei = PLC_TEI_INVAL;
if (pb_st->first_pb && pb_st->last_pb &&
pb_ed->rx_pb_crc_err == 0) {
if (proto == PLC_PROTO_TYPE_SG) {
mac_header_t *mac_hd_sg = (mac_header_t *)(data);
org_dtei = mac_hd_sg->org_dest_tei;
} else if (proto == PLC_PROTO_TYPE_SPG) {
spg_mac_header_t *mac_hd_spg = (spg_mac_header_t *)(data);
org_dtei = mac_hd_spg->org_dest_tei;
} else {
/* reserve for future */
}
}
return org_dtei;
}
static uint32_t mac_judge_is_not_self_pkt(uint32_t proto,
mac_vdev_t *vdev, rx_pb_start *pb_st,
rx_pb_end *pb_ed, uint8_t *data)
{
/* if the dtei in the mac header is myself,
* mac layer need to send the packet to CVG,
* and only just 1pb packet need to do this.
*/
uint8_t do_not_upload = 1;
uint8_t cert_mode = mac_get_cert_test_mode();
if (!cert_mode) {
uint32_t org_dtei = mac_get_org_dtei(proto, pb_st, pb_ed, data);
if (org_dtei != PLC_TEI_INVAL &&
org_dtei == vdev_get_tei(vdev)) {
do_not_upload = 0;
}
}
return do_not_upload;
}
#if (MAC_RX_CHK_VALID_I1901)
/* return 0 - this packet invalid, 1 - this packet valid*/
static uint8_t mac_rx_check_data_i1901(rx_attention *att,
rx_mpdu_start *mpdu_st, rx_pb_end *pb_ed, uint32_t buf_size)
{
uint8_t is_valid;
i1901_frame_control_t *fc_1901;
uint8_t tmi = 0, tmi_ext = 0, pb_num = 0;
uint16_t stei = 0, dtei = 0;
(void)att;
(void)pb_ed;
(void)buf_size;
fc_1901 = (i1901_frame_control_t *)mac_rx_mpdu_st_get_fc_addr(mpdu_st);
switch (fc_1901->delimiter_type) {
case FC_DELIM_BEACON:
tmi = fc_1901->vf.bcn.tmi;
tmi_ext = 0;
stei = fc_1901->vf.bcn.stei;
break;
case FC_DELIM_SOF:
tmi = fc_1901->vf.sof.tmi;
tmi_ext = fc_1901->vf.sof.tmi_ext;
pb_num = fc_1901->vf.sof.pb_num;
stei = fc_1901->vf.sof.stei;
dtei = fc_1901->vf.sof.dtei;
break;
case FC_DELIM_SACK:
pb_num = fc_1901->vf.sack.rx_pb;
stei = fc_1901->vf.sack.stei;
dtei = fc_1901->vf.sack.dtei;
break;
case I1901_RTS_CTS:
stei = fc_1901->vf.rts_cts.stei;
dtei = fc_1901->vf.rts_cts.dtei;
break;
case FC_DELIM_NNCCO:
break;
default:
return 0;
}
is_valid = 0;
do {
if (tmi_ext) {
if (tmi >= I1901_EXT_TMI_MAX) {
break;
}
} else {
if (tmi >= I1901_TMI_MAX) {
break;
}
}
if (pb_num > PLC_I1901_MAX_PB_NUM) {
break;
}
if ((PLC_TEI_BCAST != stei) && (PLC_TEI_CTRL != stei)
&& (PLC_TEI_CTRL_GW != stei) && (stei > PLC_TEI_MAX_NUM)) {
break;
}
if ((PLC_TEI_BCAST != dtei) && (PLC_TEI_CTRL != dtei)
&& (PLC_TEI_CTRL_GW != dtei) && (dtei > PLC_TEI_MAX_NUM)) {
break;
}
is_valid = 1;
} while (0);
return is_valid;
}
#else /* MAC_RX_CHK_VALID_I1901 */
#define mac_rx_check_data_i1901(att, mpdu_st, pb_ed, buf_size) (1)
#endif /* MAC_RX_CHK_VALID_I1901 */
#if SUPPORT_SOUTHERN_POWER_GRID
const uint8_t g_spg_gx_swich_band_pl[] = {
0x03, 0x00, 0x13, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x02, 0x21, 0x43, 0x00, 0x01, 0x11, 0x01,
0x01, 0x00, 0x02, 0x40, 0xF0, 0x01, 0x34, 0x12,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38,
0x8B, 0xB9, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
};
const uint32_t g_spg_gx_swich_band_crc = 0xC547CD;
const uint8_t g_spg_guizhou_assoc_ind_pl[] = {
0x02, 0x00, 0x3C, 0x00, 0xFF, 0x1F, 0x00, 0x06,
0x11, 0x12, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x19, 0x21,
0x68, 0x00, 0x00, 0x01, 0x00, 0x81, 0x00, 0x00,
0xE1, 0x88, 0x01, 0x3A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x19, 0x21, 0x68, 0x00, 0x00, 0x01,
0x01, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x19, 0x21, 0x68, 0x00,
0x09, 0x04, 0x05, 0x00, 0x96, 0x44, 0x56, 0x3E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
};
const uint32_t g_spg_guizhou_assoc_ind_crc = 0x218E56;
#endif
#define MAC_WAR_RX_ABORT_SPG_WAR_MAX 5
static uint8_t mac_rx_abort_packet_check(rx_fc_msg_t *rx_fc,
rx_mpdu_end *mpdu_end, rx_pb_start *pb_start, rx_pb_end *pb_end,
uint8_t *payload)
{
uint8_t is_free_pkt = 1;
if (4 == mac_rx_mpdu_end_get_rx_abnormal_id(mpdu_end)) {
if (rx_fc->delimiter == FC_DELIM_BEACON) {
pb_end->rx_pb_crc_err = 1;
/* not free beacon pkt for rx abort reason4 */
is_free_pkt = 0;
} else if (rx_fc->delimiter == FC_DELIM_SOF) {
#if SUPPORT_SOUTHERN_POWER_GRID
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
mac_vdev_t *vdev = get_vdev_ptr(PLC_PDEV_ID, PLC_DEFAULT_VDEV);
uint32_t user_type = iot_oem_get_user_type();
if (pdev->rx_abort_spg_war_cnt <= MAC_WAR_RX_ABORT_SPG_WAR_MAX) {
pdev->rx_abort_spg_war_cnt++;
}
/* cco */
if (mac_vdev_cfg_get_node_role(vdev) == PLC_DEV_ROLE_CCO) {
if (USER_TYPE_SOUTHEN_POWER_GRID_GX_NW21 == user_type) {
if ((pdev->rx_abort_spg_war_cnt
== MAC_WAR_RX_ABORT_SPG_WAR_MAX)
&& (rx_fc->nid == 0x0) && (rx_fc->src_tei == 0)
&& (rx_fc->dst_tei == 1) && (rx_fc->tmi == 4)
&& (rx_fc->numsym == 0x26)) {
mpdu_end->rx_abnormal_id = 0;
pb_start->first_pb = 1;
pb_start->last_pb = 1;
pb_start->msdu_start = 1;
pb_start->msdu_end = 1;
pb_start->ssn = 0;
pb_end->rx_pb_crc_err = 0;
mac_rx_pb_end_set_pb_crc(pb_end,
g_spg_gx_swich_band_crc);
os_mem_cpy(payload, g_spg_gx_swich_band_pl,
sizeof(g_spg_gx_swich_band_pl));
is_free_pkt = 0;
}
}
} else {
/* sta */
if (USER_TYPE_SOUTHEN_POWER_GRID_GUIZHOU == user_type) {
if ((pdev->rx_abort_spg_war_cnt <= 1)
&& (rx_fc->nid == 0x6) && (rx_fc->src_tei == 1)
&& (rx_fc->dst_tei == 0xFFF) && (rx_fc->tmi == 0)
&& (rx_fc->numsym == 121)) {
mpdu_end->rx_abnormal_id = 0;
pb_start->first_pb = 1;
pb_start->last_pb = 1;
pb_start->msdu_start = 1;
pb_start->msdu_end = 1;
pb_start->ssn = 0;
pb_end->rx_pb_crc_err = 0;
mac_rx_pb_end_set_pb_crc(pb_end,
g_spg_guizhou_assoc_ind_crc);
os_mem_cpy(payload, g_spg_guizhou_assoc_ind_pl,
sizeof(g_spg_guizhou_assoc_ind_pl));
is_free_pkt = 0;
}
}
}
#endif
}
}
return is_free_pkt;
}
uint32_t g_no_pb_done = 0;
uint32_t mac_rx_hw_mpdu_internal(void *pdev_in, uint32_t ring_id,
uint32_t quota_ms)
{
mac_pdev_t *pdev = (mac_pdev_t*)pdev_in;
iot_pkt_t *iot_pkt_array[1] = { 0 };
rx_attention *att;
rx_mpdu_start *mpdu_st;
rx_mpdu_end *mpdu_ed;
rx_pb_start *pb_st;
rx_pb_end *pb_ed;
uint32_t is_retry_mpdu = 0;
uint32_t ret;
mac_vdev_t *vdev;
mac_peer_t *peer = NULL;
mac_stream_t *stream = NULL;
rx_buf_ring_t *ring;
int32_t delta_ntb;
uint8_t *payload;
uint32_t nid = 0;
uint32_t proto = 0;
int8_t snr = INVALID_SNR;
uint32_t is_overflow;
uint32_t delimiter_type = 0xFFFFFFFF;
uint32_t proto_band_id;
uint8_t rx_phase;
rx_fc_msg_t rx_fc_msg = { 0 };
uint8_t is_vdev_found;
uint8_t is_not_my_ucast;
uint32_t pbsz = 0;
int8_t raw_snr = INVALID_SNR;
uint8_t rssi = INV_RSSI;
uint8_t node_role;
#if HW_PLATFORM == HW_PLATFORM_SIMU
ring = &pdev->simu.rx_ring[ring_id];
#else
ring = &pdev->ring_hdl.ring[ring_id];
#endif
mac_pdev_t *pdev_t = g_mac_pdev[PLC_PDEV_ID];
#if MAC_TIMESTAMPING
/* mac rx ntb in dsr */
pdev->mac_rx_ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
#endif
#if ((HW_PLATFORM > HW_PLATFORM_SIMU) && PLC_SUPPORT_STA_ROLE && IOT_MP_SUPPORT)
BUILD_BUG_ON(ENA_SYNC_DIFF_CCO_PPM);
#endif
uint32_t cur_ts = os_boot_time32();
do {
if (pop_buf_from_ring(ring, 1, iot_pkt_array))
{
if (pdev->vdev[PLC_DEFAULT_VDEV]->stop_flag ||
pdev->vdev[PLC_DEFAULT_VDEV]->tx_rx_suspend) {
goto free_pkt;
}
mac_add_rx_pb_cnt();
/* if pop something out */
uint8_t *tmp =
iot_pkt_block_ptr(iot_pkt_array[0], IOT_PKT_BLOCK_DATA);
if(iot_pkt_validation(iot_pkt_array[0]))
{
uint32_t *p = (uint32_t *) (((uint8_t *) iot_pkt_array[0])
- ring->buf_sz - 16);
(void)p;
mem_dump(p, (ring->buf_sz >> 1) + 4);
IOT_ASSERT_DUMP(0, p, (ring->buf_sz >> 1) + 4);
goto free_pkt;
}
#if WAR_MPDU_NOT_DONE
if (ring->not_done) {
/* if not done due to HW overflow or overwrite issue,
* just skip some pkt
*/
ring->not_done--;
ring->overflow = 1;
mem_dump((uint32_t *)iot_pkt_array[0], 20);
goto free_pkt;
}
#endif
att = (rx_attention*)(tmp + RX_ATTENTION_OFFSET);
mpdu_st = (rx_mpdu_start *)(tmp + MPDU_START_OFFSET);
mpdu_ed = (rx_mpdu_end *)(tmp + MPDU_END_OFFSET);
pb_st = (rx_pb_start *)(tmp + PB_START_OFFSET);
pb_ed = (rx_pb_end *)(tmp + PB_END_OFFSET);
payload = tmp + PB_PAYLOAD_OFFSET;
(void)payload;
#if MAC_TIMESTAMPING
/* record rx timestamp */
pdev_t->mac_rx_timestamp = \
mac_rx_mpdu_end_get_local_timestamp(mpdu_ed);
#endif
//log for ring id and delimiter type
mac_rx_debug_log_ringid_and_detype(mpdu_st);
//log for info
mac_rx_debug_log_info(iot_pkt_array[0]);
/* if this pb done */
if (pb_ed->rx_pb_done) {
/* check rx phy err */
mac_rx_debug_log_check_phy_err(pb_st, mpdu_ed);
/* check rx protocol */
#if (SUPPORT_SOUTHERN_POWER_GRID && (HW_PLATFORM >= HW_PLATFORM_FPGA))
proto = mac_rx_mpdu_st_get_rx_proto(mpdu_st);
if (PLC_PROTO_TYPE_SPG != proto) {
iot_printf("mac_rx_proto:hw-%d,phy-%d\n", \
proto, PHY_PROTO_TYPE_GET());
mac_add_rx_proto_nomatch_cnt();
goto free_pkt;
}
#endif
/* handle rx abort */
if((mac_rx_pb_st_get_last_pb(pb_st) \
&& mac_rx_mpdu_end_get_rx_abort(mpdu_ed)) || \
(mac_rx_pb_st_get_first_pb(pb_st) \
&& mac_rx_att_get_rx_abort(att)))
{
#if (SUPPORT_SOUTHERN_POWER_GRID && (HW_PLATFORM >= HW_PLATFORM_FPGA))
if (pdev->rx_abort_rst_cnt < 10) {
/* disable mac raw data mode */
mac_rawdata_mode_enable(0);
/* clear pb size BB */
phy_rawdata_mode_bb_set_ps_tr(0, 0, 0);
pdev->rx_abort_rst_cnt++;
}
#endif
#if DBG_RX_ABORT_REASON_4 == 1
if (++pdev->cont_rx_abort4_cnt > 20) {
/* rx abort continues */
iot_printf("rx abort stuck!\n");
/* TODO: call dump and reset phy here */
#if DBG_HW_DUMP == 1
mac_dump_buf((uint32_t *)att,
sizeof(rx_buf_hdr_t)/sizeof(uint32_t),
(uint32_t *)RGF_RX_BASEADDR, 128, NULL, 0, true);
#else
#if IOT_MP_SUPPORT
mac_pdev_send_reset_war_msg(pdev, CONT_RX_ABORT4);
#endif
pdev->cont_rx_abort4_cnt = 0;
#endif
}
#endif
//log for rx abort
mac_rx_debug_log_rxabort(iot_pkt_array[0]);
mac_add_rx_abort_cnt();
if (pb_st->last_pb) {
ring->cur_mpdu = NULL;
} else if (pb_st->first_pb) {
/* if multi pb and first pb's rx abort
* we need to save the buf's mpdu_st desc
* or else the rest print info is not reliable
*/
goto save_mpdu_st_and_free;
}
#if (SIMU_DBG == 1)
iot_printf("simu_dbg, mac drop package, rx abort\n");
#endif
proto = mac_rx_mpdu_st_get_rx_proto(mpdu_st);
mac_get_rx_frm_msg_from_fc(proto,
mac_rx_mpdu_st_get_fc_addr(mpdu_st), &rx_fc_msg);
if (mac_rx_abort_packet_check(&rx_fc_msg, mpdu_ed, pb_st,
pb_ed, payload)) {
goto free_pkt;
}
}
/* handle overflow */
if((mac_rx_pb_st_get_last_pb(pb_st) \
&& mac_rx_mpdu_end_get_is_overflow(mpdu_ed)) || \
(mac_rx_pb_st_get_first_pb(pb_st) \
&& mac_rx_att_get_is_overflow(att)))
{
/* handle pb payload overflow */
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1)
iot_printf("rx pb overflow:att@0x%x\n", att);
#endif
if (pb_st->last_pb) {
ring->cur_mpdu = NULL;
}
goto free_pkt;
}
//half_mpdu_check:
/* handle desc overflow */
is_overflow = ring->overflow | \
(rx_ring_get_overflow_status() & (0x1 << ring_id));
if (pb_st->first_pb) {
/* for first pb */
if (!mac_rx_att_get_rx_mpdu_done(att)) {
//add mpdu not done cnt
mac_add_rx_att_not_done_cnt();
/* should not happen, mpdu_done should
* always be valid when first pb
*/
iot_printf("mpdu_done not set correctly," \
" att@0x%x\n", att);
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
IOT_ASSERT(0);
#endif
if (!pb_st->last_pb) {
/* if multi pb and first pb's freed
* we need to save the buf's mpdu_st desc
* or else the rest print info is not reliable
*/
goto save_mpdu_st_and_free;
}
goto free_pkt;
}
if (mac_rx_check_fccs(att, mpdu_st)) {
if (!pb_st->last_pb) {
/* if multi pb and first pb's freed
* we need to save the buf's mpdu_st desc
* or else the rest print info is not reliable
*/
goto save_mpdu_st_and_free;
}
goto free_pkt;
}
if (!is_overflow) {
if (ring->cur_mpdu != NULL && !pb_st->last_pb) {
/* if not overflow, should not happen */
/* for first pb, record the mpdu start
* only the first pb's mpdu start is valid
*/
mac_add_rx_half_pkt_cnt();
iot_printf("last pb not seen. half_pkt_cnt = %d\n",\
mac_get_rx_half_pkt_cnt());
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
IOT_ASSERT(ring->cur_mpdu == NULL);
#endif
}
}
else {
/* overflow happen */
if (ring->cur_mpdu) {
/* if first pb but cur_mpdu is not null,
* this may result half mpdu received.
* do nothing, just restart recording
* and continue
* the mpdu record
*/
}
}
/* record the first pb */
/* correct the snr for the upper layer */
raw_snr = mac_rx_mpdu_st_get_avg_snr(mpdu_st);
mac_rx_mpdu_st_set_avg_snr(mpdu_st,
phy_rx_snr_cal(
mac_rx_mpdu_st_get_phy_info_addr(mpdu_st),
mac_rx_mpdu_st_get_rx_phase(mpdu_st)));
os_mem_cpy(&ring->saved_mpdu_st, mpdu_st,
sizeof(ring->saved_mpdu_st));
ring->cur_mpdu = &ring->saved_mpdu_st;
}
else {
/* if not first pb */
if (!is_overflow) {
if (ring->cur_mpdu == NULL) {
/* if not overflow, should not happen */
/* if not first pb and ring->cur_mpdu == null
* this means not a full mpdu received
* when enter dsr. it usually
* should not happen
*/
mac_add_rx_half_pkt_cnt();
iot_printf("first pb not seen, drop the pb, cnt:%d.\n",\
mac_get_rx_half_pkt_cnt());
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
IOT_ASSERT(0);
#endif
goto free_pkt;
}
}
else {
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1)
iot_printf("rx overflow:reason-%d\n", \
mpdu_ed->rx_abnormal_id);
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO_LVL_2,
IOT_MAC_RX_OVERFLOW_ID, 1,\
mpdu_ed->rx_abnormal_id);
#endif
mac_add_rx_overflow_cnt();
/* if overflow, and latter half mpdu received.
* drop the pbs till receive a first pb
*/
/* set fcs err */
mac_rx_att_set_is_fcserr(att, 1);
/* free the error pb */
#if (SIMU_DBG == 1)
iot_printf("simu_dbg, mac drop package, is_overflow\n");
#endif
goto free_pkt;
}
mpdu_st = ring->cur_mpdu;
IOT_ASSERT(mpdu_st);
}
if (0 == mac_rx_check_data_i1901(att, mpdu_st, pb_ed,
ring->buf_sz)) {
mac_add_rx_fc_invalid_cnt();
goto free_pkt;
}
mac_fc_i1901_to_sg(mac_rx_mpdu_st_get_rx_proto(mpdu_st),
mac_rx_mpdu_st_get_fc_addr(mpdu_st));
//log for fc
mac_rx_debug_log_fc(mpdu_st);
/* sta spur check */
/* sta restart timer */
uint32_t *fc_spur = \
(uint32_t*)mac_rx_mpdu_st_get_fc_addr(mpdu_st);
uint32_t is_local_nw_pkt =
(mac_get_nid_from_fc(proto, (void *)fc_spur) ==
mac_get_hw_nid());
/* pb ok and fc valid */
if (pb_ed->rx_pb_crc_err == 0 &&
mac_rx_hw_check_fc_valid(fc_spur)) {
/* sta check spur restart */
mac_sta_check_spur_timer_restart( \
&pdev_t->mac_check_spur_ctxt, is_local_nw_pkt);
}
//process_pb:
/*
* process the pb if ring pb callback exist
*/
if (pdev->ring_hdl.mpdu_pb_cb) {
ret = pdev->ring_hdl.mpdu_pb_cb(pdev, \
iot_pkt_array[0]);
if(CON_PKT_NOT_FREE == ret) //cert mode loopback
{
if (pb_st->last_pb) {
ring->cur_mpdu = NULL;
}
continue;
}
else if(CON_PKT_FREE == ret) //cert mode other test case
{
if (pb_st->first_pb && !pb_st->last_pb) {
/* if multi pb and first pb's freed
* we need to save the buf's mpdu_st desc
* or else the rest print info is not reliable
*/
goto save_mpdu_st_and_free;
}
goto free_pkt;
} else if (CON_PKT_NOT_CARE == ret) {
/* continue rx path */
}
}
/* get cert mode */
uint8_t cert_mode = mac_get_cert_test_mode();
if (pb_st->first_pb || ring->cur_mpdu) {
/* get info only first pb, used across mpdu */
/* get proto, deli, nid */
proto = mpdu_st->rx_proto;
delimiter_type = \
mac_get_rx_delimiter_from_fc(proto, \
mac_rx_mpdu_st_get_fc_addr(mpdu_st));
/* get rx fc message */
mac_get_rx_frm_msg_from_fc(proto, \
mac_rx_mpdu_st_get_fc_addr(mpdu_st), &rx_fc_msg);
nid = mac_get_nid_from_fc(proto, \
mac_rx_mpdu_st_get_fc_addr(mpdu_st));
#if (ENA_RX_DIFF_NID_BCAST)
mac_vdev_t *dft_vdev = find_vdev_by_nid(pdev->pdev_id, nid);
if ((FC_DELIM_SOF == delimiter_type)
&& (PLC_TEI_BCAST == rx_fc_msg.dst_tei)
&& !cert_mode) {
/* if bcast then force nid = local nid to rx in the
* same vdev.
*/
if (NULL == dft_vdev) {
//TODO: maybe use reduced vdev
dft_vdev = pdev->vdev[PLC_DEFAULT_VDEV];
}
vdev_get_nid(dft_vdev, &nid);
}
#endif
ret = phy_get_pb_size(proto, rx_fc_msg.tmi,
rx_fc_msg.tmi_ext, &pbsz);
if (ret!= ERR_OK) {
/* err handle */
iot_printf("pbsz get failed:tmi=%d,etmi=%d\n",
rx_fc_msg.tmi, rx_fc_msg.tmi_ext);
goto free_pkt;
}
} else {
/* no saved mpdu FC info, should
* not happen
*/
IOT_ASSERT_DUMP(0, (uint32_t * )att, 17);
goto free_pkt;
}
if (pb_st->last_pb) {
/* LED hook */
mac_rx_led_control(mpdu_st);
if (cert_mode && mac_cert_is_nid_valid(nid)) {
mac_check_spur_en(&pdev_t->mac_check_spur_ctxt, 0);
/* PHY channel estimation */
phy_info_check_entry(mpdu_st,
mac_rx_mpdu_st_get_fc_addr(mpdu_st), 0,
cert_mode);
}
/* last pb, clr the cur_mpdu */
ring->cur_mpdu = NULL;
mac_add_rx_mpdu_cnt();
}
/* find the vdev info, if no matching nid and
* not assoc yet,
* return the first vdev that nid = 0
*/
vdev = find_vdev_by_nid(pdev->pdev_id, nid);
peer = NULL;
stream = NULL;
is_vdev_found = 0;
is_not_my_ucast = 0;
if (pb_st->last_pb && vdev) {
/* save the rx time stamp */
vdev->last_rx_ntb = \
mac_rx_mpdu_end_get_ntb_timestamp(mpdu_ed);
}
proto_band_id = phy_hw_band_to_proto_band(mpdu_st->rx_band_sel);
mac_scan_update_rx_status(&pdev->scan, &rx_fc_msg,
(uint8_t)proto_band_id);
switch (delimiter_type)
{
case FC_DELIM_SOF:
{
#if (PLC_MAC_RX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_2)
iot_printf("ssn = %d, msdu_start = %d, msdu_end = %d\n", \
pb_st->ssn, pb_st->msdu_start, pb_st->msdu_end);
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO_LVL_2,
IOT_MAC_RX_PB_HEADER_ID, 3,\
pb_st->ssn, pb_st->msdu_start, pb_st->msdu_end);
mem_dump((uint32_t *)att, 0x50);
#endif
if (!vdev) {
/* vdev not found, drop this SOF by
* force crc error
*/
pb_ed->rx_pb_crc_err = 1;
#if (SIMU_DBG == 1)
iot_printf("simu_dbg, mac drop package, vdev not found\n");
#endif
goto handle_sof;
}
else {
is_vdev_found = 1;
}
/* remove interference from other network packets */
if ((CERT_TEST_CMD_ENTER_MAC_T == cert_mode)
&& !mac_cert_is_nid_valid(nid)) {
pb_ed->rx_pb_crc_err = 1;
goto handle_sof;
}
/* fix spg msdu_start/msdu_end */
if (PLC_PROTO_TYPE_SPG == proto) {
/**
* sof msdu_start and msdu_end
* fields always 0 in SPG protocol
*/
if (0 == mac_rx_pb_st_get_ssn(pb_st)) {
mac_rx_pb_st_set_msdu_start(pb_st, 1);
}
/* spg must be used long mpdu tx */
if (mac_rx_pb_st_get_last_pb(pb_st) &&
(rx_fc_msg.pb_num == (mac_rx_pb_st_get_ssn(pb_st) + 1))) {
mac_rx_pb_st_set_msdu_end(pb_st, 1);
}
}
/* handle bcast */
if (rx_fc_msg.dst_tei != PLC_TEI_BCAST) {
/* for uni-cast.
* for SPG, when not assoc,
* the CCO might reply with dtei with future tei or 0,
* we need receive this kind of packet
*
*/
nid_t temp;
uint8_t unicast_check = 0;
if (rx_fc_msg.dst_tei != vdev_get_tei(vdev)) {
if (mac_vdev_cfg_get_node_role(vdev) ==
PLC_DEV_ROLE_CCO) {
if (vdev_get_nid(vdev, &temp) == ERR_OK) {
unicast_check = 1;
}
/* for cco, if the networking is not started
* (NID is not set), try to receive all unicast
* packets.
*/
} else {
unicast_check = (PLC_PROTO_TYPE_SPG == proto) ?
(vdev_get_tei(vdev) != 0) : 1;
}
if (unicast_check
&& mac_judge_is_not_self_pkt(proto, vdev, pb_st,
pb_ed, payload)) {
/* not directed for me
* drop right now
*/
pb_ed->rx_pb_crc_err = 1;
is_not_my_ucast = 1;
#if (SIMU_DBG == 1)
iot_printf("simu_dbg, mac drop package,"
"rx_fc_msg.dst_tei:%d, vdev_get_tei(vdev):%d\n",
rx_fc_msg.dst_tei, vdev_get_tei(vdev));
#endif
goto handle_sof;
}
}
/* receive a unicast */
mac_add_rx_unicast_cnt();
//log for sof uncast info
mac_rx_debug_log_sof_uicast_info(rx_fc_msg, \
mpdu_st, mpdu_ed, pb_st, raw_snr);
peer = find_peer(vdev, nid, \
(tei_t)rx_fc_msg.src_tei);
}
else {
/* for bcast */
mac_add_rx_broadcast_cnt();
peer = vdev->bcast_peer;
IOT_ASSERT(peer);
//log for sof bcast
mac_rx_debug_log_sof_bcast_info(rx_fc_msg,
mpdu_st, mpdu_ed, pb_st, raw_snr);
}
#if ENA_WAR_396_DEBUG
/* check if this pb valid, for some HW error
* case, pb crc correct but it's wrong */
if ((pb_ed->rx_pb_crc_err == 0)
&& !mac_rx_check_pb_st_ssn_valid(proto, pbsz,
rx_fc_msg.pb_num, pb_st)) {
/* error case */
static uint32_t g_wrong_pbcrc_cnt = 0;
uint32_t *p =
(uint32_t *) (((uint8_t *) iot_pkt_array[0])
- 16);
(void) p;
iot_printf("Wrong RX PBCRC result from HW, pbsz:%d, cnt:%d.\n",
pbsz, ++g_wrong_pbcrc_cnt);
/* check next pkt whether overwrite */
if (iot_pkt_check_end_overwrite(iot_pkt_array[0])) {
mem_dump(p, (ring->buf_sz >> 1) + 12);
IOT_ASSERT_DUMP(0, p, (ring->buf_sz >> 1) + 12);
}
pb_ed->rx_pb_crc_err = 1;
goto handle_sof;
}
#if ENA_SW_PBCRC_CHECK
if (pb_ed->rx_pb_crc_err == 0) {
uint32_t pb_head = \
mac_desc_get_pb_head_from_rx_pb_st(proto, pb_st);
uint32_t crc_cal;
crc_cal = mac_crc_get_pb_swcrc(proto, &pb_head, \
payload, pbsz, FC_DELIM_SOF);
if (crc_cal != mac_rx_pb_end_get_pb_crc(pb_ed)) {
pb_ed->rx_pb_crc_err = 1;
goto handle_sof;
}
}
#endif
#endif
/* find the peer and stream info */
if (!peer) {
/* if the peer is not exist,
* create it right now
*/
ret = mac_peer_alloc(vdev, \
(tei_t)rx_fc_msg.src_tei, \
0, 1, 0, 0, &peer);
if (ret) {
/* create peer failed */
IOT_ASSERT(0);
}
}
stream = find_stream(peer, nid,
(tei_t)rx_fc_msg.src_tei,
(lid_t)rx_fc_msg.lid, IS_RX_STREAM, IS_PLC_STREAM);
if (!stream) {
/* if stream is not found
* create it now
*/
ret = mac_stream_alloc(peer, IS_RX_STREAM,
(lid_t)rx_fc_msg.lid, IS_PLC_STREAM,
&stream);
if (ret != ERR_OK && ret != ERR_EXIST) {
/* create stream failed */
IOT_ASSERT(0);
}
}
#if MAC_STREAM_TIMEOUT_SUPPORT
//updata rate info last rx ntb
mac_peer_rx_ts_update(peer, cur_ts);
mac_vdev_sort_peer_list(vdev, peer);
#else
(void)cur_ts;
#endif
/* handle pb flag check */
if (pb_st->first_pb) {
is_retry_mpdu = \
rx_fc_msg.retry;
}
handle_sof:
#if MAC_RX_2PB_WAR
/* NOTE: war fo dingxin 2pb.
* 1. we can't take 2PB packets of Dingxin,
* only the first package can be received correctly.
* 2. if the first pb already contains all valid data,
* and the second pb just contains msdu crc.
* 3. we can dorp data of second pb,
* and make an MSDU CRC to fill the second PB.
* 4. so uplayer can see this package and handle.
*/
if (pb_ed->rx_pb_crc_err == 1 && is_not_my_ucast == 0 &&
is_vdev_found == 1 && rx_fc_msg.pb_num == 2 &&
pb_st->first_pb == 0 && pb_st->last_pb == 1) {
/* get the first pb */
reorder_msdu_buf_t *spg_msdu =
&stream->msdu.rx.reorder_buf;
pb_buf_list_t *spg_1st_pbuf = &spg_msdu->pb_list;
if (spg_1st_pbuf->pb_buf == NULL) {
/* first pb rx error */
goto spg_war_handle;
}
/* get pld of the first pb */
uint8_t *fst_pbbuf = iot_pkt_data(spg_1st_pbuf->pb_buf)
+ PB_PAYLOAD_OFFSET;
/* get mac header len */
spg_mac_header_t *spg_mac = (spg_mac_header_t *)fst_pbbuf;
uint32_t mac_hdr_len = 0;
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);
}
/* get msdu len in the first pb */
uint32_t pb_data_size = pbsz - mac_hdr_len -
mac_get_pb_hdr_resv_crc_len(FC_DELIM_SOF,
PLC_PROTO_TYPE_SPG);
#if (PLC_MAC_RX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_2)
iot_printf("dingxin war ssn:%d, msdu_st:%d, "
"msdu_ed:%d, hdr_type:%d, snid:%d, msdu_len:%d, "
"mac_hdr_len:%d, pb_valid_data:%d\n",
spg_1st_pbuf->ssn, spg_1st_pbuf->msdu_start,
spg_1st_pbuf->msdu_end, spg_mac->mac_hdr_type,
spg_mac->snid, spg_mac->msdu_len,
mac_hdr_len, pb_data_size);
#endif
/* if all msdu data in the first pb */
if (spg_mac->msdu_len <= pb_data_size) {
iot_printf("rx 2sec pb fail and war it for spg\n");
uint32_t msdu_rsv_crc =
pb_data_size - spg_mac->msdu_len;
/* calculate msdu crc */
uint8_t *msdu_valid_buf = fst_pbbuf + mac_hdr_len;
uint32_t msdu_crc = iot_getcrc32(msdu_valid_buf,
spg_mac->msdu_len);
if (msdu_rsv_crc < SPG_MAC_MSDU_CRC_LEN) {
/* 1.MSDU CRC at the beginning of next pb crc
* fill the crc to 2sec pb
* 2.one part of MSDU CRC is in the first Pb,
* and the other part of MSDU CRC is
* in the second PB
*/
uint8_t *msdu_crc_t = (uint8_t *)&msdu_crc;
/* fill the crc to 2sec pb */
os_mem_cpy(payload, msdu_crc_t + msdu_rsv_crc,
SPG_MAC_MSDU_CRC_LEN - msdu_rsv_crc);
} else {
/* the next pb has no valid data and no MSDU CRC */
}
/* modify desc */
pb_st->ssn = 1;
mac_rx_pb_st_set_msdu_end(pb_st, 1);
pb_ed->rx_pb_crc_err = 0;
}
}
spg_war_handle:
#endif
if (pb_ed->rx_pb_crc_err == 0) {
#if (PLC_MAC_RX_DEBUG_LOG > PLC_MAC_LOG_LEVEL_2)
iot_printf("%s, msdu->buf = %p", \
__FUNCTION__, iot_pkt_array[0]);
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO,
IOT_MAC_RX_BUF_ID, 1, iot_pkt_array[0]);
#endif
#if DEBUG_SPG_PER_MSDU_MPDU_RX
if ((PLC_PROTO_TYPE_SPG == proto) \
&& (mac_rx_pb_st_get_ssn(pb_st) != 0) \
&& (136 == pbsz)) {
IOT_ASSERT_DUMP(0, (uint32_t *)iot_pkt_block_ptr(\
iot_pkt_array[0], IOT_PKT_BLOCK_DATA), 16);
}
#endif
reorder_buf_insert(&stream->msdu.rx.reorder_buf, \
iot_pkt_array[0], \
mac_rx_pb_st_get_ssn(pb_st), \
mac_rx_pb_st_get_msdu_start(pb_st), \
mac_rx_pb_st_get_msdu_end(pb_st), \
is_retry_mpdu, \
pbsz
);
}
else {
int16_t ppm_err = PLC_MAX_MAC_NTB_PPM;
uint32_t rate_id = MAX_RATE_IDX;
(void)rate_id;
(void)ppm_err;
ppm_err = (int16_t)mac_multi_sync_get_ppm(pdev->pdev_id,
nid);
if (is_not_my_ucast == 0 && is_vdev_found == 1)
{
/*sof err cnt*/
mac_add_rx_sof_pb_err_cnt();
#if MAC_RID_PBNUM_FLASH_LOG
/*record sof err cnt by rid and pbnum*/
ret = phy_find_rid_by_tmi((uint8_t)proto,\
phy_proto_single_band_id_get(),\
&rate_id, rx_fc_msg.tmi, rx_fc_msg.tmi_ext);
if (ret == ERR_OK && rate_id != MAX_RATE_IDX) {
mac_add_sof_err_cnt(proto, rate_id, \
(uint8_t)mac_rx_mpdu_st_get_rx_pb_num(mpdu_st));
}
#endif
mem_dump((uint32_t *)mpdu_st, sizeof(*mpdu_st)>>2);
}
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1)
iot_printf("sof pb dropped:"\
"not_my_ucast = %d,"\
"vdev_found = %d,"
"rid = %d,"
#if MAC_RID_PBNUM_FLASH_LOG
"sof_err_cnt = %d, "
#endif
"sw_multi_ppm = %d, "
"ppm = %d, dtei = %d, stei = %d, nid = 0x%x\n",\
is_not_my_ucast,\
is_vdev_found,
rate_id,
#if MAC_RID_PBNUM_FLASH_LOG
mac_get_sof_err_cnt(proto, rate_id,\
(uint8_t)mac_rx_mpdu_st_get_rx_pb_num(mpdu_st)),
#endif
ppm_err,
mac_rx_mpdu_st_get_estimated_ppm(mpdu_st),
rx_fc_msg.dst_tei,
rx_fc_msg.src_tei,
rx_fc_msg.nid);
iot_dbglog_input(PLC_MAC_RX_HW_MID, \
DBGLOG_INFO_LVL_2, \
IOT_MAC_RX_SOF_DROP_ID, \
3, is_not_my_ucast, is_vdev_found,\
mac_rx_mpdu_st_get_estimated_ppm(mpdu_st) \
);
#endif
#if (SIMU_DBG == 1)
iot_printf("simu_dbg, mac drop package," \
" sof pb dropped\n");
#endif
if (pb_st->first_pb && !pb_st->last_pb) {
/* if multi pb and first pb's crc err
* we need to save the buf's mpdu_st desc
* or else the rest print info is not reliable
*/
goto save_mpdu_st_and_free;
}
/* NOTE: if rx pkt pb error,
* alloc peer and stream need free.
* especially, spg not joined net, it will receive unicast.
* if this pkt pb is error, allco peer/stream need free.
*/
if (vdev) {
if (vdev_get_tei(vdev) == 0 &&
rx_fc_msg.dst_tei != PLC_TEI_BCAST && peer) {
mac_peer_del_temp_peer(peer);
}
}
goto free_pkt;
}
break;
}
case FC_DELIM_BEACON:
{
uint32_t rate_mode = mac_rx_mpdu_st_get_rx_rate_mode(mpdu_st);
uint32_t local_ts = mac_rx_mpdu_end_get_local_timestamp(mpdu_ed);
uint8_t est_ppm = mac_rx_mpdu_st_get_estimated_ppm(mpdu_st);
uint32_t ntb_ts = mac_rx_mpdu_end_get_ntb_timestamp(mpdu_ed);
snr = mac_rx_mpdu_st_get_avg_snr(mpdu_st);
uint8_t is_chk_bcn_ppm = 1;
uint8_t is_self_nid = 0;
/* TODO: remove the next line later */
(void)ntb_ts;
//log for beacon info
mac_rx_debug_log_bcn_info(&rx_fc_msg, \
mpdu_st, mpdu_ed, pb_ed, raw_snr);
if (!vdev) {
/* force first vdev, and upload all bcn */
vdev = g_mac_pdev[PLC_PDEV_ID]->vdev[PLC_DEFAULT_VDEV];
if ((mac_vdev_cfg_get_node_role(vdev) \
== PLC_DEV_ROLE_INVALID)) {
/* only upload for valid role */
goto free_pkt;
}
}
node_role = mac_vdev_cfg_get_node_role(vdev);
{
uint32_t *fc = \
(uint32_t*)mac_rx_mpdu_st_get_fc_addr(mpdu_st);
if (!mac_rx_hw_check_fc_valid(fc)) {
/* HWWAR for all 0s FC */
pb_ed->rx_pb_crc_err = 1;
goto free_pkt;
}
}
ret = mac_filter_bcn_by_band(proto, proto_band_id);
if (ret != ERR_OK) {
iot_printf("rx bcn band:%d fliter!\n", proto_band_id);
goto free_pkt;
}
nid_t cur_my_nid = PLC_NID_INVALID;
vdev_get_nid(vdev, &cur_my_nid);
if (cert_mode == CERT_TEST_CMD_NOT_RX) {
/* if not cert mode, then we need age out
* the ppm data to support more CCOs
*/
mac_multi_sync_nid_timeout_clear(pdev->pdev_id);
}
/* my ppm is updated via single PPM case down below
* my nid's ntb/ppm sync need to be done with my
* proxy tei, it would be more accurate, so only update
* other nid's ntb/ppm here */
(void)mac_multi_ppm_record(pdev->pdev_id, nid,
cur_my_nid, rate_mode, rx_fc_msg.time_stamp,
local_ts, ntb_ts,
DEF_MULTI_SYNC_PERIOD, PLC_MAX_MAC_NTB_PPM);
/* crystal ppm error sync */
#if CPLC_IOT_CERT_SUPPORT
if (cert_mode)
{
/* or if CERT test mode's CCO
* and NID = 0's bcn, use it to
* sync the crystal freq error
*/
if (mac_cert_is_nid_valid(nid)) {
int16_t ppm_cert = PLC_MAX_MAC_NTB_PPM;
mac_ntb_ppm_sync(&vdev->mac_ppm,
rate_mode,
rx_fc_msg.time_stamp,
local_ts,
ntb_ts,
est_ppm,
&ppm_cert, vdev_get_bc_period_ms(vdev, proto),
true);
/* use the first stable ppm in cert loopback mode */
if (cert_mode == CERT_TEST_CMD_ENTER_PHY_LP) {
if (mac_get_lp_cal_ppm_is_hold()) {
mac_scan_set_bb_ppm(&vdev->mac_ppm,
-mac_get_rcd_lp_ppm(),
0, BB_PPM_TXRX);
ppm_cert = PLC_MAX_MAC_NTB_PPM;
} else {
if (ppm_cert != PLC_MAX_MAC_NTB_PPM) {
int8_t rcdppm = (int8_t)(ppm_cert >>
PLC_NTB_PPM_SHIFT);
if (!mac_get_is_not_first_cal_lp_ppm()) {
mac_set_rcd_lp_ppm(rcdppm);
mac_set_not_first_cal_lp_ppm(1);
} else {
int8_t dltppm =
mac_get_rcd_lp_ppm() - rcdppm;
if (IOT_ABS(dltppm) < 3) {
iot_printf("mac cert lp mode "
"hold ppm:%d\n", rcdppm);
mac_set_lp_cal_ppm_hold(1);
}
mac_set_rcd_lp_ppm(rcdppm);
}
}
}
}
/* stop the scan to sync the bcn
* test mode no need to scan the band
*/
//mac_scan_stop(&pdev->scan);
phy_set_sw_nn_ppm_para(0, 0,
ppm_cert >> PLC_NTB_PPM_SHIFT);
phy_set_sw_nn_ppm_para(1, nid,
ppm_cert >> PLC_NTB_PPM_SHIFT);
}
}
else
#endif
if ((nid != PLC_NID_INVALID)
&& (node_role == PLC_DEV_ROLE_STA))
{
/* if STA mode
* we need to sync the crystal disparity
*/
nid_t my_nid;
tei_t my_proxy = vdev_get_proxy_tei(vdev);
vdev_get_nid(vdev, &my_nid);
if (my_nid == nid) {
/* sync with joined network if available */
if ((rx_fc_msg.src_tei == my_proxy)) {
int16_t ppm_err = PLC_MAX_MAC_NTB_PPM;
mac_ntb_ppm_sync(&vdev->mac_ppm, rate_mode, \
rx_fc_msg.time_stamp, local_ts, ntb_ts, \
est_ppm, &ppm_err,
vdev_get_bc_period_ms(vdev, proto), true);
(void)mac_multi_ppm_record(pdev->pdev_id, my_nid,
my_nid, rate_mode, rx_fc_msg.time_stamp,
local_ts, ntb_ts,
DEF_MULTI_SYNC_PERIOD,
ppm_err);
#if K48_STA_MULTI_CHANNEL_SELECT_ENABLE
iot_mac_k48sta_scan_channel_stop(pdev);
#endif
is_chk_bcn_ppm = 0;
}
mac_ppm_record_handle(vdev, nid, &rx_fc_msg,
local_ts, ntb_ts, proto);
is_self_nid = 1;
}
}
if (pb_ed->rx_pb_crc_err)
{
mac_add_rx_bcn_pb_err_cnt();
if (rx_fc_msg.src_tei == PLC_TEI_CCO) {
mac_sched_cco_snr_rx(vdev, nid, snr,
RF_CHANNEL_ID_INVALID, 0, 0,
(uint8_t)proto_band_id);
}
/* free the error pb */
goto free_pkt;
}
if (!mac_tx_hw_get_bcn_swcrc_cfg())
{
/* if hw bcn crc enabled */
if (pb_ed->rx_beacon_pld_crc_err)
{
mac_add_rx_pld_err_cnt();
/* free the error pb */
goto free_pkt;
}
}
/* if all crc is ok, start to process
* and for bcn, should be last pb, save
* snr first, will fill this into
* rx_info later
*/
if (!pb_st->last_pb) {
//IOT_ASSERT(pb_st->last_pb);
iot_printf("bcn has no last pb\n");
goto free_pkt;
}
rx_phase = (uint8_t)mpdu_st->rx_phase;
delta_ntb = rx_fc_msg.time_stamp -
mac_rx_mpdu_end_get_ntb_timestamp(mpdu_ed);
if ((node_role != PLC_DEV_ROLE_CCO)
&& !cert_mode && is_self_nid) {
if (is_chk_bcn_ppm && vdev->bcn_ctx.sta.ntb_sync_done) {
int16_t tmp_ppm;
mac_ntb_record_ctxt_t tmp_ntb_record;
os_mem_cpy(&tmp_ntb_record, &vdev->sync_ntb_record,
sizeof(tmp_ntb_record));
tmp_ppm = mac_ppm_cal(&tmp_ntb_record,
rx_fc_msg.time_stamp, local_ts, ntb_ts, 1);
if (IOT_ABS(tmp_ppm) > PLC_SYNC_NTB_MAX_PPM) {
delta_ntb = 0;
} else {
os_mem_cpy(&vdev->sync_ntb_record,
&tmp_ntb_record, sizeof(tmp_ntb_record));
}
} else {
os_mem_cpy(&vdev->sync_ntb_record,
&vdev->mac_ppm.ntb_record,
sizeof(vdev->sync_ntb_record));
}
}
/* pull a rx desc len, after this point, rx meta info
* is overwritten with mac_rx_info_t.
*/
/* iot_pkt_array[0]'s data pointer is at the
* beginning. the following is att, mpdu_st, ...
* so we need to make sure the rx_info_t's
* memcpy is not overlay with previous FC.
* if it really does, we need to make some
* special action to copy this FC
*/
BUILD_BUG_ON(sizeof(mac_rx_info_t) < PB_PAYLOAD_OFFSET \
- sizeof(*att) - sizeof(frame_control_t));
mac_rx_info_t *p =
(mac_rx_info_t *)iot_pkt_pull(iot_pkt_array[0], \
PB_PAYLOAD_OFFSET - sizeof(mac_rx_info_t));
uint8_t *bcn_pld = \
iot_pkt_pull(iot_pkt_array[0], sizeof(mac_rx_info_t));
os_mem_cpy(&p->fc, mac_rx_mpdu_st_get_fc_addr(mpdu_st), \
sizeof(frame_control_t));
rssi = PHY_RSSI_FROM_RMI_GAIN(
mac_rx_mpdu_st_get_adc_power(mpdu_st),
mac_rx_mpdu_st_get_agc_gain_entry(mpdu_st));
/* TODO: remove this MAX/MIN and do it in PHY */
if (rssi != INV_RSSI) {
rssi = min(MAX_RSSI, rssi);
rssi = max(MIN_RSSI, rssi);
}
p->delta_ntb = delta_ntb;
p->phy.band_id = (uint8_t)proto_band_id;
p->phy.phase = rx_phase;
/* fill in snr saved before */
p->phy.snr = snr;
p->phy.rssi = PHY_RSSI_DBUV_TO_DBM(rssi);
p->phy.is_rf = 0;
p->phy.channel_id = RF_CHANNEL_ID_INVALID;
p->phy.rf_option = RF_OPTION_INVALID;
/* get the bcn pb sz and shrink the real bcn size */
ret = (uint32_t)iot_pkt_set_tail(iot_pkt_array[0], \
bcn_pld + pbsz);
if (ret == 0) {
iot_printf("pkt=0x%x, bcn_pld=0x%x, pbsz=%d\n",
iot_pkt_array[0], bcn_pld, pbsz);
IOT_ASSERT_DUMP(0,(uint32_t*)iot_pkt_array[0],17);
goto free_pkt;
}
/* upload to upper layer */
if (vdev->start_cfg.mac_bc_rx_func) {
#if defined(SIMU_NTB_SYNC)
nid_t simu_nid;
vdev_get_nid(vdev, &simu_nid); //TODO:
if ((node_role != PLC_DEV_ROLE_CCO) \
&& (nid == simu_nid))
{
vdev_ntb_sync(\
g_mac_pdev[pdev_id]->vdev[vdev_id], \
rx_fc_msg.time_stamp);
#if (PLC_MAC_RX_DEBUG_LOG)
iot_printf("vdev ntb %ld\n",
vdev_ntb_get(
g_mac_pdev[pdev_id]->vdev[vdev_id]));
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO,
IOT_MAC_RX_VDEV_NTB_ID, 1,\
vdev_ntb_get(
g_mac_pdev[pdev_id]->vdev[vdev_id]));
#endif
}
#endif
mac_add_rx_bcn_ok_cnt();
mac_beacon_rx((uint8_t)proto, vdev, iot_pkt_array[0]);
#if DBG_RX_ABORT_REASON_4 == 1
/* correct bcn received, clear the cnt */
pdev->cont_rx_abort4_cnt = 0;
#endif
}
else {
/* free this frame */
goto free_pkt;
}
break;
}
case FC_DELIM_SACK:
{
if (rx_fc_msg.sack_ext_deli == SACK_EXT_TYPE_SYNC || \
rx_fc_msg.sack_ext_deli == SACK_EXT_TYPE_SEARCH) {
mac_ckq_rx_and_ppm_sync(pdev, vdev, &rx_fc_msg, \
iot_pkt_array[0]);
} else {
if (!vdev) {
/* vdev not found, drop this SACK
*/
goto free_pkt;
}
if (rx_fc_msg.dst_tei != \
vdev_get_tei(vdev)){
/* if not dest for me, drop it */
goto free_pkt;
}
peer = find_peer(vdev, nid, \
(tei_t)rx_fc_msg.src_tei);
if (!peer) {
/* if the peer is not exist,
* create it right now
*/
ret = mac_peer_alloc(vdev, \
(tei_t)rx_fc_msg.src_tei, \
0, 1, 0, 0, &peer);
if (ret) {
/* create peer failed */
IOT_ASSERT(0);
}
}
/* update the rate info in peer */
if (vdev->ra_cb) {
vdev->ra_cb(peer, &rx_fc_msg);
}
/* free temp peer */
mac_peer_del_temp_peer(peer);
goto free_pkt;
}
break;
}
case FC_DELIM_NNCCO:
{
/* TODO: handle nncco or RTS-CTS*/
if (PLC_PROTO_TYPE_GP == proto)
{
mac_rx_debug_log_for_gp(rx_fc_msg.rtsf);
goto free_pkt;
}
else {
void *fc = mac_rx_mpdu_st_get_fc_addr(mpdu_st);
proto_band_id =
phy_hw_band_to_proto_band(mpdu_st->rx_band_sel);
uint32_t rxntb =
mac_rx_mpdu_end_get_ntb_timestamp(mpdu_ed);
if (mac_get_cert_test_flag() &&
USER_TYPE_STATE_GRID_XIAN ==
iot_oem_get_user_type()) {
/* modify rxntb(-3ms) for sanxi cert test */
rxntb -= 75000;
}
mac_sched_nn_rx(pdev,
fc, rxntb,
mac_rx_mpdu_st_get_avg_snr(mpdu_st), 0,
(uint8_t)proto_band_id);
#if (PLC_MAC_RX_DEBUG_LOG >= PLC_MAC_LOG_LEVEL_1)
iot_printf("NNCCO rx - st:%d,dur:%d, s_nid:0x%x, "
"r_nid:0x%x, rx_ts:%u\n",
mac_get_nncco_protect_region_offset(proto, fc),
mac_get_nncco_protect_dur(proto, fc),
mac_get_nid_from_fc(proto, fc),
mac_get_nncco_received_nid(proto, fc), rxntb);
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_INFO_LVL_1,
IOT_MAC_RX_NNCCO_ID, 0);
#endif
goto free_pkt;
}
break;
}
case I1901_RTS_CTS:
{
if (SUPPORT_IEEE_1901 && (PLC_PROTO_TYPE_SG == proto)) {
i1901_frame_control_t *i1901_fc;
i1901_fc = (i1901_frame_control_t *)
mac_rx_mpdu_st_get_fc_addr(mpdu_st);
iot_printf("rtscts rx, stei:%d, dtei:%d, rtsf:%d, "
"dur:%d\n",
rx_fc_msg.src_tei, rx_fc_msg.dst_tei,
rx_fc_msg.rtsf, i1901_fc->vf.rts_cts.dur);
} else {
iot_printf("invalid proto %d deli %d\n",
proto, delimiter_type);
}
goto free_pkt;
}
default:
{
/* TODO: other mpdu */
iot_printf("-----Unknown MPDU!-----\n");
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_WARN,
IOT_MAC_RX_UNKNOW_MPDU_ID, 0);
mac_add_rx_mpdu_type_err_cnt();
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_CRITICAL
mem_dump((uint32_t *)att, 16);
IOT_ASSERT(0);
#endif
goto free_pkt;
}
} // switch (delimiter_type)
/* done the switch case for type processing */
}
else {
/* should rx done */
iot_printf("-----Not done PB!-----\n");
iot_dbglog_input(PLC_MAC_RX_HW_MID, DBGLOG_WARN,
IOT_MAC_RX_MPDU_NOTDONE_ID, 0);
#if WAR_MPDU_NOT_DONE
ring->not_done = 4;
#endif
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
mem_dump((uint32_t *)iot_pkt_array[0], 20);
IOT_ASSERT_DUMP(0, (uint32_t *)att, 17);
#endif
goto free_pkt;
}
}
else {
/* ring empty, get out normally */
break;
}
//next_pkt:
/* need up layer to free the pkt for successful case */
continue;
save_mpdu_st_and_free:
/* save the current mpdu_st and then free the pb */
os_mem_cpy(&ring->saved_mpdu_st, mpdu_st,
sizeof(ring->saved_mpdu_st));
ring->cur_mpdu = &ring->saved_mpdu_st;
free_pkt:
/* free the error pb and continue rx next pkt */
iot_pkt_free(iot_pkt_array[0]);
continue;
/* if rest time is not enough, break and
* back later
*/
} while (os_boot_time32() - cur_ts < quota_ms);
return 0;
}
uint32_t mac_rx_hw_mpdu(void *pdev, uint32_t ring_id, uint32_t quota_ms)
{
uint32_t ret = ERR_OK;
rx_buf_ring_t *ring;
#if HW_PLATFORM == HW_PLATFORM_SIMU
ring = &((mac_pdev_t*)pdev)->simu.rx_ring[ring_id];
#else
ring = &((mac_pdev_t*)pdev)->ring_hdl.ring[ring_id];
#endif
if (!ring->msg_delivered) {
/* if not delivered, queue the msg */
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->type = MAC_MSG_TYPE_DSR;
msg->id = MAC_MSG_ID_DSR_RX_TO_MSG;
/* bit0~bit15: ring id.
* bit16: indicate ring type. 0 - plc ring, 1 - rf ring.
*/
msg->data1 = ring_id & 0xFFFF;
msg->data2 = pdev;
msg->data3 = (void*)quota_ms;
mac_queue_msg(msg, MAC_MSG_QUEUE_MP);
/* TODO: this is assume in the same task of MAC */
ring->msg_delivered = 1;
}
out:
return ret;
}