476 lines
14 KiB
C
Executable File
476 lines
14 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.
|
|
|
|
****************************************************************************/
|
|
|
|
/* os shim includes */
|
|
#include "os_types.h"
|
|
|
|
/* mac module internal includes */
|
|
#include "mac_vdev.h"
|
|
#include "mac_pdev.h"
|
|
#include "command_list.h"
|
|
#include "hw_reg_api.h"
|
|
#include "mac_sys_reg.h"
|
|
#include "mac_hwq_reg.h"
|
|
#include "os_task.h"
|
|
|
|
#if MAC_SCHED_HW_DEBUG || ENA_WAR_911
|
|
#include "iot_io.h"
|
|
#endif
|
|
|
|
/* public api includes */
|
|
#include "plc_fr.h"
|
|
|
|
#include "mac_status.h"
|
|
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
|
|
#if ENA_WAR_440
|
|
#include "phy_bb.h"
|
|
#endif
|
|
|
|
void mac_sched_enable_hw_ntb_sync(mac_vdev_t *vdev, uint8_t enable)
|
|
{
|
|
uint32_t value;
|
|
|
|
/* disable irq */
|
|
os_disable_irq();
|
|
|
|
value = RGF_MAC_READ_REG(CFG_NTB_SYNC_0_ADDR);
|
|
if (enable) {
|
|
REG_FIELD_SET(CFG_HW_NTB_SYNC_EN, value, 1);
|
|
REG_FIELD_SET(CFG_NTB_SW_SYNC_CLR, value, 1);
|
|
} else {
|
|
REG_FIELD_SET(CFG_HW_NTB_SYNC_EN, value, 0);
|
|
REG_FIELD_SET(CFG_NTB_HW_SYNC_CLR, value, 1);
|
|
}
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_0_ADDR, value);
|
|
|
|
/* enable irq */
|
|
os_enable_irq();
|
|
}
|
|
|
|
void mac_record_sync_ntb_overflow(uint64_t st_ntb, uint32_t result)
|
|
{
|
|
/* bitmap 0 1 3 4 */
|
|
#define SYNC_OVERFLOW_NTB_WAY_1 0x1B
|
|
/* bitmap 0 1 3 5 */
|
|
#define SYNC_OVERFLOW_NTB_WAY_2 0x2B
|
|
/* bitmap 0 2 3 4 */
|
|
#define SYNC_OVERFLOW_NTB_WAY_3 0x1D
|
|
/* bitmap 0 2 3 5 */
|
|
#define SYNC_OVERFLOW_NTB_WAY_4 0x2D
|
|
/* bitmap 6 */
|
|
#define SYNC_OVERFLOW_NTB_WAY_5 0x40
|
|
mac_pdev_t *pdev = get_pdev_ptr(PLC_PDEV_ID);
|
|
mac_sync_ntb_record_t *sync_ntb_record = &pdev->mac_status.sync_ntb_record;
|
|
uint64_t cur_ntb = mac_sched_get_ntb64(NULL);
|
|
switch (result) {
|
|
case SYNC_OVERFLOW_NTB_WAY_1 :
|
|
sync_ntb_record->sync_ntb_ovf_way1_cnt++;
|
|
if (iot_uint64_higher32(cur_ntb) - iot_uint64_higher32(st_ntb) == 1) {
|
|
sync_ntb_record->way1_success_cnt++;
|
|
}
|
|
break;
|
|
case SYNC_OVERFLOW_NTB_WAY_2 :
|
|
sync_ntb_record->sync_ntb_ovf_way2_cnt++;
|
|
if (iot_uint64_higher32(cur_ntb) - iot_uint64_higher32(st_ntb) == 1) {
|
|
sync_ntb_record->way2_success_cnt++;
|
|
}
|
|
break;
|
|
case SYNC_OVERFLOW_NTB_WAY_3 :
|
|
sync_ntb_record->sync_ntb_ovf_way3_cnt++;
|
|
if (iot_uint64_higher32(cur_ntb) - iot_uint64_higher32(st_ntb) == 1) {
|
|
sync_ntb_record->way3_success_cnt++;
|
|
}
|
|
break;
|
|
case SYNC_OVERFLOW_NTB_WAY_4 :
|
|
sync_ntb_record->sync_ntb_ovf_way4_cnt++;
|
|
if (iot_uint64_higher32(cur_ntb) - iot_uint64_higher32(st_ntb) == 1) {
|
|
sync_ntb_record->way4_success_cnt++;
|
|
}
|
|
break;
|
|
case SYNC_OVERFLOW_NTB_WAY_5 :
|
|
sync_ntb_record->sync_ntb_ovf_way5_cnt++;
|
|
break;
|
|
default:
|
|
sync_ntb_record->sync_ntb_ovf_way6_cnt++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void mac_sched_sync_ntb(mac_vdev_t *vdev, uint16_t golden_gap,
|
|
int32_t ntb_delta)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
/* disable irq */
|
|
os_disable_irq();
|
|
|
|
value = RGF_MAC_READ_REG(CFG_NTB_SYNC_0_ADDR);
|
|
value |= CFG_NTB_DELTA_VAL_SIGN_MASK | CFG_MODIFY_NTB_EN_MASK;
|
|
if (golden_gap) {
|
|
/* set golden gap only when it's non-zero, this value shouldn't be
|
|
* changed once set.
|
|
*/
|
|
value &= ~CFG_NTB_GOLDEN_GAP_MASK;
|
|
value |= (((uint32_t)golden_gap) << CFG_NTB_GOLDEN_GAP_OFFSET)
|
|
& CFG_NTB_GOLDEN_GAP_MASK;
|
|
}
|
|
if (!(value & CFG_HW_NTB_SYNC_EN_MASK)) {
|
|
/* make sure HW don't sync NTB blindly */
|
|
IOT_ASSERT(RGF_MAC_READ_REG(CFG_RO_NTB_HW_SYNC_VAL_ADDR) == 0);
|
|
}
|
|
|
|
uint32_t u_ntb_delta = 0;
|
|
|
|
#if ENA_WAR_911
|
|
|
|
uint32_t result = 0;
|
|
/* war for hw bug, low bit overflow high bit not + 1 */
|
|
uint32_t ntb_delta_a = 0;
|
|
uint32_t ntb_delta_b = 0;
|
|
uint64_t cur_ntb = mac_sched_get_ntb64(NULL);
|
|
if (ntb_delta >= 0) {
|
|
/* positive */
|
|
uint64_t temp_ntb = (uint64_t)iot_uint64_lower32(cur_ntb) + ntb_delta;
|
|
/* if overflow */
|
|
if (iot_uint64_higher32(temp_ntb) >= 1) {
|
|
result |= 1 << 0;
|
|
/* set delta part a */
|
|
ntb_delta_a = MAX_UINT32_NTB - iot_uint64_lower32(cur_ntb);
|
|
if (ntb_delta_a > (RESERVE_NTB + (RESERVE_NTB >> 1))) {
|
|
result |= 1 << 1;
|
|
ntb_delta_a = ntb_delta_a - RESERVE_NTB;
|
|
/* set part a to register */
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_1_ADDR, ntb_delta_a);
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_0_ADDR, value);
|
|
} else {
|
|
result |= 1 << 2;
|
|
ntb_delta_a = 0;
|
|
}
|
|
IOT_ASSERT(ntb_delta >= ntb_delta_a);
|
|
/* set delta part b */
|
|
ntb_delta_b = ntb_delta - ntb_delta_a;
|
|
/* delay to wait hight bit +1 */
|
|
temp_ntb = mac_sched_get_ntb64(NULL);
|
|
/* check ntb is normal */
|
|
if (iot_uint64_higher32(temp_ntb) >= iot_uint64_higher32(cur_ntb)) {
|
|
result |= 1 << 3;
|
|
/* wait overflow happen */
|
|
uint32_t time_span = 0;
|
|
uint32_t cur_ntb_temp = 0;
|
|
do {
|
|
cur_ntb_temp = mac_sched_get_ntb(NULL);
|
|
time_span = cur_ntb_temp - iot_uint64_lower32(temp_ntb);
|
|
} while (cur_ntb_temp > (MAX_UINT32_NTB >> 1) &&
|
|
time_span < DELAY_MAX_NTB);
|
|
|
|
/* check which condition jumps out of the while */
|
|
if (cur_ntb_temp < (MAX_UINT32_NTB >> 1)) {
|
|
result |= 1 << 4;
|
|
/* set delta next part */
|
|
u_ntb_delta = ntb_delta_b;
|
|
} else {
|
|
result |= 1 << 5;
|
|
/* timeout and give up this sync part b */
|
|
u_ntb_delta = 0;
|
|
iot_printf("%s wait overflow timeout\n", __FUNCTION__);
|
|
}
|
|
} else {
|
|
iot_printf("%s sync ntb error\n", __FUNCTION__);
|
|
IOT_ASSERT(0);
|
|
}
|
|
}else {
|
|
u_ntb_delta = ntb_delta;
|
|
}
|
|
} else {
|
|
/* negative */
|
|
if ((iot_uint64_lower32(cur_ntb) < (-ntb_delta)) &&
|
|
(vdev_get_tei(vdev) != PLC_TEI_INVAL)) {
|
|
result |= 1 << 6;
|
|
u_ntb_delta = iot_uint64_lower32(cur_ntb);
|
|
} else {
|
|
u_ntb_delta = MAX_UINT32_NTB + ntb_delta;
|
|
}
|
|
}
|
|
|
|
/* launch ntb delta first as enable NTB modify bit will cause HW
|
|
* launch the delta value right away.
|
|
*/
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_1_ADDR, u_ntb_delta);
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_0_ADDR, value);
|
|
|
|
/* enable irq */
|
|
os_enable_irq();
|
|
|
|
if (result) {
|
|
mac_record_sync_ntb_overflow(cur_ntb, result);
|
|
}
|
|
|
|
#else
|
|
|
|
if (ntb_delta < 0) {
|
|
u_ntb_delta = MAX_UINT32_NTB + ntb_delta;
|
|
} else {
|
|
u_ntb_delta = ntb_delta;
|
|
}
|
|
/* launch ntb delta first as enable NTB modify bit will cause HW
|
|
* launch the delta value right away.
|
|
*/
|
|
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_1_ADDR, u_ntb_delta);
|
|
RGF_MAC_WRITE_REG(CFG_NTB_SYNC_0_ADDR, value);
|
|
|
|
/* enable irq */
|
|
os_enable_irq();
|
|
|
|
#endif
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_NTB_SYNC_0_ADDR %x\n", __FUNCTION__,
|
|
value);
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_NTB_SYNC_1_ADDR %d\n", __FUNCTION__,
|
|
ntb_delta);
|
|
#endif
|
|
}
|
|
|
|
uint32_t IRAM_ATTR mac_sched_get_ntb(mac_vdev_t *vdev)
|
|
{
|
|
(void)vdev;
|
|
|
|
return RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
}
|
|
|
|
uint32_t IRAM_ATTR mac_sched_get_lts()
|
|
{
|
|
return RGF_MAC_READ_REG(CFG_RD_LOCAL_TMR_ADDR);
|
|
}
|
|
|
|
uint64_t IRAM_ATTR mac_sched_get_ntb64(mac_vdev_t *vdev)
|
|
{
|
|
uint32_t ntb;
|
|
uint64_t ntb64_a, ntb64_b;
|
|
(void)vdev;
|
|
|
|
ntb64_a = RGF_MAC_READ_REG(CFG_RO_NTB_TMR_WRAP_ADDR);
|
|
ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
ntb64_b = RGF_MAC_READ_REG(CFG_RO_NTB_TMR_WRAP_ADDR);
|
|
|
|
if (ntb64_b != ntb64_a) {
|
|
/* wrap round happened */
|
|
ntb = RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
}
|
|
ntb64_b = (ntb64_b << 32) | ntb;
|
|
|
|
return ntb64_b;
|
|
}
|
|
|
|
void mac_sched_set_bp_ahead_alert(mac_vdev_t *vdev, uint16_t ahead)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
value = (((uint32_t)ahead) << CFG_BCN_ALERT_AHEAD_OFFSET)
|
|
& CFG_BCN_ALERT_AHEAD_MASK;
|
|
RGF_MAC_WRITE_REG(CFG_BEACON_ADDR, value);
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_BEACON_ADDR %x\n", __FUNCTION__,
|
|
value);
|
|
#endif
|
|
}
|
|
|
|
void mac_sched_set_recursive_mode(mac_vdev_t *vdev, uint8_t enable)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
value &= ~CFG_SCH_SELF_RECUR_EN_MASK;
|
|
value |= ((uint32_t)(enable & 0x01)) << CFG_SCH_SELF_RECUR_EN_OFFSET;
|
|
RGF_HWQ_WRITE_REG(CFG_SCHEDULE_ADDR, value);
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_SCHEDULE_ADDR %x\n", __FUNCTION__,
|
|
value);
|
|
#endif
|
|
}
|
|
|
|
/* config start ntb of next beacon period */
|
|
void mac_sched_set_bp_start_ntb(mac_vdev_t *vdev,
|
|
uint32_t start_ntb)
|
|
{
|
|
(void)vdev;
|
|
#if ENA_WAR_440
|
|
g_phy_cpu_share_ctxt.bcn_start_update_ntb = \
|
|
RGF_MAC_READ_REG(CFG_RD_NTB_ADDR);
|
|
#endif
|
|
|
|
RGF_MAC_WRITE_REG(CFG_BCN_START_NTB_ADDR, start_ntb);
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_BCN_START_NTB_ADDR %x\n",
|
|
__FUNCTION__, start_ntb);
|
|
#endif
|
|
}
|
|
|
|
uint32_t mac_sched_get_bp_start_ntb()
|
|
{
|
|
return RGF_MAC_READ_REG(CFG_BCN_START_NTB_ADDR);
|
|
}
|
|
|
|
uint32_t mac_sched_get_bp_dur()
|
|
{
|
|
uint32_t tmp = RGF_MAC_READ_REG(CFG_BEACON_PERIOD_ADDR);
|
|
return REG_FIELD_GET(CFG_BEACON_PERIOD, tmp);
|
|
}
|
|
|
|
/* config next beacon period duration */
|
|
void mac_sched_set_bp_dur(mac_vdev_t *vdev, uint16_t bp)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
value = (((uint32_t)bp) << CFG_BEACON_PERIOD_OFFSET)
|
|
& CFG_BEACON_PERIOD_MASK;
|
|
RGF_MAC_WRITE_REG(CFG_BEACON_PERIOD_ADDR, value);
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_BEACON_PERIOD_ADDR %x\n",
|
|
__FUNCTION__, value);
|
|
#endif
|
|
}
|
|
|
|
/* config scheduler of next beacon period */
|
|
void mac_sched_set_bp_cmd_list(mac_vdev_t *vdev, hw_sched_cmd_t *cmd,
|
|
uint16_t cnt)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
value &= ~CFG_SCH_CMD_NUM_MASK;
|
|
value |= (((uint32_t)cnt << 1) << CFG_SCH_CMD_NUM_OFFSET)
|
|
& CFG_SCH_CMD_NUM_MASK;
|
|
RGF_HWQ_WRITE_REG(CFG_SCHEDULE_ADDR, value);
|
|
|
|
RGF_HWQ_WRITE_REG(CFG_SCH_PTR_ADDR, (uint32_t)cmd);
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_SCHEDULE_ADDR %x\n", __FUNCTION__,
|
|
value);
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_SCH_PTR_ADDR %x\n", __FUNCTION__,
|
|
cmd);
|
|
#endif
|
|
}
|
|
|
|
/* get cmd list cnt being used by HW */
|
|
uint8_t mac_sched_get_cmd_list_cnt(mac_vdev_t *vdev)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
value &= SCH_CUR_NUM_MASK;
|
|
value >>= SCH_CUR_NUM_OFFSET;
|
|
|
|
return (uint8_t)value;
|
|
}
|
|
|
|
/* write trigger for the next beacon period */
|
|
void mac_sched_trigger_bp(mac_vdev_t *vdev)
|
|
{
|
|
uint32_t value;
|
|
(void)vdev;
|
|
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
if (value & SCH_WR_TRIG_ENABLE_MASK) {
|
|
value |= 1 << CFG_SCH_WR_TRIG_OFFSET;
|
|
RGF_HWQ_WRITE_REG(CFG_SCHEDULE_ADDR, value);
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
}
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_SCHEDULE_ADDR %x\n", __FUNCTION__,
|
|
value);
|
|
#endif
|
|
}
|
|
|
|
#define SCHED_ENABLE_SYNC_MAX_LOOP 0xFFFFFFFE
|
|
|
|
/* enable or disable scheduler of next beacon period */
|
|
void mac_sched_enable_bp(mac_vdev_t *vdev, uint8_t enable)
|
|
{
|
|
uint32_t i, value;
|
|
(void)vdev;
|
|
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
/* check if HW scheduler already enabled or disabled */
|
|
if ((!!(value & SCH_STATUS_MASK)) == (!!enable))
|
|
return;
|
|
|
|
/* enable or disable HW scheduler */
|
|
value &= ~CFG_SCH_EN_MASK;
|
|
value |= (((uint32_t)(enable & 0x01)) << CFG_SCH_EN_OFFSET)
|
|
& CFG_SCH_EN_MASK;
|
|
|
|
RGF_HWQ_WRITE_REG(CFG_SCHEDULE_ADDR, value);
|
|
|
|
#if MAC_SCHED_HW_DEBUG
|
|
iot_printf("MAC_SCHED_HW ---%s--- CFG_SCHEDULE_ADDR %x\n", __FUNCTION__,
|
|
value);
|
|
#endif
|
|
#if DEBUG_HWQ_SHCED_HANG
|
|
uint32_t debug_cnt = 0;
|
|
#endif
|
|
if (!mac_txq_is_dbg_mode()) {
|
|
/* if sch mode */
|
|
/* make sure the HW scheduler status is in sync */
|
|
for (i = 0; i < SCHED_ENABLE_SYNC_MAX_LOOP; i++) {
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
if ((!!(value & SCH_STATUS_MASK)) == (!!enable)) {
|
|
break;
|
|
}
|
|
if (i & 0x100) {
|
|
/* try to enable or disable again */
|
|
REG_FIELD_SET(CFG_SCH_EN, value, enable & 0x01);
|
|
RGF_HWQ_WRITE_REG(CFG_SCHEDULE_ADDR, value);
|
|
}
|
|
#if DEBUG_HWQ_SHCED_HANG
|
|
debug_cnt++;
|
|
if(debug_cnt > MAX_WAIT_DUMP_CNT)
|
|
{
|
|
mac_dump_buf(MAC_DUMP_TYPE_5, NULL, 0, \
|
|
(uint32_t *)RGF_HWQ_BASEADDR, 108, \
|
|
(uint32_t *)RGF_RX_BASEADDR, 69, true);
|
|
}
|
|
#endif
|
|
}
|
|
if (i >= SCHED_ENABLE_SYNC_MAX_LOOP)
|
|
IOT_ASSERT(0);
|
|
}
|
|
|
|
if (!enable) {
|
|
/* clear schduler command list if scheduler disabled */
|
|
value = RGF_HWQ_READ_REG(CFG_SCHEDULE_ADDR);
|
|
value |= CFG_SCH_CLR_MASK;
|
|
RGF_HWQ_WRITE_REG(CFG_SCHEDULE_ADDR, value);
|
|
}
|
|
}
|
|
|
|
#endif /* HW_PLATFORM >= HW_PLATFORM_FPGA */
|