Files
kunlun/plc/halmac/htbus/beacon_frame_htbus.c

538 lines
18 KiB
C
Raw Permalink Normal View History

2024-09-28 14:24:04 +08:00
/****************************************************************************
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 "beacon_frame.h"
#include "mac_reset.h"
#include "mac_sched.h"
#include "mac_sched_htbus.h"
#include "mac_cmn_hw.h"
#include "mac_crc.h"
#include "mpdu_header.h"
#include "rate_control.h"
#include "phy_txrx_pwr.h"
#include "plc_beacon_htbus.h"
#include "iot_config_api.h"
#include "iot_bitmap_api.h"
#include "iot_io_api.h"
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#if IOT_HTBUS_EN
static void mac_beacon_fill_buf_htbus(mac_beacon_ctx_t *bcn, uint8_t **tmp)
{
uint8_t *data = *tmp;
beacon_htbus_payload_fixed_header_t *plh;
beacon_htbus_entry_ts_t *tsh;
beacon_htbus_entry_ud_t *udh;
/* fill FC */
frame_control_t *fc = (frame_control_t *)data;
data += sizeof(frame_control_t);
if (bcn->beacon_component_enable[MAC_BC_FC_INFO]) {
fc->delimiter_type = FC_DELIM_BEACON;
fc->network_type = bcn->fc.net_type;
fc->nid = bcn->fc.nid;
fc->vf.bcn.time_stamp =
mac_sched_get_ntb((mac_vdev_t *)bcn->ref_vdev_ptr);
#if (MAC_SCHED_DEBUG || RUNTIME_DEBUG)
iot_printf("%s curr ntb:%lu, start ntb %lu, nid %lu phase %lu\n",
__FUNCTION__, fc->vf.bcn.time_stamp, bcn->ts_htbus.start_ntb,
bcn->fc.nid, bcn->fc.phase);
iot_dbglog_input(PLC_MAC_BEACON_MID, DBGLOG_INFO,
IOT_MAC_BEACON_TX_NTB_INFO, 4, fc->vf.bcn.time_stamp,
bcn->ts_htbus.start_ntb, bcn->fc.nid, bcn->fc.phase);
#endif
fc->vf.bcn.src_tei = vdev_get_tei(bcn->ref_vdev_ptr);
fc->vf.bcn.sym_num = 0; /* filled by HW */
fc->vf.bcn.phase_num = bcn->fc.phase;
} else {
IOT_ASSERT(0);
}
/* fill in beacon payload fixed header */
plh = (beacon_htbus_payload_fixed_header_t *)data;
data += sizeof(*plh);
if (bcn->beacon_component_enable[MAC_BC_BMI_HTBUS_FIX_P]) {
plh->type = bcn->fp_htbus.type;
plh->reboot_cnt = bcn->fp_htbus.reboot_cnt;
plh->period_cnt = bcn->fp_htbus.req_period_cnt;
plh->beacon_entry_num = 0;
} else {
IOT_ASSERT(0);
}
/* fill in the time slot entry info */
if (bcn->beacon_component_enable[MAC_BC_BMI_HTBUS_TIME_SLOT] &&
mac_vdev_cfg_get_node_role(bcn->ref_vdev_ptr) == PLC_DEV_ROLE_CCO) {
tsh = (beacon_htbus_entry_ts_t *)data;
tsh->hdr.entry_type = MAC_BCN_HTBUS_ENTRY_TYPE_ID_TS;
tsh->cco_slot_dur = bcn->ts_htbus.cco_slot;
tsh->sta_slot_dur = bcn->ts_htbus.sta_slot;
tsh->start_ntb = bcn->ts_htbus.start_ntb;
tsh->bm_len = (iot_bitmap_fls(bcn->ts_htbus.rsp_bm,
sizeof(bcn->ts_htbus.rsp_bm)) + 7) >> 3;
os_mem_cpy(tsh->rsp_bm, bcn->ts_htbus.rsp_bm, tsh->bm_len);
tsh->hdr.entry_len = sizeof(*tsh) + tsh->bm_len;
data += tsh->hdr.entry_len;
plh->beacon_entry_num++;
}
/* fill user data entry info */
if (bcn->beacon_component_enable[MAC_BC_BMI_HTBUS_USER_DATA]) {
udh = (beacon_htbus_entry_ud_t *)data;
udh->hdr.entry_type = MAC_BCN_HTBUS_ENTRY_TYPE_ID_UD;
os_mem_cpy(udh->data, bcn->ud_htbus.data_ptr, bcn->ud_htbus.len);
udh->hdr.entry_len = sizeof(*udh) + bcn->ud_htbus.len;
data += udh->hdr.entry_len;
plh->beacon_entry_num++;
}
*tmp = data;
}
static void mac_beacon_fill_pld_icv_htbus(uint32_t proto,
uint8_t *data, iot_pkt_t *bcn_buf)
{
IOT_ASSERT(data);
uint8_t fc_len = mac_get_mpdu_fc_len(proto);
switch (proto) {
case PLC_PROTO_TYPE_SG:
{
beacon_payload_icv_t *icv = NULL;
icv = (beacon_payload_icv_t *)data;
icv->icv = iot_getcrc32(iot_pkt_data(bcn_buf) + fc_len,
(uint32_t)(data - iot_pkt_data(bcn_buf) - fc_len));
break;
}
default:
IOT_ASSERT(0);
break;
}
}
static void mac_beacon_fill_fc_tmi_htbus(uint32_t proto, frame_control_t *fc,
uint32_t tmi)
{
IOT_ASSERT(fc);
switch (proto) {
case PLC_PROTO_TYPE_SG:
{
fc->vf.bcn.tmi = tmi & 0xf;
break;
}
default:
IOT_ASSERT(0);
break;
}
}
static void mac_beacon_calc_rate_htbus(uint32_t beacon_len,
uint32_t *tmi, uint32_t *pb_size, uint32_t *rate_mode)
{
if (beacon_len > 136) {
*tmi = 1;
*pb_size = 520;
} else {
*tmi = 2;
*pb_size = 136;
}
*rate_mode = 0;
}
static uint8_t mac_beacon_tx_htbus(uint32_t proto, uint32_t proto_band_id,
mac_beacon_ctx_t *bcn, iot_pkt_t *bcn_buf)
{
uint32_t tmi;
uint32_t rate_mode;
uint32_t tx_power = PHY_FULL_PWR_DBUV;
uint32_t pb_size;
uint8_t *tmp = iot_pkt_data(bcn_buf);
uint8_t bc_pb_crc_len = mac_get_pb_crc_len(FC_DELIM_BEACON, proto);
uint8_t bc_pld_icv_len = 0;
uint8_t fc_len = mac_get_mpdu_fc_len(proto);
void *fc = (void *)tmp;
os_mem_set(tmp, 0, iot_pkt_block_len(bcn_buf, IOT_PKT_BLOCK_DATA) +
iot_pkt_block_len(bcn_buf, IOT_PKT_BLOCK_TAIL));
mac_beacon_fill_buf_htbus(bcn, &tmp);
bc_pld_icv_len = sizeof(beacon_payload_icv_t);
uint32_t bcn_len;
/* bcn_len is payload length for mac_bcn_get_rate, not including FC */
bcn_len = tmp - iot_pkt_data(bcn_buf) + bc_pld_icv_len +
bc_pb_crc_len - fc_len;
mac_beacon_calc_rate_htbus(bcn_len, &tmi, &pb_size, &rate_mode);
IOT_ASSERT(bcn_len <= pb_size);
tmp = iot_pkt_data(bcn_buf) + fc_len + pb_size -
bc_pb_crc_len - bc_pld_icv_len;
/* fill icv */
mac_beacon_fill_pld_icv_htbus(proto, tmp, bcn_buf);
tmp += bc_pld_icv_len;
/* fill the correct tmi now, as the bcn len is got into consideration */
mac_beacon_fill_fc_tmi_htbus(proto, fc, tmi);
IOT_ASSERT(iot_pkt_set_tail(bcn_buf, tmp));
mac_send_bcn(proto, proto_band_id,
((mac_vdev_t *)bcn->ref_vdev_ptr)->ref_pdev_id,
bcn_buf, rate_mode, bcn->fc.phase, 0, tx_power);
return 1;
}
#if PLC_SUPPORT_CCO_ROLE
/* htbus cco only beacon update handling */
static uint8_t mac_update_beacon_cco_htbus(uint32_t proto, mac_vdev_t *vdev,
mac_bc_update_t *ent)
{
uint64_t tmp;
uint8_t tx_cnt = 0;
/* below fields need to be updated for every beacon by mac layer
* 1. request period count
* 2. request period start ntb
*/
if (ent->new_bp_req) {
if (!vdev->bcn_ctx.cco.started) {
mac_sched_stop(vdev);
vdev->bcn_ctx.cco.started = 1;
mac_config_tei(vdev, vdev_get_tei(vdev));
}
/* apply the next beacon period schedule into HW */
tmp = mac_sched_get_ntb64(vdev);
tmp += MAC_MS_TO_NTB(MAC_BP_AHEAD_NEXT_BP_DUR);
/* config scheduler for next beacon period */
mac_sched_cco_set_htbus(vdev, &vdev->bcn_ctx.ts_htbus, tmp);
/* update request period count */
vdev->bcn_ctx.cco.curr_bp_cnt++;
if (vdev->bcn_ctx.cco.curr_bp_cnt > 0xFFFF) {
vdev->bcn_ctx.cco.curr_bp_cnt = 1;
}
vdev->bcn_ctx.fp_htbus.req_period_cnt =
(uint16_t)vdev->bcn_ctx.cco.curr_bp_cnt;
/* update start ntb */
vdev->bcn_ctx.ts_htbus.start_ntb = tmp;
/* update tx phase */
vdev->bcn_ctx.fc.phase = vdev->l_phase1;
/* trigger new beacon tx */
tx_cnt = mac_beacon_tx_htbus(proto, phy_proto_single_band_id_get(),
&vdev->bcn_ctx, vdev->bcn_ctx.mac_beacon_buffer[0]);
}
return tx_cnt;
}
#else /* PLC_SUPPORT_CCO_ROLE */
#define mac_update_beacon_cco_htbus(proto, vdev, ent) (0)
#endif /* PLC_SUPPORT_CCO_ROLE */
/* sta only beacon update handling */
static uint8_t mac_update_beacon_sta_htbus(uint32_t proto, mac_vdev_t *vdev,
mac_bc_update_t *ent)
{
uint64_t curr_ntb;
uint32_t end_ntb;
uint8_t tx_cnt = 0;
uint32_t resp_slot_cnt;
mac_beacon_ctx_t *bcn_ctx = &vdev->bcn_ctx;
#if DEBUG_HWQ_SHCED_HANG
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
pdev->dbg_status = MAC_TX_HANG_STATUS_4;
#endif
/* stop HW scheduler first if it's running */
mac_sched_stop(vdev);
#if DEBUG_HWQ_SHCED_HANG
pdev->dbg_status = MACC_TX_HANG_STATUS_MAX;
#endif
if (bcn_ctx->sta.ntb_sync_done == 0) {
/* config HW to sync up the NTB with the preferred network. */
if (bcn_ctx->fc.delta_ntb) {
mac_sched_sync_ntb(vdev, 0, bcn_ctx->fc.delta_ntb);
}
mac_zc_set_func_cmd(vdev->ref_pdev_id, MAC_ZC_FUNC_CMD_RESET_HW, NULL);
bcn_ctx->sta.ntb_sync_done = 1;
} else if (bcn_ctx->sta.force_sw_sync) {
/* config HW to sync up the NTB with the preferred network. */
if (bcn_ctx->fc.delta_ntb) {
mac_sched_sync_ntb(vdev, 0, bcn_ctx->fc.delta_ntb);
}
}
curr_ntb = mac_sched_get_ntb64(vdev);
resp_slot_cnt = iot_bitmap_cbs((uint8_t *)&bcn_ctx->ts_htbus.rsp_bm,
sizeof(bcn_ctx->ts_htbus.rsp_bm));
end_ntb = bcn_ctx->ts_htbus.start_ntb +
MAC_MS_TO_NTB(bcn_ctx->ts_htbus.cco_slot +
resp_slot_cnt * bcn_ctx->ts_htbus.sta_slot);
if ((end_ntb - iot_uint64_lower32(curr_ntb)) >= 0x7FFFFFFF) {
/* current beacon period is obsolete */
iot_printf("%s bp already expired start_ntb %lu, "
"end_ntb %lu, curr_ntb %lu\n", __FUNCTION__,
bcn_ctx->ts_htbus.start_ntb, end_ntb,
iot_uint64_lower32(curr_ntb));
/* config a csma only command list to enable scheduler */
mac_sched_set_csma_only(vdev, curr_ntb, 0);
} else {
/* apply the next beacon period schedule into HW, at least enable tx
* for local logical phase.
*/
mac_sched_sta_set_htbus(vdev, &vdev->bcn_ctx.ts_htbus,
bcn_ctx->ts_htbus.start_ntb);
/* check if a new beacon tx is required for the update beacon
* template. for cco role device, always delay the new beacon tx
* to the periodical beacon phase.
*/
if (ent->tx_req) {
/* always use local phase for beacon tx */
vdev->bcn_ctx.fc.phase = vdev->l_phase1;
tx_cnt = mac_beacon_tx_htbus(proto, phy_proto_single_band_id_get(),
&vdev->bcn_ctx, vdev->bcn_ctx.mac_beacon_buffer[0]);
}
}
return tx_cnt;
}
static uint32_t mac_beacon_rx_icv_get_htbus(uint8_t proto, iot_pkt_t* buf)
{
uint32_t bcn_icv = 0;
IOT_ASSERT(buf);
switch (proto) {
#if SUPPORT_SMART_GRID
case PLC_PROTO_TYPE_SG:
{
beacon_payload_icv_t *icv;
icv = (beacon_payload_icv_t*)(iot_pkt_block_ptr(buf, IOT_PKT_BLOCK_TAIL)
- sizeof(beacon_payload_icv_t) - SG_BCN_PB_CRC_LEN);
bcn_icv = icv->icv;
break;
}
#endif
default:
break;
}
return bcn_icv;
}
static void mac_beacon_rx_plh_get_htbus(uint8_t proto,
bcn_pld_hdr_t *msg, uint8_t *tmp)
{
IOT_ASSERT(msg);
beacon_htbus_payload_fixed_header_t *plh_htbus =
(beacon_htbus_payload_fixed_header_t *)tmp;
msg->beacon_type = plh_htbus->type;
msg->beacon_seq_num = (uint32_t)plh_htbus->period_cnt;
}
uint32_t mac_beacon_rx(uint8_t proto, void *vdev_ptr, iot_pkt_t *buf)
{
mac_vdev_t *vdev = (mac_vdev_t *)vdev_ptr;
uint8_t *tmp, new_bp = 0;
uint32_t i = 0;
uint32_t crc = 0;
uint32_t bcn_len, bcn_icv = 0;
mac_rx_info_t *rx_info;
uint32_t ret = ERR_OK;
bcn_pld_hdr_t plh = { 0 };
rx_fc_msg_t rx_fc = { 0 };
uint32_t bc_period_cnt;
if (!vdev || !buf) {
IOT_ASSERT(0);
ret = ERR_INVAL;
goto err;
}
if (vdev->start_cfg.mac_bc_rx_func == NULL) {
ret = ERR_NOT_READY;
goto err;
}
tmp = iot_pkt_block_ptr(buf, IOT_PKT_BLOCK_DATA);
rx_info = (mac_rx_info_t *)(tmp - sizeof(*rx_info));
/* check crc */
bcn_len = iot_pkt_block_len(buf, IOT_PKT_BLOCK_DATA);
#if PLC_MAC_RX_DEBUG_LOG
iot_printf("rx bcn len %d on band %d\n", bcn_len, rx_info->phy.band_id);
#endif
/* check beacon payload crc */
bcn_icv = mac_beacon_rx_icv_get_htbus(proto, buf);
ret = mac_crc_get_bcn_swcrc(proto, iot_pkt_data(buf), bcn_len, &crc);
if (ret == ERR_CRC_LEN) {
mem_dump((uint32_t *)buf, 21); // 4iot_pkt addr + 16desc + 1DW plod
goto err;
}
if (crc != bcn_icv) {
/* TODO: check with accurate len,
*/
mac_add_rx_bcn_err_cnt();
iot_printf("bcn crcerrcnt: %lu, bcn_icv=0x%x, crc_cal=0x%x \n",
mac_get_rx_bcn_err_cnt(), bcn_icv, crc);
#if PLC_HW_ISSUE_ASSERT_LEVEL <= PLC_HW_ISSUE_ASSERT_ALL
IOT_ASSERT(0);
#endif
ret = ERR_CRC_FAIL;
goto err;
}
/* get fixed header and fc info */
mac_beacon_rx_plh_get_htbus(proto, &plh, tmp);
mac_beacon_rx_fc_info_get(proto, rx_info, &rx_fc);
/* sync sta/pco's timestamp */
if ((mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) &&
(rx_fc.nid == vdev->bcn_ctx.fc.nid)) {
bc_period_cnt = vdev->bcn_ctx.fp_htbus.req_period_cnt;
if (bc_period_cnt == 0) {
/* always accept the first beacon */
i = 1;
} else {
i = plh.beacon_seq_num - bc_period_cnt;
}
if (i && i <= PLC_BCN_DUPLICATE_GUARD) {
/* new beacon period, sync up the time stamp and save the
* start ntb
*/
new_bp = 1;
#if (MAC_SCHED_DEBUG || RUNTIME_DEBUG)
iot_printf("%s bc recv ntb %lu, bc send ntb %lu, bp cnt %lu\n",
__FUNCTION__, mac_sched_get_ntb(vdev), rx_fc.time_stamp,
bc_period_cnt);
iot_dbglog_input(PLC_MAC_DATA_MID, DBGLOG_INFO,
IOT_MAC_BEACON_RX_NTB_INFO, 3, mac_sched_get_ntb(vdev),
rx_fc.time_stamp, bc_period_cnt);
#endif
}
}
mac_add_rx_bcn_upload_cnt();
vdev->start_cfg.mac_bc_rx_func(vdev->start_cfg.mac_callback_arg,
buf, new_bp);
goto out;
err:
iot_printf("%s error reason %d\n", __FUNCTION__, ret);
iot_pkt_free(buf);
out:
return ret;
}
uint32_t mac_update_beacon_internal(uint8_t pdev_id, uint8_t vdev_id,
mac_bc_update_t *ent, uint8_t *tx_cnt)
{
uint32_t ret = ERR_OK;
uint32_t i;
mac_vdev_t *vdev = NULL;
uint32_t proto = PHY_PROTO_TYPE_GET();
mac_beacon_ctx_t *bcn_ctxt;
*tx_cnt = 0;
vdev = get_vdev_ptr(pdev_id, vdev_id);
if (vdev == NULL) {
ret = ERR_INVAL;
goto out;
}
bcn_ctxt = &vdev->bcn_ctx;
/* alwasy disable optional beacon entry for each update by default */
bcn_ctxt->beacon_component_enable[MAC_BC_FC_INFO] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_HTBUS_FIX_P] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_HTBUS_TIME_SLOT] = 0;
bcn_ctxt->beacon_component_enable[MAC_BC_BMI_HTBUS_USER_DATA] = 0;
for (i = 0; i < ent->count; i++) {
switch (ent->entry[i].type) {
case MAC_BC_FC_INFO:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->fc, ent->entry[i].data,
sizeof(bcn_ctxt->fc));
bcn_ctxt->fc.nid = mac_mask_input_nid(bcn_ctxt->fc.nid);
bcn_ctxt->beacon_component_enable[ent->entry[i].type] = 1;
}
break;
}
case MAC_BC_BMI_HTBUS_FIX_P:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->fp_htbus, ent->entry[i].data,
sizeof(bcn_ctxt->fp_htbus));
bcn_ctxt->beacon_component_enable[ent->entry[i].type] = 1;
}
break;
}
case MAC_BC_BMI_HTBUS_TIME_SLOT:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->ts_htbus, ent->entry[i].data,
sizeof(bcn_ctxt->ts_htbus));
bcn_ctxt->beacon_component_enable[ent->entry[i].type] = 1;
}
break;
}
case MAC_BC_BMI_HTBUS_USER_DATA:
{
if (ent->action[i] == MAC_BC_ACT_ADD) {
os_mem_cpy(&bcn_ctxt->ud_htbus, ent->entry[i].data,
sizeof(bcn_ctxt->ud_htbus));
bcn_ctxt->beacon_component_enable[ent->entry[i].type] = 1;
}
break;
}
default:
IOT_ASSERT(0);
break;
}
}
/* config NID to HW once the NID is available */
vdev_set_nid(vdev, bcn_ctxt->fc.nid);
if (mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) {
*tx_cnt = mac_update_beacon_sta_htbus(proto, vdev, ent);
} else {
*tx_cnt = mac_update_beacon_cco_htbus(proto, vdev, ent);
}
#if PLC_SUPPORT_DBG_PKT_MODE
vdev_set_block_dbg_pkt_4_rx_only(vdev, true);
#endif
out:
return ret;
}
#endif /* IOT_HTBUS_EN */