1232 lines
42 KiB
C
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 */
|
|
|