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

544 lines
16 KiB
C
Executable File

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "sw_sched.h"
#include "iot_errno.h"
#include "mac_msg.h"
#include "mac.h"
#include "mac_hwq_mgr.h"
#include "mac_stream.h"
#include "mac_pdev.h"
#include "mac_desc_engine.h"
#include "hw_tonemap.h"
#include "rate_control.h"
#include "mac_tx_hw.h"
#include "mac_msdu.h"
#include "iot_bitops.h"
#include "phy_chn.h"
#include "iot_io.h"
#include "mac_peer.h"
#include "mac_tx_power.h"
#include "mac_rf.h"
mac_swq_t * g_mac_swq[MAX_MAC_QUE_NUM]={0};
#if HPLC_RF_DEV_SUPPORT
#include "mac_rf_common_hw.h"
#include "rf_hw_tonemap.h"
#include "rf_rate_control.h"
mac_swq_t * g_mac_rf_swq[MAX_MAC_RF_QUE_NUM] = {0};
uint32_t mac_rf_swsch_init()
{
uint32_t type;
iot_printf("%s\n", __FUNCTION__);
for (type = 0; type < MAX_MAC_RF_QUE_NUM; type++) {
g_mac_rf_swq[type] = os_mem_malloc(PLC_MAC_SHC_MID,
sizeof(mac_swq_t));
IOT_ASSERT(g_mac_rf_swq[type]);
g_mac_rf_swq[type]->q_depth = 0;
iot_list_init(&g_mac_rf_swq[type]->stream_list);
}
return 0;
}
uint32_t mac_rf_swsch_trigger_tx(pdevid_t rf_pdev_id, vdevid_t rf_vdev_id)
{
uint32_t ret = ERR_OK;
mac_rf_vdev_t *rf_vdev = get_rf_vdev_ptr(PLC_PDEV_ID, rf_pdev_id,
rf_vdev_id);
IOT_ASSERT(rf_vdev);
if (rf_vdev->stop_flag == 0) {
//iot_printf("%s\n", __FUNCTION__);
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->type = MAC_MSG_TYPE_SCH;
msg->id = MAC_MSG_ID_SCH_TX;
msg->data1 = (((uint32_t)rf_pdev_id) << 8) | rf_vdev_id;
msg->data2 = NULL;
msg->data3 = NULL;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
} else {
ret = ERR_FAIL;
}
out:
return ret;
}
uint32_t mac_rf_swsch_tx_msdu(mac_rf_pdev_t *rf_pdev, mac_msdu_t *msdu,
uint32_t delimiter_type, tei_t dtei, lid_t lid, uint8_t is_bcast)
{
uint8_t blkz = 0;
uint32_t pbsz = 0;
uint8_t phr_mcs = 0;
uint8_t mcs = 0;
nid_t nid = 0;
mac_vdev_t *vdev = NULL;
uint32_t option = mac_rf_get_self_option();
/* get msdu len && all pb num */
uint32_t msdu_len = iot_pkt_data_len(msdu->buf);
/* get block size, pb size, phy header mcs , plc mcs */
mac_rf_data_get_rate(msdu_len, option, is_bcast, &blkz, &phr_mcs, &mcs,
msdu->retry_cnt, dtei);
pbsz = phy_rf_get_pbsz(blkz);
if (msdu->is_dbg_pkt) {
mac_pdev_t *pdev = get_pdev_ptr(rf_pdev->parent_pdev_id);
vdev = get_vdev_ptr(rf_pdev->parent_pdev_id, pdev->dbg_pkt_vdev_id);
} else {
vdev = get_vdev_ptr(rf_pdev->parent_pdev_id, PLC_DEFAULT_VDEV);
}
tei_t stei = vdev_get_tei(vdev);
/* get nid */
vdev_get_nid(vdev, &nid);
return mac_tx_rf_msdu(rf_pdev, msdu, option, delimiter_type, dtei,
lid, is_bcast, nid, stei, blkz, pbsz, phr_mcs, mcs, msdu_len);
}
#endif /* HPLC_RF_DEV_SUPPORT */
mac_swq_t * mac_swsch_get_g_swq(uint32_t swq_id, uint32_t is_rf)
{
mac_swq_t *swq = NULL;
#if HPLC_RF_DEV_SUPPORT
swq = ((is_rf) ? g_mac_rf_swq[(swq_id)] : g_mac_swq[(swq_id)]);
#else /* HPLC_RF_DEV_SUPPORT */
swq = ((is_rf) ? NULL : g_mac_swq[(swq_id)]);
#endif /* HPLC_RF_DEV_SUPPORT */
return swq;
}
uint32_t mac_swsch_init()
{
uint32_t type;
iot_printf("%s\n", __FUNCTION__);
#if 1
for(type = 0; type < MAX_MAC_QUE_NUM; type++)
{
g_mac_swq[type] = os_mem_malloc(PLC_MAC_SHC_MID,sizeof(mac_swq_t));
IOT_ASSERT(g_mac_swq[type]);
g_mac_swq[type]->q_depth = 0;
iot_list_init(&g_mac_swq[type]->stream_list);
}
#endif
return 0;
}
uint32_t mac_swsch_trigger_tx(pdevid_t pdev_id, vdevid_t vdev_id)
{
/* send a MAC_MSG_TYPE_SCH : MAC_MSG_ID_SCH_TX*/
uint32_t ret = 0;
mac_vdev_t * vdev = g_mac_pdev[pdev_id]->vdev[vdev_id];
if(vdev->stop_flag == 0){
//iot_printf("%s\n", __FUNCTION__);
mac_msg_t *msg = mac_alloc_msg();
if (msg == NULL) {
IOT_ASSERT(0);
ret = ERR_NOMEM;
goto out;
}
msg->type = MAC_MSG_TYPE_SCH;
msg->id = MAC_MSG_ID_SCH_TX;
msg->data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->data2 = NULL;
msg->data3 = NULL;
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
}
out:
return ret;
}
uint32_t mac_swsch_append(mac_swq_t *swq, phase_t phase, mac_stream_t *node)
{
/* TODO: */
IOT_ASSERT(swq && node);
if (iot_list_empty(&swq->stream_list))
{
/* if empty */
IOT_ASSERT(0 == swq->q_depth);
}
if (node->in_swq == 0) {
/* add prev head, i.e. put to the last */
iot_list_add_prev(&node->msdu.tx.swq_node, &swq->stream_list);
swq->q_depth++;
node->phase_in_swq = phase;
node->in_swq = 1;
}
return 0;
}
uint32_t mac_swsch_remove(mac_swq_t *swq, mac_stream_t *node)
{
/* TODO: */
IOT_ASSERT(swq && node);
if (!iot_list_empty(&swq->stream_list))
{
/* if not empty */
IOT_ASSERT(swq->q_depth > 0 && node->in_swq == 1);
iot_list_del(&node->msdu.tx.swq_node);
swq->q_depth--;
node->in_swq = 0;
node->phase_in_swq = PLC_PHASE_ALL;
}
else {
/* already empty */
IOT_ASSERT(0);
}
return 0;
}
uint32_t mac_swsch_del_stream(void *stream)
{
mac_stream_t *str = (mac_stream_t *)stream;
mac_swq_t *swq_ptr = NULL;
uint32_t swq_id;
if(str->in_swq == 1) {
str->in_swq = 0;
uint32_t bcn_region_type = mac_get_bcn_region_type(str->lid);
if (str->is_rf) {
swq_id = (uint32_t)mac_rf_q_get_swq_type(bcn_region_type,
str->lid, (str->is_tx == IS_DBG_TX_STREAM));
} else {
swq_id = (uint32_t)mac_q_get_swq_type(bcn_region_type,
str->phase_in_swq, str->lid);
}
swq_ptr = mac_swsch_get_g_swq(swq_id, str->is_rf);
IOT_ASSERT(swq_ptr);
if (swq_ptr->q_depth > 0) {
//TODO: focus on the reason
swq_ptr->q_depth--;
iot_list_del(&str->msdu.tx.swq_node);
str->in_swq = 0;
str->phase_in_swq = PLC_PHASE_ALL;
}
}
return 0;
}
uint32_t mac_swsch_tx_msdu(pdevid_t pdev_id, vdevid_t vdev_id,
mac_msdu_t *msdu,uint32_t delimiter_type,
uint32_t proto,uint32_t port)
{
mac_pdev_t *pdev;
mac_vdev_t *vdev;
uint32_t ret;
uint32_t pb_num_per_mpdu;
uint32_t mpdu_num_to_send;
uint32_t tmi, ext_tmi;
uint8_t rid;
uint32_t rate_mode;
uint32_t pb_sz, old_pb_sz;
uint32_t nid;
tei_t stei;
mac_stream_t *stream = msdu->ref_mac_stream;
mac_peer_t *peer = stream->peer;
tei_t dtei = (tei_t)peer->tei;
uint32_t lid = stream->lid;
uint32_t single_proto_band;
uint8_t is_fixed_rate;
uint32_t is_fixed_pbsz;
uint32_t hw_band_id;
pdev = get_pdev_ptr(pdev_id);
if (msdu->is_dbg_pkt) {
vdev = get_vdev_ptr(pdev_id, pdev->dbg_pkt_vdev_id);
} else {
vdev = get_vdev_ptr(pdev_id, vdev_id);
}
stei = vdev_get_tei(vdev);
IOT_ASSERT(stream->msdu.tx.cur_tx_msdu);
uint8_t is_bcast =\
(uint8_t)stream->msdu.tx.cur_tx_msdu->is_bcast;
phase_t phase =\
(uint8_t)stream->msdu.tx.cur_tx_msdu->phase;
uint32_t pkt_len = iot_pkt_data_len(msdu->buf);
/* get nid */
ret = vdev_get_nid(vdev, &nid);
//TODO: need fix swsch trigger logic, need check vdev.
//IOT_ASSERT(ERR_OK == ret);
hw_band_id = mac_tx_hw_band_id_get(vdev,
phy_band_id_get(), msdu->retry_cnt);
single_proto_band = phy_hw_band_to_proto_band(hw_band_id);
/* get the rate for this mpdu */
if (!is_bcast) {
/* if uni-cast */
if (!vdev_get_fixed_rate(vdev)) {
is_fixed_rate = false;
} else {
is_fixed_rate = true;
}
if (msdu->fix_rate) {
is_fixed_rate = true;
}
#if (PLC_SUPPORT_STA_TX_3_PHASE)
if (dtei == PLC_TEI_CCO) {
is_fixed_rate = true;
}
#endif
/* only first send, allow choose the pbsz */
is_fixed_pbsz = (msdu->retry)?1:0;
ret = mac_data_get_rate(vdev, peer, proto, is_fixed_rate, pkt_len,\
single_proto_band, is_fixed_pbsz, &rid, &pb_num_per_mpdu, \
&mpdu_num_to_send, &rate_mode, (uint8_t)msdu->retry_cnt);
}
else
{
ret = mac_data_get_bcast_rate(vdev, proto, true, pkt_len,
single_proto_band, msdu->retry_cnt, &rid, &rate_mode,
&mpdu_num_to_send, &pb_num_per_mpdu, msdu->is_dbg_pkt,
msdu->retry, msdu->rd_retry_cnt);
}
IOT_ASSERT(ret == 0);
/* get pbsz, tmi and ext emi if not GP */
phy_get_tmi_by_rid(proto, rid, &tmi, &ext_tmi);
phy_get_rt_pbsz(proto, rid, &pb_sz);
#if SUPPORT_SOUTHERN_POWER_GRID
if (PLC_PROTO_TYPE_SPG == proto) {
/* for spg, one mpdu should accommodate the msdu */
IOT_ASSERT((mac_get_sof_pb_valid_payload_sz(proto, pb_sz) \
* pb_num_per_mpdu * mpdu_num_to_send) >= pkt_len);
}
#endif
#if DBG_MAC_TX_RID
iot_printf("tx msdu 0x%x's r%d->r%d, bmp=0x%x\n",
msdu, msdu->rate_idx, rid, msdu->send_bitmap);
#endif
if (msdu->send_bitmap == 0xffffffff || msdu->rate_idx == MAX_RATE_IDX) {
/* first send */
msdu->rate_idx = rid;
}
else
{
if (msdu->rate_idx != rid) {
/* if selected tmi is not the same to
* the previous one, restart the send
*/
phy_get_rt_pbsz(proto, (uint8_t)msdu->rate_idx, &old_pb_sz);
if (pb_sz != old_pb_sz) {
msdu->retry = 0;
msdu->send_bitmap = 0xffffffff;
msdu->last_pos = 0;
iot_printf("change msdu 0x%x's pbsz %d->%d\n",
msdu, old_pb_sz, pb_sz);
}
msdu->rate_idx = rid;
}
}
if (!is_bcast && msdu->retry == 0) {
/* only one mpdu for the first send of ucast */
mpdu_num_to_send = 1;
}
return mac_tx_msdu(pdev, msdu, \
pb_sz, pb_num_per_mpdu, \
mpdu_num_to_send, \
delimiter_type, nid, \
stei, dtei, lid, is_bcast, \
phase, proto, port, \
tmi, ext_tmi, rate_mode, single_proto_band);
}
//load mac_frame_list to cur_msdu
uint32_t mac_load_msdu(mac_msdu_t * cur_msdu,
mac_stream_t *stream)
{
IOT_ASSERT(cur_msdu && stream);
mac_msdu_frame_t *msdu_list = \
stream->msdu.tx.mac_frame_list;
if (msdu_list && msdu_list->buf) {
/* if has frame in the queue */
mac_msdu_init(cur_msdu, 1, stream, \
msdu_list->buf, (uint8_t)msdu_list->retry_cnt);
cur_msdu->is_bcast = \
msdu_list->is_bcast;
cur_msdu->phase = \
msdu_list->phase;
cur_msdu->tx_3phase = msdu_list->tx_3phase;
cur_msdu->is_dbg_pkt = msdu_list->is_dbg_pkt;
cur_msdu->fix_rate = msdu_list->fix_rate;
cur_msdu->ppm_step = msdu_list->ppm_step;
cur_msdu->ppm_step_type = (uint8_t)msdu_list->ppm_step_type;
cur_msdu->need_encrypt = (uint8_t)msdu_list->need_encrypt;
cur_msdu->key_idx = msdu_list->key_idx;
/* remove the loaded mac_frame_t */
if (msdu_list->next == NULL) {
stream->msdu.tx.last_mac_frame = NULL;
}
stream->msdu.tx.mac_frame_list = msdu_list->next;
IOT_ASSERT(stream->msdu.tx.mac_frame_num > 0);
stream->msdu.tx.mac_frame_num--;
/* increase token number */
uint32_t bcn_region_type;
bcn_region_type = \
mac_get_bcn_region_type(stream->lid);
mac_token_free(bcn_region_type, stream->lid, stream->is_rf);
mac_desc_free(&g_mac_desc_eng, \
PLC_MAC_MSDU_FRAME_POOL, \
msdu_list);
return ERR_OK;
}
/* empty queue */
return ERR_FAIL;
}
static uint32_t mac_swsch_post_msdu_internal(uint32_t is_rf)
{
mac_stream_t *stream = NULL;
uint32_t ret = 0;
uint32_t swq_id;
uint32_t proto = PHY_PROTO_TYPE_GET();
uint32_t max_mac_queue_num = 0;
mac_swq_t *p_mac_swq = NULL;
pdevid_t pdev_id = PLC_PDEV_ID;
vdevid_t vdev_id = PLC_DEFAULT_VDEV;
mac_rf_pdev_t *rf_pdev = get_rf_pdev_ptr(pdev_id, RF_PDEV_ID);
max_mac_queue_num = is_rf ? MAX_MAC_RF_QUE_NUM : MAX_MAC_QUE_NUM;
for (swq_id = 0; swq_id < max_mac_queue_num; swq_id++) //go through all swq
{
nextstream:
p_mac_swq = mac_swsch_get_g_swq(swq_id, is_rf);
if (p_mac_swq->q_depth > 0) //swq have stream pending
{
iot_list_head_t * curr_swq_head = \
&p_mac_swq->stream_list;
/* should not empty */
IOT_ASSERT_DUMP(!iot_list_empty(curr_swq_head), \
&p_mac_swq->q_depth, 1);
/* get stream through list_head, get one node just after
* the head node
*/
stream = iot_list_entry(curr_swq_head->next, \
mac_stream_t, msdu.tx.swq_node);
if (NULL == stream->msdu.tx.cur_tx_msdu) {
/* not sending msdu before, alloc the msdu */
ret = \
mac_desc_get(&g_mac_desc_eng, PLC_MAC_MSDU_POOL, \
(void**)&stream->msdu.tx.cur_tx_msdu);
IOT_ASSERT(ret == 0);
}
mac_msdu_t *msdu = stream->msdu.tx.cur_tx_msdu;
if (msdu->buf)
{
if (!msdu->in_hwq) {
/* if not in hwq, retry the msdu */
if (!is_rf) {
ret = mac_swsch_tx_msdu(pdev_id, vdev_id, \
msdu, FC_DELIM_SOF, \
proto, \
HW_DESC_TX_PORT_PLC);
} else {
ret = mac_rf_swsch_tx_msdu(rf_pdev, msdu, FC_DELIM_SOF,
stream->peer->tei, stream->lid,
(uint8_t)msdu->is_bcast);
}
}
else {
/* if already in hwq, continue for next stream */
continue;
}
}
else
{
/* first time sending of the packet */
ret = mac_load_msdu(msdu, stream);
if (ret == ERR_FAIL) {
/* if no msdu in this stream left, free
* the msdu desc in the stream to save
* some memory
*/
mac_msdu_deinit(msdu);
stream->msdu.tx.cur_tx_msdu = NULL;
/* if empty, remove the stream from the queue and
* then sch next swq. if the peer can del ,del it
*/
mac_peer_t *peer = stream->peer;
mac_swsch_remove(p_mac_swq, stream);
//TODO: confirm do we need delete temp peer when rf msdu ?
mac_peer_del_temp_peer(peer);
if(p_mac_swq->q_depth)
goto nextstream;
continue;
}
if (!is_rf) {
ret = mac_swsch_tx_msdu(pdev_id, vdev_id, \
msdu, FC_DELIM_SOF, \
proto, \
HW_DESC_TX_PORT_PLC);
} else {
ret = mac_rf_swsch_tx_msdu(rf_pdev, msdu, FC_DELIM_SOF,
stream->peer->tei, stream->lid,
(uint8_t)msdu->is_bcast);
}
}
}
}
return ret;
}
uint32_t mac_swsch_post_msdu(pdevid_t pdev_id, vdevid_t vdev_id)
{
uint32_t ret = 0;
(void)pdev_id;
(void)vdev_id;
ret = mac_swsch_post_msdu_internal(0);
#if HPLC_RF_DEV_SUPPORT
ret = mac_swsch_post_msdu_internal(1);
#endif
return ret;
}