project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp: Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem. sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately. sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades. sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for fastboot. Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
980 lines
32 KiB
C
980 lines
32 KiB
C
/*
|
||
* Copyright (c) Hisilicon Technologies Co., Ltd. 2020-2020. All rights reserved.
|
||
* Description: hcc layer frw task.
|
||
* Author: dujinxin
|
||
* Create: 2020-09-28
|
||
*/
|
||
/* 头文件包含 */
|
||
#include "hcc_task.h"
|
||
#include "securec.h"
|
||
#include "oal_mm.h"
|
||
#include "oal_channel_host_if.h"
|
||
#include "hcc_list.h"
|
||
#include <linux/delay.h>
|
||
|
||
#ifdef __cplusplus
|
||
#if __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
#endif
|
||
|
||
/* 宏定义 */
|
||
#define THRESHOLD_SIZE_128_BYTES 128
|
||
#define THRESHOLD_SIZE_256_BYTES 256
|
||
#define THRESHOLD_SIZE_512_BYTES 512
|
||
#define THRESHOLD_SIZE_1024_BYTES 1024
|
||
|
||
#define oal_min(a, b) (((a) > (b)) ? (b) : (a))
|
||
#define oal_max(a, b) (((a) > (b)) ? (a) : (b))
|
||
/* 全局变量定义 */
|
||
hcc_handler_stru *g_hcc_host_handler = HI_NULL;
|
||
hi_u32 g_hcc_assemble_count = 5;
|
||
static hi_u32 g_lo_buf_times = 0;
|
||
#define MAX_TIMES 1
|
||
#define MAX_TIME_VALUE 1000 //1ms
|
||
#define MIN_TIME_VALUE 1000 //1ms
|
||
|
||
/* 函数定义 */
|
||
hcc_handler_stru *hcc_host_get_handler(hi_void)
|
||
{
|
||
return g_hcc_host_handler;
|
||
}
|
||
|
||
static hi_void hcc_tx_list_free(hcc_data_queue *hcc_queue)
|
||
{
|
||
hcc_unc_struc *unc_buf = HI_NULL;
|
||
for (;;) {
|
||
unc_buf = hcc_list_dequeue(hcc_queue);
|
||
if (unc_buf == HI_NULL) {
|
||
break;
|
||
}
|
||
unc_buf->free(unc_buf);
|
||
}
|
||
}
|
||
|
||
hi_void hcc_clear_queues(hcc_handler_stru *hcc, hcc_chan_type type)
|
||
{
|
||
hi_s32 i;
|
||
hcc_data_queue *head = HI_NULL;
|
||
for (i = 0; i < HCC_QUEUE_COUNT; i++) {
|
||
head = &hcc->hcc_transer_info.hcc_queues[type].queues[i].queue_info;
|
||
if (hcc_list_len(head) > 0) {
|
||
hcc_tx_list_free(head);
|
||
}
|
||
}
|
||
}
|
||
|
||
hi_void hcc_sched_transfer(hcc_handler_stru *hcc_handler)
|
||
{
|
||
if (oal_warn_on(hcc_handler == HI_NULL)) {
|
||
oam_error_log0("hcc_sched_transfer:: hcc_handler is null!");
|
||
return;
|
||
}
|
||
|
||
hi_wait_queue_wake_up_interrupt(&hcc_handler->hcc_transer_info.hcc_tx_wq);
|
||
}
|
||
|
||
/* init hcc transfer_queue */
|
||
hi_void hcc_transfer_queues_init(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hi_s32 i, j;
|
||
for (i = 0; i < HCC_DIR_COUNT; i++) {
|
||
for (j = 0; j < HCC_QUEUE_COUNT; j++) {
|
||
hcc_list_head_init(&hcc_handler->hcc_transer_info.hcc_queues[i].queues[j].queue_info);
|
||
}
|
||
}
|
||
}
|
||
|
||
static hi_void hcc_build_next_assem_descr(hcc_handler_stru *hcc_handler,
|
||
hcc_queue_type_enum type,
|
||
hcc_data_queue *head,
|
||
hcc_data_queue *next_assembled_head,
|
||
const hcc_unc_struc *descr,
|
||
hi_u32 remain_len)
|
||
{
|
||
hi_s32 i = 0;
|
||
hi_s32 len;
|
||
hi_u8 *buf = HI_NULL;
|
||
hcc_unc_struc *unc_buf = HI_NULL;
|
||
hcc_unc_struc *unc_buf_t = HI_NULL;
|
||
hi_u32 assemble_max_count, queue_len, current_trans_len;
|
||
|
||
buf = (hi_u8 *)oal_unc_data(descr);
|
||
len = (hi_s32)oal_unc_len(descr);
|
||
assemble_max_count = oal_max(1, g_hcc_assemble_count);
|
||
queue_len = hcc_list_len(head);
|
||
current_trans_len = oal_min(queue_len, assemble_max_count);
|
||
current_trans_len = oal_min(current_trans_len, remain_len);
|
||
buf[0] = 0;
|
||
|
||
if (current_trans_len == 0) {
|
||
return;
|
||
}
|
||
|
||
for (;;) {
|
||
/* move the netbuf from head queue to prepare-send queue, head->tail */
|
||
unc_buf = hcc_list_dequeue(head);
|
||
if (unc_buf == HI_NULL) {
|
||
break;
|
||
}
|
||
|
||
/* align the buff len to 32B */
|
||
if (hcc_handler->hcc_bus_ops && hcc_handler->hcc_bus_ops->private_len_align) {
|
||
unc_buf_t = hcc_handler->hcc_bus_ops->private_len_align(unc_buf, HIBUS_H2D_SCATT_BUFFLEN_ALIGN);
|
||
if (oal_unlikely(unc_buf_t == HI_NULL)) {
|
||
hcc_list_add_head(head, unc_buf);
|
||
break;
|
||
}
|
||
}
|
||
|
||
current_trans_len--;
|
||
|
||
hcc_list_add_tail(next_assembled_head, unc_buf_t);
|
||
if (oal_likely(i >= len)) {
|
||
break;
|
||
}
|
||
|
||
buf[i++] = (hi_u8)(oal_unc_len(unc_buf_t) >> HIBUS_H2D_SCATT_BUFFLEN_ALIGN_BITS);
|
||
if (current_trans_len == 0) {
|
||
/* send empty */
|
||
if (i != len) {
|
||
buf[i] = 0;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (oal_likely(!hcc_is_list_empty(next_assembled_head))) {
|
||
hcc_handler->hcc_transer_info.tx_assem_info.assembled_queue_type = type;
|
||
}
|
||
}
|
||
|
||
hcc_unc_struc *hcc_tx_assem_descr_get(hcc_handler_stru *hcc_handler)
|
||
{
|
||
return hcc_list_dequeue(&hcc_handler->tx_descr_info.tx_assem_descr_hdr);
|
||
}
|
||
|
||
static hi_void hcc_tx_assem_descr_put(hcc_handler_stru *hcc_handler,
|
||
hcc_unc_struc *unc_buf)
|
||
{
|
||
hcc_list_add_tail(&hcc_handler->tx_descr_info.tx_assem_descr_hdr, unc_buf);
|
||
}
|
||
|
||
static hi_s32 hcc_send_data_packet(hcc_handler_stru *hcc_handler,
|
||
hcc_data_queue *head,
|
||
hcc_queue_type_enum type,
|
||
hcc_data_queue *next_assembled_head,
|
||
hcc_send_mode mode,
|
||
hi_u32 *remain_len)
|
||
{
|
||
hi_s32 ret = HI_SUCCESS;
|
||
hcc_data_queue head_send;
|
||
hcc_unc_struc *unc_buf_t = HI_NULL;
|
||
|
||
if (*remain_len == 0) {
|
||
return HI_SUCCESS;
|
||
}
|
||
|
||
hcc_unc_struc *descr_netbuf = hcc_tx_assem_descr_get(hcc_handler);
|
||
if (descr_netbuf == HI_NULL) {
|
||
ret = -OAL_ENOMEM;
|
||
goto failed_get_assem_descr;
|
||
}
|
||
|
||
hi_u32 *info = hcc_handler->hcc_transer_info.tx_assem_info.info;
|
||
|
||
hcc_list_head_init(&head_send);
|
||
|
||
if (hcc_is_list_empty(next_assembled_head)) {
|
||
/* single send */
|
||
hcc_unc_struc *unc_buf = hcc_list_dequeue(head);
|
||
if (unc_buf == HI_NULL) {
|
||
ret = HI_FAIL;
|
||
goto failed_get_sig_buff;
|
||
}
|
||
|
||
if (hcc_handler->hcc_bus_ops && hcc_handler->hcc_bus_ops->private_len_align) {
|
||
unc_buf_t = hcc_handler->hcc_bus_ops->private_len_align(unc_buf, HIBUS_H2D_SCATT_BUFFLEN_ALIGN);
|
||
if (oal_unlikely(unc_buf_t == HI_NULL)) {
|
||
hcc_list_add_head(head, unc_buf);
|
||
ret = HI_FAIL;
|
||
goto failed_align_unc_buf;
|
||
}
|
||
} else {
|
||
goto failed_get_sig_buff;
|
||
}
|
||
|
||
hcc_list_add_tail(&head_send, unc_buf_t);
|
||
info[0]++;
|
||
} else {
|
||
hi_u32 assemble_len = hcc_list_len(next_assembled_head);
|
||
/* move the assem list to send queue */
|
||
hcc_list_splice_init(next_assembled_head, &head_send);
|
||
info[assemble_len]++;
|
||
}
|
||
|
||
hi_u32 total_send = hcc_list_len(&head_send);
|
||
if (*remain_len >= total_send) {
|
||
*remain_len -= total_send;
|
||
} else {
|
||
*remain_len = 0;
|
||
}
|
||
|
||
if (mode == HCC_ASSEM_SEND) {
|
||
hcc_build_next_assem_descr(hcc_handler, type, head, next_assembled_head, descr_netbuf, *remain_len);
|
||
} else {
|
||
hi_u8 *buf = oal_unc_data(descr_netbuf);
|
||
*((hi_u32 *) buf) = 0;
|
||
}
|
||
|
||
/* add the assem descr buf */
|
||
hcc_list_add_head(&head_send, descr_netbuf);
|
||
|
||
ret = oal_channel_transfer_list(hcc_handler->hi_channel, &head_send, SDIO_WRITE);
|
||
|
||
if ((hcc_handler->hcc_bus_ops != HI_NULL) && (hcc_handler->hcc_bus_ops->wlan_pm_set_packet_cnt)) {
|
||
hcc_handler->hcc_bus_ops->wlan_pm_set_packet_cnt(total_send);
|
||
}
|
||
hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[type].total_pkts += total_send;
|
||
|
||
descr_netbuf = hcc_list_dequeue(&head_send);
|
||
if (descr_netbuf == HI_NULL) {
|
||
ret = HI_SUCCESS;
|
||
goto failed_get_assem_descr;
|
||
}
|
||
hcc_tx_assem_descr_put(hcc_handler, descr_netbuf);
|
||
/* free the sent netbuf,release the wakelock */
|
||
hcc_tx_list_free(&head_send);
|
||
return ret;
|
||
failed_align_unc_buf:
|
||
failed_get_sig_buff:
|
||
hcc_tx_assem_descr_put(hcc_handler, descr_netbuf);
|
||
failed_get_assem_descr:
|
||
return ret;
|
||
}
|
||
|
||
static hi_s32 hcc_send_single_descr(hcc_handler_stru *hcc_handler, hcc_unc_struc *unc_buf)
|
||
{
|
||
hi_s32 ret;
|
||
hcc_data_queue head_send;
|
||
oal_reference(hcc_handler);
|
||
hcc_list_head_init(&head_send);
|
||
hcc_list_add_tail(&head_send, unc_buf);
|
||
ret = oal_channel_transfer_list(hcc_handler->hi_channel, &head_send, SDIO_WRITE);
|
||
return ret;
|
||
}
|
||
|
||
hi_s32 hcc_send_descr_control_data(hcc_handler_stru *hcc_handler, hcc_descr_type descr_type,
|
||
const hi_void *data, hi_u32 ul_size)
|
||
{
|
||
hi_s32 ret;
|
||
hcc_unc_struc *unc_buf = HI_NULL;
|
||
struct hcc_descr_header *dscr_hdr = HI_NULL;
|
||
unc_buf = hcc_tx_assem_descr_get(hcc_handler);
|
||
if (unc_buf == HI_NULL) {
|
||
return -OAL_ENOMEM;
|
||
}
|
||
|
||
dscr_hdr = (struct hcc_descr_header *)oal_unc_data(unc_buf);
|
||
dscr_hdr->descr_type = descr_type;
|
||
|
||
if (ul_size) {
|
||
if (oal_warn_on(data == HI_NULL)) {
|
||
hcc_tx_assem_descr_put(hcc_handler, unc_buf);
|
||
return -OAL_EINVAL;
|
||
}
|
||
if (oal_warn_on(ul_size + sizeof(struct hcc_descr_header) > oal_unc_len(unc_buf))) {
|
||
hcc_tx_assem_descr_put(hcc_handler, unc_buf);
|
||
return -OAL_EINVAL;
|
||
}
|
||
|
||
/* lint -e124 */
|
||
if (memcpy_s((hi_void *)((hi_u8 *)oal_unc_data(unc_buf) + sizeof(struct hcc_descr_header)),
|
||
ul_size, data, ul_size) != 0) {
|
||
return -OAL_EINVAL;
|
||
}
|
||
}
|
||
ret = hcc_send_single_descr(hcc_handler, unc_buf);
|
||
|
||
hcc_tx_assem_descr_put(hcc_handler, unc_buf);
|
||
return ret;
|
||
}
|
||
|
||
static hi_void hcc_restore_assemble_netbuf_list(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hcc_queue_type_enum type;
|
||
hcc_data_queue *assembled_head;
|
||
|
||
type = hcc_handler->hcc_transer_info.tx_assem_info.assembled_queue_type;
|
||
assembled_head = &hcc_handler->hcc_transer_info.tx_assem_info.assembled_head;
|
||
|
||
if (type >= HCC_QUEUE_COUNT) {
|
||
type = DATA_LO_QUEUE;
|
||
}
|
||
|
||
if (!hcc_is_list_empty(assembled_head)) {
|
||
hcc_list_splice_sync(&hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[type].queue_info,
|
||
assembled_head);
|
||
}
|
||
}
|
||
|
||
static hi_s32 hcc_send_assemble_reset(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hi_s32 ret;
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.flowctrl_reset_count++;
|
||
/* 当只发送一个聚合描述符包,并且聚合个数为0描述通知Device 重置聚合信息 */
|
||
ret = hcc_send_descr_control_data(hcc_handler, HCC_DESCR_ASSEM_RESET, HI_NULL, 0);
|
||
hcc_restore_assemble_netbuf_list(hcc_handler);
|
||
return ret;
|
||
}
|
||
|
||
hi_s32 hcc_tx_queue_switch(hcc_handler_stru *hcc_handler, hcc_netbuf_queue_type queue_type)
|
||
{
|
||
return hcc_send_descr_control_data(hcc_handler, HCC_QUEUE_SWITCH, &queue_type, sizeof(queue_type));
|
||
}
|
||
|
||
hi_s32 hcc_switch_high_pri_queue(hcc_handler_stru *hcc_handler,
|
||
hcc_netbuf_queue_type pool_type)
|
||
{
|
||
hi_s32 ret = OAL_EFAIL;
|
||
if (pool_type == HCC_HIGH_QUEUE) {
|
||
/* 此处在最高位表示是否是配置事件 */
|
||
ret = hcc_tx_queue_switch(hcc_handler, HCC_HIGH_QUEUE);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
hi_s32 hcc_restore_normal_pri_queue(hcc_handler_stru *hcc_handler, hcc_netbuf_queue_type pool_type)
|
||
{
|
||
hi_s32 ret = OAL_EFAIL;
|
||
if (pool_type == HCC_HIGH_QUEUE) {
|
||
ret = hcc_tx_queue_switch(hcc_handler, HCC_NORMAL_QUEUE);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static hi_u32 hcc_tx_flow_ctrl_handle(hcc_handler_stru *hcc_handler, hcc_queue_type_enum type)
|
||
{
|
||
hi_u32 priority_cnt;
|
||
hi_s32 ret = HI_SUCCESS;
|
||
hcc_trans_queue_stru* hcc_queue;
|
||
|
||
hcc_queue = &hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[type];
|
||
|
||
if (hcc_handler->hi_channel && oal_get_channel_func(hcc_handler->hi_channel) != HI_NULL) {
|
||
ret = oal_channel_get_credit(hcc_handler->hi_channel, &priority_cnt);
|
||
if (ret < 0) {
|
||
oam_error_log0("hcc_tx_flow_ctrl_handle fail!");
|
||
hcc_handler->hcc_transer_info.channel_exception_flag = (1 << EXCEPTION_CMD_SEND_FAILED);
|
||
return HI_FAIL;
|
||
}
|
||
}
|
||
oal_spin_lock(&(hcc_handler->hcc_transer_info.tx_flow_ctrl.st_hipri_lock));
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.uc_hipriority_cnt = hcc_mgmt_pkt_get(priority_cnt);
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.uc_lopriority_cnt = hcc_large_pkt_get(priority_cnt);
|
||
oal_spin_unlock(&(hcc_handler->hcc_transer_info.tx_flow_ctrl.st_hipri_lock));
|
||
if (hcc_handler->hcc_bus_ops &&
|
||
hcc_handler->hcc_bus_ops->tx_flow_ctrl_handle) {
|
||
if (hcc_queue->flow_ctrl.flow_type == HCC_FLOWCTRL_CREDIT) {
|
||
ret = hcc_handler->hcc_bus_ops->tx_flow_ctrl_handle(hcc_queue->flow_ctrl.flow_type,
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.uc_hipriority_cnt);
|
||
} else if (hcc_queue->flow_ctrl.flow_type == HCC_FLOWCTRL_SDIO) {
|
||
ret = hcc_handler->hcc_bus_ops->tx_flow_ctrl_handle(hcc_queue->flow_ctrl.flow_type,
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.uc_lopriority_cnt);
|
||
}
|
||
}
|
||
|
||
if (printk_ratelimit() && (ret == HI_FAIL))
|
||
oam_error_log2("tx_flow uc_hipriority %d, uc_lopriority %d!", hcc_mgmt_pkt_get(priority_cnt),
|
||
hcc_large_pkt_get(priority_cnt));
|
||
|
||
return ret;
|
||
}
|
||
|
||
hi_void hcc_tx_sleep(hi_void)
|
||
{
|
||
g_lo_buf_times++;
|
||
if (g_lo_buf_times > MAX_TIMES) {
|
||
usleep_range(MIN_TIME_VALUE, MAX_TIME_VALUE);
|
||
g_lo_buf_times = 0;
|
||
}
|
||
}
|
||
|
||
hi_s32 hcc_host_proc_tx_queue(hcc_handler_stru *hcc_handler, hcc_queue_type_enum type)
|
||
{
|
||
hi_s32 count = 0;
|
||
|
||
if (type >= HCC_QUEUE_COUNT) {
|
||
oam_error_log1("hcc_send_tx_queue:: invalid hcc_queue type[%d]", type);
|
||
return count;
|
||
}
|
||
|
||
if (hcc_handler->hcc_transer_info.tx_flow_ctrl.flowctrl_flag == D2H_MSG_FLOWCTRL_OFF) {
|
||
if (printk_ratelimit())
|
||
oam_error_log0("tx_flow_ctrl: tx congestion!!!");
|
||
hcc_tx_sleep();
|
||
return count;
|
||
}
|
||
|
||
hcc_trans_queue_stru *hcc_queue = &hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[type];
|
||
hcc_data_queue *head = &hcc_queue->queue_info;
|
||
|
||
hi_u32 remain_len = hcc_list_len(head);
|
||
if (!remain_len) {
|
||
goto hcc_tx_exit;
|
||
}
|
||
|
||
/* hcc流控处理 */
|
||
hi_s32 ret = hcc_tx_flow_ctrl_handle(hcc_handler, type);
|
||
if (ret != HI_SUCCESS) {
|
||
hcc_tx_sleep();
|
||
goto hcc_tx_exit;
|
||
}
|
||
|
||
g_lo_buf_times = 0;
|
||
|
||
if (hcc_queue->flow_ctrl.flow_type == HCC_FLOWCTRL_CREDIT) {
|
||
remain_len = oal_min(hcc_handler->hcc_transer_info.tx_flow_ctrl.uc_hipriority_cnt, remain_len);
|
||
} else if (hcc_queue->flow_ctrl.flow_type == HCC_FLOWCTRL_SDIO) {
|
||
remain_len = oal_min(hcc_handler->hcc_transer_info.tx_flow_ctrl.uc_lopriority_cnt, remain_len);
|
||
}
|
||
|
||
hi_u32 remain_len_t = remain_len;
|
||
hcc_data_queue *next_assembled_head = &hcc_handler->hcc_transer_info.tx_assem_info.assembled_head;
|
||
|
||
if (!hcc_is_list_empty(next_assembled_head)) {
|
||
if (hcc_send_assemble_reset(hcc_handler) != HI_SUCCESS) {
|
||
/* send one pkt */
|
||
count = 1;
|
||
goto hcc_tx_exit;
|
||
}
|
||
}
|
||
|
||
hcc_send_mode send_mode = hcc_queue->send_mode;
|
||
hcc_queue_type pool_type = hcc_queue->pool_type;
|
||
while (remain_len != 0) {
|
||
if (hcc_queue->flow_ctrl.flow_type == HCC_FLOWCTRL_CREDIT) {
|
||
ret = hcc_switch_high_pri_queue(hcc_handler, pool_type);
|
||
if (ret != HI_SUCCESS) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (hcc_handler->hcc_transer_info.tx_flow_ctrl.flowctrl_flag == D2H_MSG_FLOWCTRL_OFF) {
|
||
break;
|
||
}
|
||
|
||
ret = hcc_send_data_packet(hcc_handler, head, type, next_assembled_head, send_mode, &remain_len);
|
||
if (ret != HI_SUCCESS) {
|
||
break;
|
||
}
|
||
count += (hi_s32)(remain_len_t - remain_len);
|
||
}
|
||
|
||
if (hcc_queue->flow_ctrl.flow_type == HCC_FLOWCTRL_CREDIT) {
|
||
hcc_restore_normal_pri_queue(hcc_handler, pool_type);
|
||
}
|
||
|
||
hcc_tx_exit:
|
||
return count;
|
||
}
|
||
|
||
hi_u32 hcc_host_proc_rx_queue(hcc_handler_stru *hcc_handler, hcc_queue_type_enum type)
|
||
{
|
||
hi_s32 count = 0;
|
||
hi_s32 ret;
|
||
hcc_data_queue *head = HI_NULL;
|
||
hcc_unc_struc *unc_buf = HI_NULL;
|
||
head = &hcc_handler->hcc_transer_info.hcc_queues[HCC_RX].queues[type].queue_info;
|
||
|
||
for (;;) {
|
||
unc_buf = hcc_list_dequeue(head);
|
||
if (unc_buf == HI_NULL) {
|
||
break;
|
||
}
|
||
if (hcc_handler->hcc_bus_ops != NULL && hcc_handler->hcc_bus_ops->rx_proc_queue) {
|
||
ret = hcc_handler->hcc_bus_ops->rx_proc_queue(unc_buf);
|
||
count++;
|
||
} else {
|
||
unc_buf->free(unc_buf);
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
hi_void hcc_trans_flow_ctrl_info_init(hcc_handler_stru *hcc_handle)
|
||
{
|
||
hi_s32 i;
|
||
|
||
hcc_handle->hcc_transer_info.tx_flow_ctrl.flowctrl_flag = D2H_MSG_FLOWCTRL_ON;
|
||
hcc_handle->hcc_transer_info.tx_flow_ctrl.flowctrl_off_count = 0;
|
||
hcc_handle->hcc_transer_info.tx_flow_ctrl.flowctrl_on_count = 0;
|
||
oal_spin_lock_init(&hcc_handle->hcc_transer_info.tx_flow_ctrl.lock);
|
||
|
||
hcc_handle->hcc_transer_info.tx_flow_ctrl.uc_hipriority_cnt = HCC_FLOW_HIGH_PRI_BUFF_CNT;
|
||
hcc_handle->hcc_transer_info.tx_flow_ctrl.uc_lopriority_cnt = HCC_FLOW_LOW_PRI_BUFF_CNT;
|
||
oal_spin_lock_init(&hcc_handle->hcc_transer_info.tx_flow_ctrl.st_hipri_lock);
|
||
|
||
hcc_trans_queues_stru *hcc_tx_queues = &hcc_handle->hcc_transer_info.hcc_queues[HCC_TX];
|
||
hcc_trans_queues_stru *hcc_rx_queues = &hcc_handle->hcc_transer_info.hcc_queues[HCC_TX];
|
||
|
||
for (i = 0; i < HCC_QUEUE_COUNT; i++) {
|
||
/* TX queue */
|
||
hcc_tx_queues->queues[i].flow_ctrl.enable = HI_TRUE;
|
||
hcc_tx_queues->queues[i].flow_ctrl.flow_type = HCC_FLOWCTRL_SDIO;
|
||
hcc_tx_queues->queues[i].flow_ctrl.is_stopped = HI_FALSE;
|
||
hcc_tx_queues->queues[i].flow_ctrl.low_waterline = THRESHOLD_SIZE_512_BYTES;
|
||
hcc_tx_queues->queues[i].flow_ctrl.high_waterline = THRESHOLD_SIZE_1024_BYTES;
|
||
hcc_tx_queues->queues[i].pool_type = HCC_NORMAL_QUEUE;
|
||
|
||
/* RX queue */
|
||
hcc_rx_queues->queues[i].flow_ctrl.enable = HI_TRUE;
|
||
hcc_rx_queues->queues[i].flow_ctrl.is_stopped = HI_FALSE;
|
||
hcc_rx_queues->queues[i].flow_ctrl.low_waterline = THRESHOLD_SIZE_128_BYTES;
|
||
hcc_rx_queues->queues[i].flow_ctrl.high_waterline = THRESHOLD_SIZE_512_BYTES;
|
||
}
|
||
|
||
/* Additional high priority flow_ctrl settings */
|
||
hcc_tx_queues->queues[DATA_HI_QUEUE].flow_ctrl.flow_type = HCC_FLOWCTRL_CREDIT;
|
||
hcc_tx_queues->queues[DATA_HI_QUEUE].flow_ctrl.enable = HI_FALSE;
|
||
hcc_tx_queues->queues[DATA_HI_QUEUE].pool_type = HCC_HIGH_QUEUE;
|
||
}
|
||
|
||
hi_void hcc_trans_send_mode_init(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hi_s32 i;
|
||
|
||
for (i = 0; i < HCC_QUEUE_COUNT; i++) {
|
||
hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[i].send_mode = HCC_ASSEM_SEND;
|
||
}
|
||
hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[DATA_HI_QUEUE].send_mode = HCC_SINGLE_SEND;
|
||
}
|
||
|
||
hi_s32 hcc_message_register(const hcc_handler_stru *hcc_handler, hi_u8 msg, hcc_msg_cb cb, hi_void *data)
|
||
{
|
||
return oal_channel_message_register(hcc_handler->hi_channel, msg, cb, data);
|
||
}
|
||
|
||
hi_void hcc_message_unregister(const hcc_handler_stru *hcc_handler, hi_u8 msg)
|
||
{
|
||
oal_channel_message_unregister(hcc_handler->hi_channel, msg);
|
||
}
|
||
|
||
static hi_u32 hcc_host_check_header_vaild(const hcc_header_stru *hcc_hdr)
|
||
{
|
||
if ((hcc_hdr->main_type >= HCC_TYPE_BUFF)) {
|
||
oam_error_log1("hcc_host_check_header_vaild:: invalid type[%d]", hcc_hdr->main_type);
|
||
return HI_FALSE;
|
||
}
|
||
return HI_TRUE;
|
||
}
|
||
|
||
static hi_void hcc_transfer_rx_handler_replace(hcc_handler_stru *hcc_handler, hcc_unc_struc *unc_buf_new)
|
||
{
|
||
hcc_unc_struc *unc_buf_old = HI_NULL;
|
||
hcc_trans_queue_stru *hcc_queue = &hcc_handler->hcc_transer_info.hcc_queues[HCC_RX].queues[DATA_LO_QUEUE];
|
||
unc_buf_old = hcc_list_dequeue(&hcc_queue->queue_info);
|
||
if (unc_buf_old != HI_NULL) {
|
||
hcc_queue->loss_pkts++;
|
||
unc_buf_old->free(unc_buf_old);
|
||
}
|
||
hcc_list_add_tail(&hcc_queue->queue_info, unc_buf_new);
|
||
}
|
||
|
||
static hi_void hcc_transfer_rx_handler(hcc_handler_stru *hcc_handler, hcc_unc_struc *unc_buf)
|
||
{
|
||
hcc_list_add_tail(&hcc_handler->hcc_transer_info.hcc_queues[HCC_RX].queues[DATA_LO_QUEUE].queue_info, unc_buf);
|
||
}
|
||
|
||
hi_void hcc_rx_sched_transfer(hcc_handler_stru *hcc_handler)
|
||
{
|
||
if (oal_warn_on(hcc_handler == HI_NULL)) {
|
||
oam_error_log0("hcc_sched_transfer:: hcc_handler is null!");
|
||
return;
|
||
}
|
||
hi_wait_queue_wake_up_interrupt(&hcc_handler->hcc_transer_info.hcc_rx_wq);
|
||
}
|
||
|
||
static hi_void hcc_rx_list_handler(hcc_handler_stru *hcc_handler, hcc_data_queue *head)
|
||
{
|
||
hi_u32 scatt_count;
|
||
hcc_unc_struc *unc_buf = HI_NULL;
|
||
hcc_header_stru *hcc_hdr = HI_NULL;
|
||
|
||
scatt_count = hcc_list_len(head);
|
||
if (scatt_count > HIBUS_DEV2HOST_SCATT_MAX) {
|
||
oam_error_log1("hcc_rx_netbuf_list_handler:: scatt buffs overflow, scatt_count[%d]", scatt_count);
|
||
scatt_count = 0;
|
||
}
|
||
|
||
hcc_handler->hcc_transer_info.rx_assem_info.info[scatt_count]++;
|
||
hcc_trans_queues_stru *hcc_rx = &hcc_handler->hcc_transer_info.hcc_queues[HCC_RX];
|
||
|
||
for (;;) {
|
||
unc_buf = hcc_list_dequeue(head);
|
||
if (unc_buf == HI_NULL) {
|
||
break;
|
||
}
|
||
hcc_hdr = (hcc_header_stru *)oal_unc_data(unc_buf);
|
||
if (hcc_host_check_header_vaild(hcc_hdr) != HI_TRUE) {
|
||
unc_buf->free(unc_buf);
|
||
oam_error_log0("invalid hcc header: ");
|
||
break;
|
||
}
|
||
|
||
if (hcc_rx->queues[DATA_LO_QUEUE].flow_ctrl.enable == HI_TRUE) {
|
||
if (hcc_list_len(&hcc_rx->queues[DATA_LO_QUEUE].queue_info) >
|
||
hcc_rx->queues[DATA_LO_QUEUE].flow_ctrl.high_waterline) {
|
||
hcc_transfer_rx_handler_replace(hcc_handler, unc_buf);
|
||
} else {
|
||
hcc_transfer_rx_handler(hcc_handler, unc_buf);
|
||
}
|
||
} else {
|
||
hcc_transfer_rx_handler(hcc_handler, unc_buf);
|
||
}
|
||
}
|
||
|
||
hcc_rx_sched_transfer(hcc_handler);
|
||
}
|
||
|
||
hi_s32 hcc_transfer_rx_data_handler(hi_void *data)
|
||
{
|
||
hi_s32 ret;
|
||
hcc_data_queue head;
|
||
hcc_handler_stru *hcc_handler = (hcc_handler_stru *)data;
|
||
|
||
hcc_list_head_init(&head);
|
||
|
||
ret = oal_channel_build_rx_list(hcc_handler->hi_channel, &head);
|
||
if (ret != HI_SUCCESS) {
|
||
oam_error_log1("oal_channel_build_rx_list:: oal_channel_build_rx_list failed[%d]", ret);
|
||
return ret;
|
||
}
|
||
|
||
ret = oal_channel_transfer_list(hcc_handler->hi_channel, &head, SDIO_READ);
|
||
if (ret != HI_SUCCESS) {
|
||
hcc_list_purge(&head);
|
||
oam_error_log1("oal_channel_transfer_list:: oal_channel_transfer_list failed[%d]", ret);
|
||
return -OAL_EFAIL;
|
||
}
|
||
|
||
hcc_rx_list_handler(hcc_handler, &head);
|
||
return HI_SUCCESS;
|
||
}
|
||
|
||
hi_void hcc_tx_assem_descr_exit(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hcc_list_purge(&hcc_handler->tx_descr_info.tx_assem_descr_hdr);
|
||
}
|
||
|
||
hi_void hcc_host_tx_assem_info_reset(hcc_handler_stru *hcc_handler)
|
||
{
|
||
memset_s(hcc_handler->hcc_transer_info.tx_assem_info.info,
|
||
sizeof(hcc_handler->hcc_transer_info.tx_assem_info.info),
|
||
0,
|
||
sizeof(hcc_handler->hcc_transer_info.tx_assem_info.info));
|
||
}
|
||
|
||
hi_void hcc_host_rx_assem_info_reset(hcc_handler_stru *hcc_handler)
|
||
{
|
||
memset_s(hcc_handler->hcc_transer_info.rx_assem_info.info,
|
||
sizeof(hcc_handler->hcc_transer_info.rx_assem_info.info),
|
||
0,
|
||
sizeof(hcc_handler->hcc_transer_info.rx_assem_info.info));
|
||
}
|
||
|
||
hi_void hcc_assem_info_init(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hcc_handler->hcc_transer_info.tx_assem_info.assemble_max_count = g_hcc_assemble_count;
|
||
hcc_host_tx_assem_info_reset(hcc_handler);
|
||
hcc_host_rx_assem_info_reset(hcc_handler);
|
||
hcc_list_head_init(&hcc_handler->hcc_transer_info.tx_assem_info.assembled_head);
|
||
}
|
||
|
||
hi_s32 hcc_tx_assem_descr_init(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hi_s32 i;
|
||
hi_s32 ret = HI_SUCCESS;
|
||
hcc_unc_struc *accem_desm = HI_NULL;
|
||
|
||
if (hcc_handler->hcc_bus_ops == HI_NULL ||
|
||
hcc_handler->hcc_bus_ops->alloc_unc_buf == HI_NULL) {
|
||
return HI_FAIL;
|
||
}
|
||
|
||
hcc_list_head_init(&hcc_handler->tx_descr_info.tx_assem_descr_hdr);
|
||
hcc_handler->tx_descr_info.descr_num = MAX_ASSEM_DESC_CNT;
|
||
|
||
for (i = 0; i < hcc_handler->tx_descr_info.descr_num; i++) {
|
||
accem_desm = hcc_handler->hcc_bus_ops->alloc_unc_buf(HIBUS_HOST2DEV_SCATT_SIZE, NORMAL_STRU_TYPE);
|
||
if (accem_desm == HI_NULL) {
|
||
goto failed_netbuf_alloc;
|
||
}
|
||
|
||
hcc_list_add_tail(&hcc_handler->tx_descr_info.tx_assem_descr_hdr, accem_desm);
|
||
if (!oal_is_aligned((uintptr_t)oal_unc_data(accem_desm), 4)) { /* 4 字节对齐 */
|
||
oam_error_log0("hcc_tx_assem_descr_init:: 4 aligned failed!");
|
||
}
|
||
}
|
||
return ret;
|
||
failed_netbuf_alloc:
|
||
hcc_list_purge(&hcc_handler->tx_descr_info.tx_assem_descr_hdr);
|
||
return -OAL_ENOMEM;
|
||
}
|
||
|
||
hi_s32 hcc_heartbeat_callback(hi_void *data)
|
||
{
|
||
hcc_handler_stru *hcc_handle = (hcc_handler_stru *)data;
|
||
if (oal_channel_send_msg(hcc_handle->hi_channel, H2D_MSG_HEARTBEAT_ACK) != HI_SUCCESS) {
|
||
return HI_FAIL;
|
||
}
|
||
return HI_SUCCESS;
|
||
}
|
||
|
||
hi_void hcc_dev_flowctrl_off(hcc_handler_stru *hcc_handler)
|
||
{
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.flowctrl_flag = D2H_MSG_FLOWCTRL_OFF;
|
||
hcc_handler->hcc_transer_info.tx_flow_ctrl.flowctrl_off_count++;
|
||
}
|
||
|
||
hi_s32 hcc_flow_off_callback(hi_void *data)
|
||
{
|
||
hcc_dev_flowctrl_off((hcc_handler_stru *)data);
|
||
return HI_SUCCESS;
|
||
}
|
||
|
||
#ifdef _PRE_HICHANNEL_DEBUG
|
||
hi_s32 hcc_test_write_over_callback(hi_void *data)
|
||
{
|
||
hcc_handler_stru *hcc_handler = (hcc_handler_stru *)data;
|
||
|
||
if (oal_warn_on(hcc_handler == HI_NULL)) {
|
||
oam_error_log0("hcc_sched_transfer:: hcc_handler is null!");
|
||
return HI_FAIL;
|
||
}
|
||
oal_complete(&hcc_handler->hcc_transer_info.hcc_test_tx);
|
||
return HI_SUCCESS;
|
||
}
|
||
#endif
|
||
|
||
//static void hcc_trig_tx_sched(unsigned long data)
|
||
static void hcc_trig_tx_sched(oal_timer_list_stru * timer_list)
|
||
{
|
||
hcc_handler_stru *hcc_handler = hcc_host_get_handler();
|
||
if (hcc_handler == HI_NULL) {
|
||
hcc_handler->hcc_transer_info.hcc_timer_status = TIMER_STOP;
|
||
return;
|
||
}
|
||
hcc_handler->hcc_transer_info.hcc_timer_status = TIMER_RUNING;
|
||
|
||
/* stop tcpip tx queue */
|
||
hcc_trans_queue_stru *hcc_queue = &hcc_handler->hcc_transer_info.hcc_queues[HCC_TX].queues[DATA_LO_QUEUE];
|
||
if ((hcc_handler->hcc_bus_ops != HI_NULL) &&
|
||
(hcc_handler->hcc_bus_ops->awake_tcpip_tx_queue != HI_NULL)) {
|
||
hcc_handler->hcc_bus_ops->awake_tcpip_tx_queue(hcc_queue);
|
||
}
|
||
|
||
hcc_sched_transfer(hcc_handler);
|
||
//hi_u32 ret = oal_timer_start(&hcc_handler->hcc_transer_info.hcc_timer, HCC_TRIG_TX_SCHED_TIMEOUT);
|
||
hi_u32 ret = oal_timer_start(timer_list, HCC_TRIG_TX_SCHED_TIMEOUT);
|
||
if (ret != 0 && ret != 1) {
|
||
oam_error_log1("{hcc_trig_tx_sched timer fail: fail ret = %d}", ret);
|
||
}
|
||
hcc_handler->hcc_transer_info.hcc_timer_status = TIMER_STOP;
|
||
}
|
||
|
||
static hcc_unc_struc* hcc_alloc_unc_buf(hi_s32 len, hcc_stru_type type)
|
||
{
|
||
hcc_handler_stru *hcc_handler = hcc_host_get_handler();
|
||
if (hcc_handler == HI_NULL) {
|
||
return HI_NULL;
|
||
}
|
||
|
||
if (hcc_handler->hcc_bus_ops &&
|
||
hcc_handler->hcc_bus_ops->alloc_unc_buf) {
|
||
return hcc_handler->hcc_bus_ops->alloc_unc_buf(len, type);
|
||
}
|
||
|
||
return HI_NULL;
|
||
}
|
||
|
||
static hi_u32 hcc_wlan_pm_wakeup_dev(hi_void *data)
|
||
{
|
||
hcc_handler_stru *hcc_handler = (hcc_handler_stru *)data;
|
||
if (hcc_handler == HI_NULL) {
|
||
return HI_FAIL;
|
||
}
|
||
|
||
if (hcc_handler->hcc_bus_ops &&
|
||
hcc_handler->hcc_bus_ops->wlan_pm_wakeup_dev) {
|
||
return hcc_handler->hcc_bus_ops->wlan_pm_wakeup_dev();
|
||
}
|
||
return HI_SUCCESS;
|
||
}
|
||
|
||
static struct hcc_bus_ops g_bus_ops = {
|
||
.rx = hcc_transfer_rx_data_handler,
|
||
.alloc_unc_buf = hcc_alloc_unc_buf,
|
||
.pm_wakeup_dev = hcc_wlan_pm_wakeup_dev,
|
||
};
|
||
|
||
hi_u32 hcc_host_init(struct hcc_bus_adpta_ops* hcc_bus_adpta_opt)
|
||
{
|
||
hcc_handler_stru *hcc_handler = (hcc_handler_stru *)oal_memalloc(sizeof(hcc_handler_stru));
|
||
if (hcc_handler == HI_NULL) {
|
||
oam_error_log0("hcc_host_init:: malloc hcc_handler fail!");
|
||
return HI_FAIL;
|
||
}
|
||
else
|
||
{
|
||
g_hcc_host_handler = hcc_handler;
|
||
oam_info_log0("hcc_host_init:: malloc hcc_handler success!");
|
||
}
|
||
if (memset_s(hcc_handler, sizeof(hcc_handler_stru), 0, sizeof(hcc_handler_stru)) != EOK) {
|
||
goto sdio_init_err;
|
||
}
|
||
|
||
if (oal_channel_init((void*)hcc_handler, 1, &g_bus_ops) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: oal_sdio_init fail!");
|
||
goto sdio_init_err;
|
||
}
|
||
|
||
hi_wait_queue_init_head(&hcc_handler->hcc_transer_info.hcc_tx_wq);
|
||
hi_wait_queue_init_head(&hcc_handler->hcc_transer_info.hcc_rx_wq);
|
||
#ifdef _PRE_HICHANNEL_DEBUG
|
||
oal_init_completion(&hcc_handler->hcc_transer_info.hcc_test_tx);
|
||
#endif
|
||
hcc_transfer_queues_init(hcc_handler);
|
||
hcc_trans_flow_ctrl_info_init(hcc_handler);
|
||
oal_mutex_init(&hcc_handler->tx_transfer_lock);
|
||
hcc_handler->hcc_bus_ops = hcc_bus_adpta_opt;
|
||
hi_u32 ret = hcc_task_init(hcc_handler);
|
||
if (ret != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: hcc_task_init failed");
|
||
goto hcc_tast_init_err;
|
||
}
|
||
|
||
/* tx线程防呆 */
|
||
oal_timer_init(&hcc_handler->hcc_transer_info.hcc_timer, HCC_TRIG_TX_SCHED_TIMEOUT,
|
||
hcc_trig_tx_sched,
|
||
(uintptr_t)hcc_handler);
|
||
oal_timer_add(&hcc_handler->hcc_transer_info.hcc_timer);
|
||
hcc_handler->hcc_transer_info.hcc_timer_status = TIMER_ADD;
|
||
|
||
hcc_assem_info_init(hcc_handler);
|
||
hcc_trans_send_mode_init(hcc_handler);
|
||
|
||
if (hcc_tx_assem_descr_init(hcc_handler) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: hcc_tx_assem_descr_init failed");
|
||
goto hcc_tast_init_err;
|
||
}
|
||
|
||
if (hcc_message_register(hcc_handler,
|
||
D2H_MSG_FLOWCTRL_OFF, hcc_flow_off_callback, hcc_handler) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: hcc_message_register_flowctrl_off failed!");
|
||
goto failed_reg_flowoff_msg;
|
||
}
|
||
|
||
if (hcc_message_register(hcc_handler,
|
||
D2H_MSG_HEARTBEAT, hcc_heartbeat_callback, hcc_handler) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: heartbeat_cb register failed!");
|
||
goto failed_reg_heartbeat_msg;
|
||
}
|
||
|
||
/* notify SDIO device to start heartbeat */
|
||
if (oal_channel_send_msg(hcc_handler->hi_channel, H2D_MSG_HEART_BEAT_OPEN) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: start heartbeat fail");
|
||
goto failed_reg_heartbeat_msg;
|
||
}
|
||
|
||
#ifdef _PRE_HICHANNEL_HDR_OPT
|
||
if (oal_channel_send_msg(hcc_handler->hi_channel, H2D_MSG_HICHANNEL_HDR_OPT) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: hichannel_hdr opt fail");
|
||
goto failed_reg_heartbeat_msg;
|
||
}
|
||
#endif
|
||
|
||
#ifdef _PRE_HICHANNEL_DEBUG
|
||
if (hcc_message_register(hcc_handler,
|
||
D2H_MSG_TEST_WRITE_OVER,
|
||
hcc_test_write_over_callback, hcc_handler) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: hcc_message_register_flowctrl_off failed!");
|
||
goto failed_reg_test_write_over;
|
||
}
|
||
#endif
|
||
|
||
//g_hcc_host_handler = hcc_handler;
|
||
if (oal_channel_send_msg(hcc_handler->hi_channel, H2D_MSG_SDIO_READY) != HI_SUCCESS) {
|
||
oam_error_log0("hcc_host_init:: send ready msg fail");
|
||
goto failed_send_ready_msg;
|
||
}
|
||
oam_warning_log0("hcc_host_init SUCCESSFULLY");
|
||
return HI_SUCCESS;
|
||
failed_send_ready_msg:
|
||
#ifdef _PRE_HICHANNEL_DEBUG
|
||
failed_reg_test_write_over:
|
||
hcc_message_unregister(hcc_handler, D2H_MSG_HEARTBEAT);
|
||
hcc_message_unregister(hcc_handler, D2H_MSG_FLOWCTRL_OFF);
|
||
#endif
|
||
failed_reg_heartbeat_msg:
|
||
hcc_message_unregister(hcc_handler, D2H_MSG_FLOWCTRL_OFF);
|
||
failed_reg_flowoff_msg:
|
||
hcc_tx_assem_descr_exit(hcc_handler);
|
||
oal_timer_delete(&hcc_handler->hcc_transer_info.hcc_timer);
|
||
hcc_handler->hcc_transer_info.hcc_timer_status = TIMER_DEL;
|
||
hcc_tast_init_err:
|
||
oal_kthread_stop(hcc_handler->hcc_transer_info.hcc_transfer_thread);
|
||
hcc_handler->hcc_transer_info.hcc_transfer_thread = HI_NULL;
|
||
oal_mutex_destroy(&hcc_handler->tx_transfer_lock);
|
||
oal_channel_exit(hcc_handler->hi_channel);
|
||
sdio_init_err:
|
||
oal_free(hcc_handler);
|
||
return HI_FAIL;
|
||
}
|
||
|
||
hi_void hcc_delete_tx_sched_timer(hcc_handler_stru *hcc)
|
||
{
|
||
hi_u16 retry_time = 10000;
|
||
if (hcc == HI_NULL || hcc->hcc_transer_info.hcc_timer_status == TIMER_DEL) {
|
||
return;
|
||
}
|
||
|
||
while (retry_time > 0 && hcc->hcc_transer_info.hcc_timer_status == TIMER_RUNING) {
|
||
usleep_range(1, 1);
|
||
retry_time--;
|
||
}
|
||
oal_timer_delete(&hcc->hcc_transer_info.hcc_timer);
|
||
hcc->hcc_transer_info.hcc_timer_status = TIMER_DEL;
|
||
}
|
||
|
||
hi_void hcc_host_exit(hcc_handler_stru *hcc)
|
||
{
|
||
if (hcc == HI_NULL) {
|
||
return;
|
||
}
|
||
|
||
hcc_message_unregister(hcc, D2H_MSG_HEARTBEAT);
|
||
#ifdef _PRE_HICHANNEL_DEBUG
|
||
hcc_message_unregister(hcc, D2H_MSG_TEST_WRITE_OVER);
|
||
#endif
|
||
hcc_tx_assem_descr_exit(hcc);
|
||
hcc_delete_tx_sched_timer(hcc);
|
||
oal_disable_channel_state(hcc->hi_channel, OAL_SDIO_ALL);
|
||
hcc_exit_task_thread(hcc);
|
||
oal_kthread_stop(hcc->hcc_transer_info.hcc_transfer_thread);
|
||
oal_kthread_stop(hcc->hcc_transer_info.hcc_rx_thread);
|
||
hcc_clear_queues(hcc, HCC_TX);
|
||
hcc_clear_queues(hcc, HCC_RX);
|
||
hcc->hcc_transer_info.hcc_transfer_thread = HI_NULL;
|
||
oal_mutex_destroy(&hcc->tx_transfer_lock);
|
||
oal_channel_exit(hcc->hi_channel);
|
||
oal_free(hcc);
|
||
g_hcc_host_handler = HI_NULL;
|
||
}
|
||
|
||
#ifdef __cplusplus
|
||
#if __cplusplus
|
||
}
|
||
#endif
|
||
#endif
|