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

1232 lines
42 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.
****************************************************************************/
/* os shim includes */
#include "os_types.h"
#include "os_mem.h"
#include "os_timer.h"
/* common includes */
#include "iot_module.h"
#include "iot_errno.h"
#include "iot_utils.h"
#include "iot_io.h"
#include "iot_config.h"
/* mac module internal includes */
#include "mac_vdev.h"
#include "mac_sched.h"
#include "mac_sched_hw.h"
#include "command_list.h"
#include "mac_desc_engine.h"
#include "mac_hwq_mgr.h"
#include "mac_pdev.h"
#include "mac.h"
#include "plc_beacon.h"
#include "hw_war.h"
#include "mac_cert_test.h"
#include "mac_rf_pdev.h"
#include "mac_rf_vdev.h"
#include "mac_rf_sched.h"
#include "mac_rf_tx_hw.h"
#if HPLC_RF_DEV_SUPPORT
#include "mac_rf_sched_hw.h"
#include "mac_rf_isr.h"
#endif
/* public api includes */
#include "plc_fr.h"
#include "mac_bcm_api.h"
#include "mac_dsr.h"
#include "mpdu_header.h"
#include "iot_bitops_api.h"
#if HW_PLATFORM != HW_PLATFORM_SIMU
/* csma region pkt tx may be overlapped with next region due to HW issue.
* reserve some gap in the end of the csma region of each beacon period.
* unit is 1ms
*/
#define MAC_RF_SCHED_CSMA_GAP_MS 40
#else /* HW_PLATFORM != HW_PLATFORM_SIMU */
#define MAC_RF_SCHED_CSMA_GAP_MS 0
#endif /* HW_PLATFORM != HW_PLATFORM_SIMU */
/* if there is big hole between current ntb and start ntb of network beacon
* period. try to insert csma region into the hole to improve bandwidth
* utilization.
* if the whole equal or larged than this value, local device should insert
* the csma region. the unit is 1 ntb.
*/
#define MAC_RF_SCHED_INSERT_CSMA_TH MAC_MS_TO_NTB(600)
/* if there is big hole between current ntb and start ntb of network beacon
* period. the amount of time reserved for software to be allocated time slot.
*/
#define MAC_RF_SCHED_PREPARE_CSMA_RESV_MS 40
/* define the supported minimum duration for command list.
* the unit is 1ms.
*/
#define MAC_RF_SCHED_CMD_LIST_DUR_MIN 500
/* define the max of rf slot dur, unit 1ms */
#define MAC_RF_MAX_SLOT_DUR 15000
/* define rf slot dur, unit 1ms */
#define MAC_RF_SLOT_DUR 500
/* define minimum rf bc slot dur, unit 1ms */
#define MAC_RF_BC_SLOT_DUR_MIN 30
/* scheulder context */
typedef struct _mac_rf_sched_ctx {
/* current command list queue in use */
hw_sched_cmd_list_t *curr_hw_cmd_list;
/* command list queue */
hw_sched_cmd_list_t *hw_cmd_list[HW_SCHED_QUEUE_DEPTH];
/* command list queue count */
uint8_t hw_cmd_list_cnt;
/* command list queue pos of the next free slot */
uint8_t hw_cmd_list_pos;
} mac_rf_sched_ctx_t;
#if HPLC_RF_DEV_SUPPORT
#if MAC_RF_SCHED_DEBUG
static void mac_rf_sched_dump(hw_sched_cmd_list_t *cl, uint16_t cnt)
{
uint16_t i;
iot_printf("%s total %lu, recusive %lu ----------------------\n",
__FUNCTION__, cnt, cl->recursive);
for (i = 0; i < cnt; i++) {
iot_printf("rf end offset - %lu, q_bm %x\n",
cl->cmd[i].rf_end_t, cl->cmd[i].rf_tx_q_en_bm);
}
iot_printf("------------------------------------------------------\n");
}
#else /* MAC_SCHED_DEBUG */
#define mac_rf_sched_dump(cl, cnt)
#endif /* MAC_SCHED_DEBUG */
/* get wide band beacon queue bitmap according to appointed phase */
static uint32_t mac_rf_sched_get_wb_bc_q(mac_rf_vdev_t *rf_vdev)
{
uint32_t ret = 0;
IOT_ASSERT(rf_vdev);
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
IOT_ASSERT(rf_pdev);
mac_rf_queue_ctxt_t *queue = &rf_pdev->hwq_hdl;
ret = 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_BCN);
return ret;
}
/* get csma queue bitmap according to appointed phase */
static uint32_t mac_rf_sched_get_csma_q(mac_rf_vdev_t *rf_vdev)
{
uint32_t ret = 0;
IOT_ASSERT(rf_vdev);
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
IOT_ASSERT(rf_pdev);
mac_rf_queue_ctxt_t *queue = &rf_pdev->hwq_hdl;
ret = 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_CSMA_0);
#if !ENA_RF_ONLY_ONE_CSMA_HWQ
/* rf csma just one hwq enable */
ret |= 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_CSMA_1);
ret |= 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_CSMA_2);
ret |= 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_CSMA_3);
#if PLC_SUPPORT_DBG_PKT_MODE
ret |= 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_CSMA_DBG);
#endif
#endif
return ret;
}
/* get tdma queue bitmap according to appointed phase */
uint32_t mac_rf_sched_get_tdma_q(mac_rf_vdev_t *rf_vdev)
{
uint32_t ret = 0;
IOT_ASSERT(rf_vdev);
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
IOT_ASSERT(rf_pdev);
mac_rf_queue_ctxt_t *queue = &rf_pdev->hwq_hdl;
ret = 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_TDMA);
return ret;
}
/* get dedicated csma queue bitmap according to appointed phase */
static uint32_t mac_rf_sched_get_dcsma_q(mac_rf_vdev_t *rf_vdev)
{
uint32_t ret = 0;
IOT_ASSERT(rf_vdev);
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
IOT_ASSERT(rf_pdev);
mac_rf_queue_ctxt_t *queue = &rf_pdev->hwq_hdl;
ret = 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_BCSMA);
return ret;
}
static uint32_t mac_rf_sched_get_dbg_q(mac_rf_vdev_t *rf_vdev)
{
uint32_t ret = 0;
IOT_ASSERT(rf_vdev);
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
IOT_ASSERT(rf_pdev);
mac_rf_queue_ctxt_t *queue = &rf_pdev->hwq_hdl;
ret = 1 << mac_rf_q_get_hwqid(queue, MAC_RF_QUE_CSMA_DBG);
return ret;
}
static hw_sched_cmd_list_t *mac_rf_sched_alloc_cmd_list(mac_rf_vdev_t *rf_vdev)
{
mac_rf_sched_ctx_t *ctx = rf_vdev->rf_sched_ctx;
hw_sched_cmd_list_t *cl = NULL;
IOT_ASSERT(ctx->hw_cmd_list_cnt <= HW_SCHED_QUEUE_DEPTH);
if (ctx->hw_cmd_list_cnt < HW_SCHED_QUEUE_DEPTH) {
/* free command list vailable, allocate new one */
if (ctx->hw_cmd_list[ctx->hw_cmd_list_pos] == NULL) {
mac_desc_get(&g_mac_desc_eng, PLC_SCHED_CMD_LIST_POOL,
(void **)&cl);
ctx->hw_cmd_list[ctx->hw_cmd_list_pos] = cl;
} else {
cl = ctx->hw_cmd_list[ctx->hw_cmd_list_pos];
}
ctx->hw_cmd_list_pos++;
if (ctx->hw_cmd_list_pos == HW_SCHED_QUEUE_DEPTH)
ctx->hw_cmd_list_pos = 0;
ctx->hw_cmd_list_cnt++;
} else {
/* check if any command list returned from HW */
if (mac_rf_sched_get_cmd_list_cnt(rf_vdev) >= HW_SCHED_QUEUE_DEPTH) {
//TODO: dbg for hw sched
os_mem_cpy(ctx->hw_cmd_list[0]->cmd, ctx->hw_cmd_list[1], 20);
IOT_ASSERT_DUMP(0, (uint32_t *)ctx->hw_cmd_list[0], 10);
}
/* re-use the previos command list returned from HW */
cl = ctx->hw_cmd_list[ctx->hw_cmd_list_pos];
ctx->hw_cmd_list_pos++;
if (ctx->hw_cmd_list_pos == HW_SCHED_QUEUE_DEPTH)
ctx->hw_cmd_list_pos = 0;
}
IOT_ASSERT(cl);
os_mem_set(cl, 0, sizeof(*cl));
#if MAC_RF_SCHED_DEBUG
iot_printf("%s allocate %p\n", __FUNCTION__, cl->cmd);
#endif
return cl;
}
static void mac_rf_sched_free_cmd_list(mac_rf_vdev_t *vdev)
{
mac_rf_sched_ctx_t *ctx = vdev->rf_sched_ctx;
ctx->hw_cmd_list_cnt = 0;
ctx->hw_cmd_list_pos = 0;
}
/* load command list into the HW scheduler, return 1 if the command list
* is already done.
*/
static uint32_t mac_rf_sched_load_cmd_list(mac_rf_vdev_t *rf_vdev,
hw_sched_cmd_list_t *cl)
{
uint32_t cnt, curr_dur, left_dur;
hw_sched_cmd_t *start_cmd, *end_cmd, *last_cmd, *prev_cmd = NULL;
if (cl->next_idx == cl->total_cnt) {
/* current command list is done */
return 1;
}
IOT_ASSERT(cl->next_idx < cl->total_cnt);
/* set start ntb of next beacon period */
mac_rf_sched_set_bp_start_ntb(rf_vdev, cl->start_ntb);
/* calculate how many commands can be push into the HW scheduler */
cnt = cl->total_cnt - cl->next_idx;
cnt = min(cnt, HW_SHCED_CMD_DEPTH);
start_cmd = cl->cmd + cl->next_idx;
if (cl->next_idx) {
prev_cmd = start_cmd - 1;
}
end_cmd = start_cmd + (cnt - 1);
last_cmd = cl->cmd + (cl->total_cnt - 1);
/* push commands into the HW */
mac_rf_sched_set_bp_cmd_list(rf_vdev, start_cmd, (uint16_t)cnt);
if (prev_cmd) {
curr_dur = end_cmd->rf_end_t - prev_cmd->rf_end_t;
} else {
curr_dur = end_cmd->rf_end_t;
}
if (last_cmd != end_cmd) {
/* reduce current command list duration to make sure enough
* duration left for the last command list.
*/
left_dur = last_cmd->rf_end_t - end_cmd->rf_end_t;
while (left_dur < MAC_MS_TO_NTB(MAC_RF_SCHED_CMD_LIST_DUR_MIN)) {
end_cmd--;
cnt--;
IOT_ASSERT(end_cmd > start_cmd);
left_dur = last_cmd->rf_end_t - end_cmd->rf_end_t;
}
if (prev_cmd) {
curr_dur = end_cmd->rf_end_t - prev_cmd->rf_end_t;
} else {
curr_dur = end_cmd->rf_end_t;
}
}
IOT_ASSERT(curr_dur >= MAC_MS_TO_NTB(MAC_RF_SCHED_CMD_LIST_DUR_MIN));
/* set command list duration */
mac_rf_sched_set_bp_dur(rf_vdev, MAC_NTB_TO_MS(end_cmd->rf_end_t));
#if MAC_RF_SCHED_DEBUG
iot_printf("%s %lu start offset %lu, end offset %lu\n", __FUNCTION__,
cl->total_cnt, prev_cmd ? prev_cmd->rf_end_t : 0,
end_cmd->rf_end_t);
#endif
/* trigger new beacon period */
mac_rf_sched_trigger_bp(rf_vdev);
cl->next_idx += cnt;
return 0;
}
/* switch the units of offset from ms to ntb */
void mac_rf_sched_offset_switch(hw_sched_cmd_list_t *cl, uint16_t cnt)
{
#if HW_PLATFORM != HW_PLATFORM_SIMU
for (uint32_t i = 0; i < cnt; i++) {
cl->cmd[i].rf_end_t = MAC_MS_TO_NTB(cl->cmd[i].rf_end_t);
}
#else
(void)cl;
(void)cnt;
#endif
}
#if (PLC_SUPPORT_CCO_ROLE)
/* cco role device need to take care of both phase and band config */
void mac_rf_sched_cco_set(mac_rf_vdev_t *rf_vdev, mac_bc_time_slot_t *ts,
uint64_t start_ntb64, uint64_t next_start_ntb64)
{
uint16_t i, cnt = 0;
uint32_t start_offset = 0, judge_ntb = 0;
hw_sched_cmd_list_t *cl = NULL;
IOT_ASSERT(rf_vdev);
mac_rf_sched_ctx_t *ctx = rf_vdev->rf_sched_ctx;
hw_sched_cmd_t *cmd;
cl = mac_rf_sched_alloc_cmd_list(rf_vdev);
IOT_ASSERT(cl);
ctx->curr_hw_cmd_list = cl;
cmd = cl->cmd;
cl->alloc_ntb = mac_rf_sched_get_ntb(rf_vdev);
cl->caller = 1;
cl->start_ntb = iot_uint64_lower32(start_ntb64);
cl->start_ntb_h = iot_uint64_higher32(start_ntb64);
/* prepare central beacon slot */
uint32_t rf_start_offset = start_offset;
// TODO: need to support CCO not simultaneously tx hplc and rf package.
/* rf beacon slot */
if (ts->rf_std_tx) {
rf_start_offset += ts->rf_bc_slot_dur;
} else {
rf_start_offset += ts->bc_slot_dur;
}
cmd->rf_end_t = rf_start_offset;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_wb_bc_q(rf_vdev);
/* calculate center beacon slot */
start_offset += ts->cco_bc_cnt * ts->bc_slot_dur;
/* prepere proxy and discovery beacon slot */
if (ts->non_cco_bc_info.bc_cnt) {
start_offset += ts->non_cco_bc_info.bc_cnt * ts->bc_slot_dur;
}
/* ensure standard rf slot does not overlap with CSMA slot */
if (start_offset > rf_start_offset) {
/* new cmd */
cnt++;
cmd++;
cmd->rf_end_t = start_offset;
} else if (start_offset < rf_start_offset) {
iot_printf("waring rf beacon slot overlap with CSMA slot. "
"TDMA slot:%lu, rf beacon slot:%lu\n",
start_offset, rf_start_offset);
cmd->rf_end_t = start_offset;
}
/* new cmd */
cnt++;
cmd++;
/* prepare tdma slot */
if (ts->tdma_slot_dur) {
/* prepare tdma for cco device */
for (i = 0; i < ts->cco_bc_cnt; i++) {
start_offset += ts->tdma_slot_dur;
}
cmd->rf_end_t = start_offset;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_tdma_q(rf_vdev);
cnt++;
cmd++;
/* prepare tdma for pco and sta device */
if (ts->non_cco_bc_info.bc_cnt) {
start_offset += ts->tdma_slot_dur * ts->non_cco_bc_info.bc_cnt;
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
}
}
/* prepare csma slot */
judge_ntb = start_offset;
for (i = 0; i < ts->csma_info.phase_cnt; i++) {
start_offset += ts->csma_info.slot_dur[i];
}
/* judge csma exist */
if (judge_ntb != start_offset) {
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
cmd->rf_end_t = start_offset - MAC_RF_SCHED_CSMA_GAP_MS;
cnt++;
cmd++;
if (MAC_RF_SCHED_CSMA_GAP_MS) {
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
}
}
/* prepare dedicated csma slot */
judge_ntb = start_offset;
for (i = 0; i < ts->d_csma_info.phase_cnt; i++) {
start_offset += ts->d_csma_info.slot_dur[i];
}
/* judge dcsma exist */
if (judge_ntb != start_offset) {
cmd->rf_tx_q_en_bm = mac_rf_sched_get_dcsma_q(rf_vdev);
cmd->rf_end_t = start_offset - MAC_RF_SCHED_CSMA_GAP_MS;
cnt++;
cmd++;
if (MAC_RF_SCHED_CSMA_GAP_MS) {
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
}
}
uint64_t tmp_ntb = next_start_ntb64 - start_ntb64;
IOT_ASSERT(iot_uint64_higher32(tmp_ntb) == 0);
uint32_t end_offset = MAC_NTB_TO_MS(iot_uint64_lower32(tmp_ntb));
/* if there is a hole form the current config beacon peirod to
* next beacon period
*/
if (end_offset > start_offset) {
start_offset = end_offset;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
}
uint32_t hole_offset, hole_csma_cnt, hole_remain, more = 0;
uint64_t cur_ntb = mac_rf_sched_get_ntb64(rf_vdev);
/* if there is a hole from current ntb to the current beacon period */
if ((cur_ntb + MAC_RF_SCHED_INSERT_CSMA_TH) < start_ntb64) {
tmp_ntb = start_ntb64 - cur_ntb;
iot_printf("%s insert csma %lu ms into hole from %lu to %lu\n",
__FUNCTION__, MAC_NTB_TO_MS((uint32_t)tmp_ntb),
iot_uint64_lower32(cur_ntb),
iot_uint64_lower32(start_ntb64));
hole_offset = (uint32_t)MAC_NTB_TO_MS(tmp_ntb) -
MAC_RF_SCHED_PREPARE_CSMA_RESV_MS - MAC_RF_SCHED_CSMA_GAP_MS;
i = 0;
start_offset = 0;
if (hole_offset > MAC_RF_MAX_SLOT_DUR) {
hole_csma_cnt = hole_offset / MAC_RF_MAX_SLOT_DUR;
hole_remain = hole_offset % MAC_RF_MAX_SLOT_DUR;
if (hole_remain > MAC_RF_SLOT_DUR) {
more = 1;
}
/* try to insert csma command put as many as possible */
IOT_ASSERT(hole_csma_cnt + more + 1 < HW_SCHED_CMD_MAX_CNT);
os_mem_move(&cl->cmd[hole_csma_cnt + more + 1], &cl->cmd[0],
sizeof(cl->cmd[0]) * cnt);
cmd = cl->cmd;
while (i < hole_csma_cnt) {
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
start_offset += MAC_RF_MAX_SLOT_DUR;
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
i++;
}
if (hole_remain > MAC_RF_SLOT_DUR) {
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
start_offset += hole_remain;
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
i++;
} else {
cmd--;
start_offset += hole_remain;
cmd->rf_end_t = start_offset;
cmd++;
}
} else {
/* try to insert csma command put as many as possible */
os_mem_move(&cl->cmd[2], &cl->cmd[0], sizeof(cl->cmd[0]) * cnt);
cmd = cl->cmd;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
start_offset += hole_offset;
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
i++;
}
/* disable tx for the last csma command before beacon region.
* see MAC_SCHED_CSMA_GAP_MS for more info.
*/
start_offset += MAC_RF_SCHED_CSMA_GAP_MS;
cmd->rf_end_t = start_offset;
cmd->rf_tx_q_en_bm = 0;
cnt++;
cmd++;
i++;
/* fix the end offset of following commands */
for (; i < cnt; i++) {
cmd->rf_end_t += start_offset;
cmd++;
}
cl->start_ntb -= (uint32_t)(tmp_ntb -
MAC_MS_TO_NTB(MAC_RF_SCHED_PREPARE_CSMA_RESV_MS));
}
IOT_ASSERT(cnt <= HW_SCHED_CMD_MAX_CNT);
cl->total_cnt = cnt;
mac_rf_sched_dump(cl, cnt);
mac_rf_sched_offset_switch(cl, cnt);
mac_rf_sched_load_cmd_list(rf_vdev, cl);
mac_rf_sched_enable_bp(rf_vdev, 1);
}
void mac_rf_sched_cco_bc_alert(mac_rf_vdev_t *rf_vdev, uint8_t cco_started)
{
uint64_t tmp;
if (!cco_started) {
tmp = mac_rf_sched_get_ntb64(rf_vdev) +
MAC_MS_TO_NTB(MAC_BP_AHEAD_ALERT_DUR);
/* rf schedule set csma only */
mac_rf_sched_set_csma_only(rf_vdev, tmp, 0);
}
}
#else /* PLC_SUPPORT_CCO_ROLE */
/* cco role device need to take care of both phase and band config */
void mac_rf_sched_cco_set(mac_rf_vdev_t *rf_vdev, mac_bc_time_slot_t *ts,
uint64_t start_ntb64, uint64_t next_start_ntb64)
{
(void)rf_vdev;
(void)ts;
(void)start_ntb64;
(void)next_start_ntb64;
IOT_ASSERT(0);
}
void mac_rf_sched_cco_bc_alert(mac_rf_vdev_t *rf_vdev, uint8_t cco_started)
{
(void)rf_vdev;
(void)cco_started;
}
#endif /* PLC_SUPPORT_CCO_ROLE */
/* sta device need to take care of band config */
uint32_t mac_rf_sched_sta_set(mac_rf_vdev_t *rf_vdev, mac_bc_time_slot_t *ts,
uint32_t start_ntb, uint8_t need_early_stop)
{
uint16_t i, j, cnt = 0;
uint8_t new_cmd_required = 0, csma_is_exist = 0;
uint32_t start_offset = 0, rf_start_offset = 0, judge_ntb = 0;
hw_sched_cmd_list_t *cl = NULL;
uint32_t rf_bc_slot_dur = ts->rf_bc_slot_dur;
/* clear flag every time */
rf_vdev->bcsma_slot_exist = 0;
IOT_ASSERT(rf_vdev);
mac_rf_sched_ctx_t *ctx = rf_vdev->rf_sched_ctx;
hw_sched_cmd_t *cmd;
uint32_t sta_tx_type = BEACON_TX_ONLY_HPLC;
tei_t self_tei = rf_vdev_get_tei(rf_vdev);
cl = mac_rf_sched_alloc_cmd_list(rf_vdev);
IOT_ASSERT(cl);
ctx->curr_hw_cmd_list = cl;
cl->start_ntb = start_ntb;
cmd = cl->cmd;
//TODO: dbg for hw sched
cl->alloc_ntb = mac_rf_sched_get_ntb(rf_vdev);
cl->caller = 2;
/* prepare central beacon slot */
if (ts->bc_slot_dur) {
start_offset += ts->bc_slot_dur * ts->cco_bc_cnt;
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
/* check rf bc slot duration */
if (rf_bc_slot_dur < MAC_RF_BC_SLOT_DUR_MIN) {
/* align with bc slot */
rf_bc_slot_dur = iot_ceil(MAC_RF_BC_SLOT_DUR_MIN, ts->bc_slot_dur) *
ts->bc_slot_dur;
}
}
if (!ts->non_cco_bc_info.tei_valid || (self_tei == PLC_TEI_INVAL)) {
/* if non bc cnt is not 0, need occupied */
if (ts->non_cco_bc_info.bc_cnt) {
start_offset += ts->bc_slot_dur * ts->non_cco_bc_info.bc_cnt;
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
}
goto bc_done;
}
/* prepere proxy and discovery beacon slot */
for (i = 0; i < ts->non_cco_bc_info.bc_cnt; i++) {
if (ts->non_cco_bc_info.sta[i].tei == self_tei) {
uint16_t tx_flag = ts->non_cco_bc_info.sta[i].tx_flag;
sta_tx_type = (uint32_t)tx_flag;
/* we think the normal process must be that BEACON_TX_HPLC_RF
* or BEACON_TX_HPLC_SIMPLE_RF comes first. otherwise it is an
* abnormal slot configuration, we just config slot, do not
* enable hwq_bitmap.
* NOTE: if BEACON_TX_ONLY_HPLC comes first, the next slot is
* BEACON_TX_ONLY_RF, and tei is same. we think that this case is a
* BEACON_TX_HPLC_RF. enable hwq_bitmap according to the case of
* BEACON_TX_HPLC_RF.
* if BEACON_TX_ONLY_RF comes first, maybe cco just want sta to send
* rf beacon, we also enable hwq_bitmap.
*/
switch (tx_flag) {
case BEACON_TX_ONLY_HPLC:
{
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
j = i + 1;
/* judge i + 1 slot */
if (j < ts->non_cco_bc_info.bc_cnt) {
tx_flag = ts->non_cco_bc_info.sta[j].tx_flag;
if (ts->non_cco_bc_info.sta[j].tei == self_tei && tx_flag ==
BEACON_TX_ONLY_RF) {
sta_tx_type = BEACON_TX_HPLC_RF;
/* new cmd */
cnt++;
cmd++;
cmd->rf_tx_q_en_bm =
mac_rf_sched_get_wb_bc_q(rf_vdev);
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
for (j = j + 1; j < ts->non_cco_bc_info.bc_cnt; j++) {
tx_flag = ts->non_cco_bc_info.sta[j].tx_flag;
if (ts->non_cco_bc_info.sta[j].tei == self_tei &&
tx_flag == BEACON_TX_ONLY_RF) {
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
} else {
break;
}
}
if (j < ts->non_cco_bc_info.bc_cnt) {
/* new cmd */
cnt++;
cmd++;
}
}
}
if (j < ts->non_cco_bc_info.bc_cnt) {
for (; j < ts->non_cco_bc_info.bc_cnt; j++) {
tx_flag = ts->non_cco_bc_info.sta[j].tx_flag;
if (ts->non_cco_bc_info.sta[j].tei == self_tei) {
iot_printf("%s warning, hplc only err tei:%lu, "
"type:%lu, st pos:%lu, cur pos:%lu\n",
__FUNCTION__, ts->non_cco_bc_info.sta[j].tei,
ts->non_cco_bc_info.sta[j].tx_flag, i, j);
}
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
}
}
new_cmd_required = 1;
break;
}
case BEACON_TX_ONLY_RF:
{
/* normally, this type does not come first */
iot_printf("%s warning abnomal type:%lu, tei:%lu, pos:%lu\n",
__FUNCTION__, tx_flag,
ts->non_cco_bc_info.sta[i].tei, i);
/* new cmd */
cnt++;
cmd++;
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_wb_bc_q(rf_vdev);
for (j = i + 1; j < ts->non_cco_bc_info.bc_cnt; j++) {
tx_flag = ts->non_cco_bc_info.sta[j].tx_flag;
if ((BEACON_TX_ONLY_RF != tx_flag) ||
(ts->non_cco_bc_info.sta[j].tei != self_tei)) {
break;
}
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
}
if (j < ts->non_cco_bc_info.bc_cnt) {
cnt++;
cmd++;
start_offset += ts->bc_slot_dur *
(ts->non_cco_bc_info.bc_cnt - j);
cmd->rf_end_t = start_offset;
}
new_cmd_required = 1;
break;
}
case BEACON_TX_HPLC_RF:
case BEACON_TX_HPLC_RF_SYNC:
{
if (tx_flag == BEACON_TX_HPLC_RF) {
/* send rf package after the current slot ends */
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
/* new cmd */
cnt++;
cmd++;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_wb_bc_q(rf_vdev);
rf_start_offset = start_offset;
rf_start_offset += rf_bc_slot_dur;
cmd->rf_end_t = rf_start_offset;
} else {
/* new cmd */
cnt++;
cmd++;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_wb_bc_q(rf_vdev);
rf_start_offset = start_offset;
rf_start_offset += rf_bc_slot_dur;
cmd->rf_end_t = rf_start_offset;
start_offset += ts->bc_slot_dur;
}
new_cmd_required = 1;
/* check that the time slot is correct */
for (j = i + 1; j < ts->non_cco_bc_info.bc_cnt; j++) {
tx_flag = ts->non_cco_bc_info.sta[j].tx_flag;
if (ts->non_cco_bc_info.sta[j].tei == self_tei) {
if (BEACON_TX_ONLY_RF != tx_flag) {
iot_printf("%s warning tx std bcn abnormal "
"tei:%lu, type:%lu, std pos:%lu, "
"cur pos:%lu\n",
__FUNCTION__,
ts->non_cco_bc_info.sta[j].tei, tx_flag,
i, j);
}
}
start_offset += ts->bc_slot_dur;
/* ensure standard rf slot does not overlap with
* other node slots.
*/
if (start_offset >= rf_start_offset) {
if (ts->non_cco_bc_info.sta[j].tei != self_tei &&
BEACON_TX_ONLY_RF == tx_flag &&
(start_offset - ts->bc_slot_dur) <
rf_start_offset) {
/* rf_bc_slot_dur is not an integer
* multiple of bc_slot_dur
*/
iot_printf("%s, warning std bcn miscfg, "
"self tei:%lu, self type:%lu, "
"conflict tei:%lu, tx type:%lu, "
"start_offset:%lu, rf_start_offset:%lu, "
"bc_slot_dur:%lu, std pos:%lu, cur pos:%lu\n",
__FUNCTION__,
ts->non_cco_bc_info.sta[i].tei,
ts->non_cco_bc_info.sta[i].tx_flag,
ts->non_cco_bc_info.sta[j].tei,
ts->non_cco_bc_info.sta[j].tx_flag,
start_offset, rf_start_offset, ts->bc_slot_dur,
i, j);
}
if (new_cmd_required) {
cnt++;
cmd++;
new_cmd_required = 0;
}
cmd->rf_end_t = start_offset;
} else {
/* just check tei different, the same tei situation
* has been detected previously.
*/
if (ts->non_cco_bc_info.sta[j].tei != self_tei) {
if (tx_flag != BEACON_TX_HPLC_CSMA_SIMPLE_RF &&
tx_flag != BEACON_TX_ONLY_HPLC) {
/* if come here, indicate that rf node slots
* overlap each other and may be misconfigured
*/
iot_printf("%s, warning std bcn miscfg, "
"self tei:%lu, self type:%lu, "
"conflict tei:%lu, tx type:%lu, "
"start_offset:%lu, rf_start_offset:%lu,"
" std pos:%lu, cur pos:%lu\n",
__FUNCTION__,
ts->non_cco_bc_info.sta[i].tei,
ts->non_cco_bc_info.sta[i].tx_flag,
ts->non_cco_bc_info.sta[j].tei,
ts->non_cco_bc_info.sta[j].tx_flag,
start_offset, rf_start_offset, i, j);
// TODO: maybe do something to backoff other slot
}
}
}
}
/* if the rf_bc_slot_dur exceeds the entire non bc period,
* we consider this is unreasonable, need print and handle.
*/
if (start_offset < rf_start_offset) {
iot_printf("%s warning std rf cfg is err, self tei:%lu"
" config_rf:%lu, etr_non_pd:%lu\n",
__FUNCTION__, self_tei, rf_start_offset, start_offset);
/* fix hplc+rf test bed STA slot time management case fail,
* pco dev is not assigned rf tdma slot to send rf beacon.
* ensure that rf beacon has enought time slot, allow
* this TDMA time slot overlapped with following time slot.
*/
if (mac_get_cert_test_flag()) {
start_offset = rf_start_offset;
cmd->rf_end_t = start_offset;
} else {
/* ensure that the TDMA time slot does not
* exceed the CSMA time slot.
*/
rf_start_offset = start_offset;
cmd->rf_end_t = rf_start_offset;
}
}
new_cmd_required = 1;
break;
}
case BEACON_TX_HPLC_SIMPLE_RF:
{
/* send rf package after the current slot ends */
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
/* new cmd */
cnt++;
cmd++;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_wb_bc_q(rf_vdev);
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
/* judge i + 1 slot */
if (i + 1 < ts->non_cco_bc_info.bc_cnt) {
tx_flag = ts->non_cco_bc_info.sta[i + 1].tx_flag;
if (ts->non_cco_bc_info.sta[i + 1].tei == self_tei) {
if (BEACON_TX_ONLY_RF != tx_flag) {
iot_printf("%s warning next simple bcn err tei:%lu, "
"type:%lu, simple pos:%lu, cur pos:%lu\n",
__FUNCTION__, ts->non_cco_bc_info.sta[i+ 1].tei,
tx_flag, i, i + 1);
}
} else {
if (BEACON_TX_ONLY_RF == tx_flag) {
iot_printf("%s warning next simple, self tei:%lu, "
"type:%lu, conflict tei:%lu, type:%lu, "
"simple pos:%lu, rf pos:%lu\n",
__FUNCTION__,
ts->non_cco_bc_info.sta[i].tei,
ts->non_cco_bc_info.sta[i].tx_flag,
ts->non_cco_bc_info.sta[i + 1].tei,
ts->non_cco_bc_info.sta[i + 1].tx_flag,
i, i + 1);
}
}
} else {
iot_printf("%s warning simple bcn err, slot empty tei:%lu, "
"type:%lu, simple pos:%lu, non bc cnt:%lu\n",
__FUNCTION__, ts->non_cco_bc_info.sta[i].tei,
ts->non_cco_bc_info.sta[i].tx_flag,
i, ts->non_cco_bc_info.bc_cnt);
}
/* check that the time slot is correct */
for (j = i + 2; j < ts->non_cco_bc_info.bc_cnt; j++) {
if (ts->non_cco_bc_info.sta[j].tei == self_tei) {
iot_printf("%s warning simple bcn err tei:%lu, "
"type:%lu, simple pos:%lu, cur pos:%lu\n",
__FUNCTION__, ts->non_cco_bc_info.sta[j].tei,
tx_flag, i, j);
}
if (new_cmd_required) {
cnt++;
cmd++;
new_cmd_required = 0;
}
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
}
new_cmd_required = 1;
break;
}
case BEACON_TX_HPLC_CSMA_SIMPLE_RF:
{
/* don't do anything, just complete the entire cmd */
for (j = i; j < ts->non_cco_bc_info.bc_cnt; j++) {
if (j > i && ts->non_cco_bc_info.sta[j].tei == self_tei) {
iot_printf("%s warning, csma rf err tei:%lu, "
"type:%lu, csma pos:%lu, cur pos:%lu\n",
__FUNCTION__, ts->non_cco_bc_info.sta[j].tei,
ts->non_cco_bc_info.sta[j].tx_flag, i, j);
}
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
}
new_cmd_required = 1;
break;
}
case BEACON_TX_HPLC_SIMPLE_RF_SYNC:
{
/* new cmd */
cnt++;
cmd++;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_wb_bc_q(rf_vdev);
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
/* check that the time slot is correct */
for (j = i + 1; j < ts->non_cco_bc_info.bc_cnt; j++) {
if (new_cmd_required) {
cnt++;
cmd++;
new_cmd_required = 0;
}
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
}
new_cmd_required = 1;
break;
}
default:
sta_tx_type = BEACON_TX_ONLY_HPLC;
iot_printf("%s warning abnomal type:%lu\n",
__FUNCTION__, tx_flag);
/* new cmd */
cnt++;
cmd++;
start_offset += ts->bc_slot_dur *
(ts->non_cco_bc_info.bc_cnt - i);
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
break;
}
/* break i loop */
break;
} else {
start_offset += ts->bc_slot_dur;
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
}
}
bc_done:
if (new_cmd_required) {
cnt++;
cmd++;
new_cmd_required = 0;
}
/* prepare tdma slot
* TODO: current do not support tdma.
*/
if (ts->tdma_slot_dur) {
start_offset += ts->tdma_slot_dur * ts->cco_bc_cnt;
start_offset += ts->tdma_slot_dur * ts->non_cco_bc_info.bc_cnt;
cmd->rf_end_t = start_offset;
new_cmd_required = 1;
}
if (new_cmd_required) {
cnt++;
cmd++;
new_cmd_required = 0;
}
/* prepare csma slot */
judge_ntb = start_offset;
for (i = 0; i < ts->csma_info.phase_cnt; i++) {
start_offset += ts->csma_info.slot_dur[i];
}
/* judge csma exist */
if (judge_ntb != start_offset) {
csma_is_exist = 1;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
cmd->rf_end_t = start_offset - MAC_RF_SCHED_CSMA_GAP_MS;
cnt++;
cmd++;
if (MAC_RF_SCHED_CSMA_GAP_MS) {
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
}
}
/* prepare dedicated csma slot */
judge_ntb = start_offset;
for (i = 0; i < ts->d_csma_info.phase_cnt; i++) {
start_offset += ts->d_csma_info.slot_dur[i];
}
/* judge dcsma exist */
if (judge_ntb != start_offset) {
csma_is_exist = 1;
cmd->rf_tx_q_en_bm = mac_rf_sched_get_dcsma_q(rf_vdev);
rf_vdev->bcsma_slot_exist = 1;
cmd->rf_end_t = start_offset - MAC_RF_SCHED_CSMA_GAP_MS;
cnt++;
cmd++;
if (MAC_RF_SCHED_CSMA_GAP_MS) {
cmd->rf_end_t = start_offset;
cnt++;
cmd++;
}
}
/* check cmd list */
if (start_offset != ts->bc_period) {
iot_printf("%s, cfg err, cfg ntb:%lu, bc pb:%lu\n",
__FUNCTION__, start_offset, ts->bc_period);
if (start_offset + MAC_RF_SCHED_CSMA_GAP_MS < ts->bc_period &&
csma_is_exist) {
start_offset = ts->bc_period;
if (MAC_RF_SCHED_CSMA_GAP_MS) {
cmd--;
cmd--;
cmd->rf_end_t = start_offset - MAC_RF_SCHED_CSMA_GAP_MS;
cmd++;
cmd->rf_end_t = start_offset;
cmd++;
} else {
cmd--;
cmd->rf_end_t = start_offset;
cmd++;
}
}
}
IOT_ASSERT(cnt <= HW_SCHED_CMD_MAX_CNT);
cl->total_cnt = cnt;
mac_rf_sched_offset_switch(cl, cnt);
if (need_early_stop) {
cl->cmd[cl->total_cnt - 1].rf_end_t -=
MAC_MS_TO_NTB(MAC_EARLY_STOP_CMDLIST_T_MS);
}
mac_rf_sched_dump(cl, cnt);
mac_rf_sched_load_cmd_list(rf_vdev, cl);
mac_rf_sched_enable_bp(rf_vdev, 1);
return sta_tx_type;
}
void mac_rf_sched_sta_bc_alert(mac_rf_vdev_t *rf_vdev, mac_bc_time_slot_t *ts,
uint64_t start_ntb, uint8_t ts_reuse, uint32_t tx_resus)
{
mac_rf_pdev_t *rf_pdev;
if (ts_reuse && tx_resus) {
/* flush tdma hwq */
rf_pdev = get_rf_pdev_ptr(PLC_PDEV_ID, rf_vdev->ref_pdev_id);
mac_rf_tx_flush_all_tdma_queue(&rf_pdev->hwq_hdl);
/* rf schedule support */
mac_rf_sched_sta_set(rf_vdev, ts, iot_uint64_lower32(start_ntb), 0);
} else {
/* rf schedule support */
mac_rf_sched_set_csma_only(rf_vdev, start_ntb, (uint8_t)tx_resus);
}
}
void mac_rf_sched_stop(mac_rf_vdev_t *rf_vdev)
{
mac_rf_sched_ctx_t *ctx = rf_vdev->rf_sched_ctx;
/* stop scheduler */
mac_rf_sched_enable_bp(rf_vdev, 0);
/* clean up command list */
mac_rf_sched_free_cmd_list(rf_vdev);
ctx->curr_hw_cmd_list = NULL;
}
/* set scheduler to work in csma only mode */
static void mac_rf_sched_set_csma_only_intern(mac_rf_vdev_t *rf_vdev,
mac_bc_cmsa_si_t *csma, uint64_t start_ntb, uint8_t enable_tx)
{
uint16_t start_offset, cnt;
hw_sched_cmd_list_t *cl = NULL;
mac_rf_sched_ctx_t *ctx = rf_vdev->rf_sched_ctx;
hw_sched_cmd_t *cmd;
/* clear flag every time */
rf_vdev->bcsma_slot_exist = 0;
cl = mac_rf_sched_alloc_cmd_list(rf_vdev);
ctx->curr_hw_cmd_list = cl;
IOT_ASSERT(cl);
cl->start_ntb = iot_uint64_lower32(start_ntb);
cl->start_ntb_h = iot_uint64_higher32(start_ntb);
cmd = cl->cmd;
cnt = 0;
start_offset = 0;
//TODO: dbg for hw sched
cl->alloc_ntb = mac_rf_sched_get_ntb(rf_vdev);
cl->caller = 3;
if (enable_tx) {
cmd->rf_tx_q_en_bm = mac_rf_sched_get_csma_q(rf_vdev);
}
#if PLC_SUPPORT_DBG_PKT_MODE
/* if and only if it's STA/PCO dev, and not blocking dbg pkt sch
* in rx only period
*/
else {
cmd->rf_tx_q_en_bm = mac_rf_sched_get_dbg_q(rf_vdev);
}
#endif
start_offset += (uint16_t)csma->slot_dur[0];
cmd->rf_end_t = start_offset;
cnt++;
mac_rf_sched_dump(cl, cnt);
/* for csma only mode, make sure cmd list is short enough */
IOT_ASSERT(cnt < HW_SHCED_CMD_DEPTH);
cl->total_cnt = cnt;
mac_rf_sched_offset_switch(cl, cnt);
/* load command list of next beacon period */
mac_rf_sched_load_cmd_list(rf_vdev, cl);
/* start HW scheduler */
mac_rf_sched_enable_bp(rf_vdev, 1);
}
void mac_rf_sched_set_csma_only(mac_rf_vdev_t *rf_vdev, uint64_t start_ntb,
uint8_t enable_tx)
{
mac_bc_cmsa_si_t csma;
/* config HW scheduler to RX only mode */
/* for one phase cco device and sta device */
csma.phase_cnt = 1;
csma.slot_dur[0] = MAC_CSMA_ONLY_PEIROD_MS;
mac_rf_sched_set_csma_only_intern(rf_vdev, &csma, start_ntb, enable_tx);
}
void mac_rf_sched_init(mac_rf_vdev_t *rf_vdev)
{
rf_vdev->rf_sched_ctx = os_mem_malloc(PLC_MAC_SCHED_MID,
sizeof(mac_rf_sched_ctx_t));
IOT_ASSERT(rf_vdev->rf_sched_ctx);
}
#endif /* HPLC_RF_DEV_SUPPORT */