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

499 lines
15 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 "mac_stream.h"
#include "mac_desc_engine.h"
#include "iot_errno.h"
#include "hash_table.h"
#include "sw_sched.h"
#include "iot_io.h"
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#include "os_utils_api.h"
typedef struct _mac_stream_vdev_dump_info {
uint32_t peer_cnt : 16,
proxy_peer_cnt : 16;
uint32_t stream_cnt : 16,
rx_stream_cnt : 16;
uint32_t stream_overflow_cnt : 16,
rsvd : 16;
} mac_stream_vdev_dump_info_t;
typedef struct _mac_stream_exhausted_info {
uint32_t cur_ts;
mac_stream_vdev_dump_info_t vdev_info[MAX_VDEV_NUM];
mac_peer_t peer;
} mac_stream_exhausted_info_t;
mac_stream_t *g_stream_hash_tbl[stream_tbl_sz] = { 0 };
uint32_t stream_hash_tbl_get_hsahv(nid_t nid, tei_t tei, \
lid_t lid, uint8_t is_tx, uint8_t is_rf)
{
stream_hash_src_t hash_src = { 0 };
hash_src.nid = nid;
hash_src.tei = tei;
hash_src.lid = lid;
hash_src.is_tx= is_tx;
hash_src.is_rf = is_rf;
uint8_t *hash_str = (uint8_t*)&hash_src;
return ((stream_tbl_sz - 1) \
& iot_getcrc32(hash_str, sizeof(stream_hash_src_t)));
}
/* @return stream address if found
* NULL if not found
*/
mac_stream_t * find_stream(mac_peer_t *peer_in, \
nid_t nid, tei_t tei, lid_t lid, uint8_t is_tx, uint8_t is_rf)
{
nid_t peer_nid = (nid_t)PLC_NID_INVALID;
if (!nid && !peer_in) {
/* if nid = 0, peer_in must valid */
return NULL;
}
mac_vdev_t *vdev = get_vdev_ptr(peer_in->pdev_id, peer_in->vdev_id);
if (ERR_OK != vdev_get_nid(vdev, &peer_nid)) {
peer_nid = (nid_t)PLC_NID_INVALID;
}
if (peer_in->is_self_peer) {
if (PLC_NID_INVALID == peer_nid) {
/* not assoc yet, use the peer's vdev's nid instead */
nid = (nid_t)PLC_NID_INVALID;
tei = vdev_get_tei(vdev);
}
} else if (peer_in->is_bcast_peer) {
/* else if bcast peer, and not assoc yet then
* ignore the nid of the packet, use
* the peer's vdev's nid instead
*/
IOT_ASSERT(peer_in->tei == PLC_TEI_BCAST);
if (PLC_NID_INVALID == peer_nid) {
/* not assoc yet, use the peer's vdev's nid instead */
nid = (nid_t)PLC_NID_INVALID;
}
tei = (tei_t)peer_in->tei;
}
/* should be the correct peer */
IOT_ASSERT(peer_in->tei == tei);
uint32_t hash_code = stream_hash_tbl_get_hsahv( \
nid, \
tei, \
lid,\
is_tx,\
is_rf);
mac_stream_t *tmp = \
g_stream_hash_tbl[hash_code];
mac_peer_t *peer;
/* look every node for the hash entry */
for (; tmp; tmp = tmp->next) {
peer = tmp->peer;
if (peer) {
vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
if (!vdev) {
continue;
}
}
else {
continue;
}
if ((tmp->lid == lid) \
&& (peer->tei == tei) \
&& (peer_nid == nid) \
&& (tmp->is_tx == is_tx) \
&& (tmp->is_rf == is_rf)) {
return tmp;
}
}
return NULL;
}
/* @return - 0 for successful
* other for failed
*/
uint32_t stream_hash_tbl_add(mac_stream_t *stream)
{
if (!stream) {
return ERR_INVAL;
}
lid_t lid = stream->lid;
mac_peer_t *peer = stream->peer;
if (!peer) {
return ERR_INVAL;
}
tei_t tei = (tei_t)peer->tei;
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
if (!vdev) {
return ERR_INVAL;
}
nid_t nid;
vdev_get_nid(vdev, &nid);
uint8_t is_tx = (uint8_t)stream->is_tx;
uint8_t is_rf = (uint8_t)stream->is_rf;
if (find_stream(peer, nid, tei, lid, is_tx, is_rf)) {
return ERR_EXIST;
}
mac_stream_t **tmp = \
&g_stream_hash_tbl[stream_hash_tbl_get_hsahv(nid, \
tei, lid, is_tx, is_rf)];
stream->next = *tmp;
*tmp = stream;
return 0;
}
uint32_t stream_hash_tbl_del(mac_stream_t *stream)
{
mac_stream_t *str = stream;
mac_stream_t **hash_table_entry;
mac_stream_t *entry = NULL;
tei_t tei;
nid_t nid;
if (str->peer) {
tei = (tei_t) str->peer->tei;
vdev_get_nid(get_vdev_ptr(str->peer->pdev_id, str->peer->vdev_id),
&nid); //TODO: check ret value
} else {
iot_printf("str lid=%d without peer\n", str->lid);
IOT_ASSERT(0);
tei = 0;
nid = 0;
return ERR_FAIL;
}
/* for normal case */
hash_table_entry = &g_stream_hash_tbl[stream_hash_tbl_get_hsahv(nid,
tei, str->lid, (uint8_t)str->is_tx,
(uint8_t)str->is_rf)];
for(mac_stream_t **cur = hash_table_entry; *cur;){
entry = *cur;
if(str == entry){
*cur = entry->next;
break;
}
else{
cur = &entry->next;
}
}
/* for nid valid but tei is 0 */
if(str != entry){
hash_table_entry = &g_stream_hash_tbl[stream_hash_tbl_get_hsahv( \
nid, 0, str->lid, (uint8_t)str->is_tx,
(uint8_t)str->is_rf)];
for(mac_stream_t **cur = hash_table_entry; *cur;){
entry = *cur;
if(str == entry){
*cur = entry->next;
break;
}
else{
cur = &entry->next;
}
}
}
/* for nid invalid and tei invalid */
if(str != entry){
hash_table_entry = &g_stream_hash_tbl[stream_hash_tbl_get_hsahv( \
0, 0, str->lid, (uint8_t)str->is_tx,
(uint8_t)str->is_rf)];
for(mac_stream_t **cur = hash_table_entry; *cur;){
entry = *cur;
if(str == entry){
*cur = entry->next;
break;
}
else{
cur = &entry->next;
}
}
}
/* for bcast when nid invalid */
if(str != entry){
hash_table_entry = &g_stream_hash_tbl[stream_hash_tbl_get_hsahv(0, tei,
str->lid, (uint8_t)str->is_tx,
(uint8_t)str->is_rf)];
for(mac_stream_t **cur = hash_table_entry; *cur;){
entry = *cur;
if(str == entry){
*cur = entry->next;
break;
}
else{
cur = &entry->next;
}
}
}
if (str != entry) {
/* if not bcast peer for this stream
* we need check where is gone
*/
iot_printf("str lid%d tei:%d nid 0x%x tx:%d is_rf:%d not found.\n",
str->lid, str->peer->tei, nid, str->is_tx, str->is_rf);
#if DEBUG_FREE_STREAM_FAIL
mac_debug_stream_t debug_str;
debug_str.nid = (uint32_t)nid;
debug_str.lid = (uint32_t)str->lid;
debug_str.tei = (uint32_t)str->peer->tei;
debug_str.is_tx = (uint32_t)str->is_tx;
debug_str.is_rf = (uint32_t)str->is_rf;
IOT_ASSERT_DUMP(0, (uint32_t *)&debug_str, \
sizeof(mac_debug_stream_t)/sizeof(uint32_t));
#endif
}
return 0;
}
uint32_t mac_tx_stream_ctxt_init(mac_tx_stream_ctxt_t *tx, \
mac_stream_t *stream, uint32_t need_free, iot_pkt_t *iot_pkt)
{
IOT_ASSERT(tx);
tx->mac_frame_list = tx->last_mac_frame = NULL;
tx->mac_frame_num = 0;
tx->cur_tx_msdu = NULL;
iot_list_init(&tx->swq_node);
(void)stream;
(void)need_free;
(void)iot_pkt;
return 0;
}
uint32_t mac_tx_stream_ctxt_deinit(mac_stream_t* stream)
{
mac_tx_stream_ctxt_t * tx = &stream->msdu.tx;
mac_msdu_frame_t *tmp = tx->mac_frame_list;
if (tx->cur_tx_msdu) {
/* free the msdu if not freed yet */
if (!tx->cur_tx_msdu->in_hwq) {
mac_msdu_deinit(tx->cur_tx_msdu);
} else {
tx->cur_tx_msdu->ref_mac_stream = NULL;
}
tx->cur_tx_msdu = NULL;
}
uint32_t bcn_region_type = \
mac_get_bcn_region_type(stream->lid);
if(tx->mac_frame_num == 0){
IOT_ASSERT(tx->last_mac_frame == NULL && \
tx->mac_frame_list == NULL);
}
else{
IOT_ASSERT(tx->last_mac_frame != NULL && \
tx->mac_frame_list != NULL);
for(uint32_t i = 0; i < (PLC_MAC_MSDU_FRAME_POOL_SIZE
+ RF_MAC_MSDU_FRAME_POOL_SIZE); i++){
if(tmp == NULL){
break;
}
tx->mac_frame_list = tmp->next;
IOT_ASSERT(tmp->buf);
iot_pkt_free_tx_done(tmp->buf, IOT_PKT_STATE_TX_FAIL);
mac_token_free(bcn_region_type, stream->lid, stream->is_rf);
mac_desc_free(&g_mac_desc_eng, \
PLC_MAC_MSDU_FRAME_POOL, tmp);
tmp = tx->mac_frame_list;
tx->mac_frame_num -= 1;
}
IOT_ASSERT(tx->mac_frame_num == 0 && tmp == NULL);
}
return 0;
}
uint32_t mac_stream_alloc(mac_peer_t *peer, uint32_t is_tx, \
lid_t lid, uint8_t is_rf, mac_stream_t **stream_ptr)
{
mac_stream_t *stream;
if (!peer) {
return ERR_INVAL;
}
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
IOT_ASSERT(vdev);
#if 0
/* double check if the stream already exist
* can be omit to make faster */
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
nid_t nid;
nid = vdev_get_nid(vdev);
if (nid) {
/* if vdev's nid is known */
stream = find_stream(peer, nid, \
peer->tei, lid);
if (stream) {
/* if found the stream already */
*stream_ptr = stream;
return ERR_EXIST;
}
}
else {
/* if vdev's nid is not set, use self peer */
mac_peer_t *self_peer = (mac_peer_t *)vdev->self_peer;
stream = find_stream(peer, nid, \
self_peer->tei, lid);
if (stream) {
/* if found the stream already */
*stream_ptr = stream;
return ERR_EXIST;
}
}
#endif
/* create the stream */
uint32_t ret = mac_desc_get(&g_mac_desc_eng, \
PLC_MAC_STREAM_POOL, (void**)&stream);
if (ret) {
/* if the first get stream fail.
* del the oldest stream. and get stream again.
*/
mac_vdev_del_timeout_stream_internal(vdev, false);
vdev->stream_overflow_cnt++;
/* get stream again */
ret = mac_desc_get(&g_mac_desc_eng, \
PLC_MAC_STREAM_POOL, (void**)&stream);
}
if (ret) {
mac_peer_stream_overflow_cnt_dbglog();
return ERR_NOMEM;
}
else {
if (is_tx) {
/* for tx usage */
mac_tx_stream_ctxt_init(&stream->msdu.tx, stream, 1, NULL);
}
else {
/* for rx usage */
reorder_buf_init(&stream->msdu.rx.reorder_buf, \
stream);
}
iot_single_list_init(&stream->peer_node);
stream->is_tx = (uint8_t)is_tx;
stream->in_swq = 0;
stream->lid = lid;
stream->peer = peer;
stream->phase_in_swq = PLC_PHASE_ALL;
stream->is_rf = is_rf;
/* add into peer */
peer_add_stream(peer, stream);
/* add into hash table */
stream_hash_tbl_add(stream);
/* stream cnt ++*/
vdev->stream_cnt++;
if (!stream->is_tx) {
vdev->rx_stream_cnt++;
}
*stream_ptr = stream;
}
#if PLC_SUPPORT_CCO_ROLE
nid_t nid;
vdev_get_nid(get_vdev_ptr(peer->pdev_id, peer->vdev_id), &nid);
iot_printf("%s,vid:%d, str:0x%x, nid: 0x%x, tei:%d, "
"lid:%d, is_tx:%d, is_rf:%d\n", __FUNCTION__, peer->vdev_id,
stream, nid, peer->tei, lid, is_tx, is_rf);
#endif
return ERR_OK;
}
uint32_t mac_stream_free(mac_peer_t *peer, mac_stream_t *stream)
{
IOT_ASSERT(peer);
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
IOT_ASSERT(vdev);
mac_stream_t *str = stream;
IOT_ASSERT(str != NULL);
/* delete this node from peer */
peer_del_stream(peer, str);
/* delete this node from hash table streamlist */
stream_hash_tbl_del(str);
/* delete from swq streamlist */
mac_swsch_del_stream(str);
#if PLC_SUPPORT_CCO_ROLE
nid_t nid;
vdev_get_nid(get_vdev_ptr(peer->pdev_id, peer->vdev_id), &nid);
iot_printf("%s,vid:%d, str:0x%x, nid: 0x%x, tei:%d, lid:%d, "
"is_tx:%d, is_rf:%d\n", __FUNCTION__, peer->vdev_id,
str, nid, peer->tei, stream->lid, stream->is_tx, stream->is_rf);
#endif
/* destroy stream */
if (stream->is_tx) {
mac_tx_stream_ctxt_deinit(str);
} else {
reorder_buf_free(&stream->msdu.rx.reorder_buf);
}
/* stream cnt--*/
vdev->stream_cnt--;
if (!stream->is_tx) {
vdev->rx_stream_cnt--;
}
mac_desc_free(&g_mac_desc_eng, PLC_MAC_STREAM_POOL, stream);
return ERR_OK;
}
uint32_t is_stream_empty(mac_stream_t *stream)
{
if (stream->is_tx == 0) {
/* is RX stream */
if (stream->msdu.rx.reorder_buf.pb_rdy_cnt != 0) {
return 0;
}
} else {
/* is TX stream */
if (stream->msdu.tx.mac_frame_num != 0 || \
(stream->msdu.tx.cur_tx_msdu != NULL && \
stream->msdu.tx.cur_tx_msdu->in_hwq != 0)) {
return 0;
}
}
return 1;
}
void mac_stream_exhausted_dump(mac_peer_t *peer)
{
uint8_t idx;
mac_vdev_t *vdev;
mac_stream_exhausted_info_t str_dump = {0};
str_dump.cur_ts = os_boot_time32();
os_mem_cpy(&str_dump.peer, peer, sizeof(*peer));
for (idx = 0; idx < MAX_VDEV_NUM; idx++) {
vdev = get_vdev_ptr(0, idx);
str_dump.vdev_info[idx].peer_cnt = vdev->peer_cnt;
str_dump.vdev_info[idx].proxy_peer_cnt = vdev->proxy_peer_cnt;
str_dump.vdev_info[idx].stream_cnt = vdev->stream_cnt;
str_dump.vdev_info[idx].rx_stream_cnt = vdev->rx_stream_cnt;
str_dump.vdev_info[idx].stream_overflow_cnt = vdev->stream_overflow_cnt;
}
IOT_ASSERT_DUMP(0, (uint32_t *)&str_dump,
sizeof(str_dump) / sizeof(uint32_t));
}