499 lines
15 KiB
C
Executable File
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));
|
|
}
|