1 /*
2 * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "flow_control_task.h"
10 #include "osal_time.h"
11 #include "hdf_log.h"
12 #include "flow_control.h"
13 #include "securec.h"
14 #define HDF_LOG_TAG HDF_WIFI_CORE
15 #define FLOW_CONTROL_MAP_SIZE 3
16 struct FcPriority {
17 FlowDir dir;
18 FlowControlQueueID id;
19 };
20
21 static FlowControlQueueID g_staPriorityMapTx[QUEUE_ID_COUNT] = {
22 CTRL_QUEUE_ID, VIP_QUEUE_ID, NORMAL_QUEUE_ID, TCP_ACK_QUEUE_ID, TCP_DATA_QUEUE_ID, VO_QUEUE_ID, VI_QUEUE_ID,
23 BE_QUEUE_ID, BK_QUEUE_ID
24 };
25
26 static FlowControlQueueID g_staPriorityMapRx[QUEUE_ID_COUNT] = {
27 CTRL_QUEUE_ID, VIP_QUEUE_ID, NORMAL_QUEUE_ID, TCP_DATA_QUEUE_ID, TCP_ACK_QUEUE_ID, VO_QUEUE_ID, VI_QUEUE_ID,
28 BE_QUEUE_ID, BK_QUEUE_ID
29 };
30
31 static FlowControlQueueID g_priorityMapTx[QUEUE_ID_COUNT] = {
32 CTRL_QUEUE_ID, VIP_QUEUE_ID, NORMAL_QUEUE_ID, TCP_DATA_QUEUE_ID, TCP_ACK_QUEUE_ID, VO_QUEUE_ID, VI_QUEUE_ID,
33 BE_QUEUE_ID, BK_QUEUE_ID
34 };
35
36 static FlowControlQueueID g_priorityMapRx[QUEUE_ID_COUNT] = {
37 CTRL_QUEUE_ID, VIP_QUEUE_ID, NORMAL_QUEUE_ID, TCP_ACK_QUEUE_ID, TCP_DATA_QUEUE_ID, VO_QUEUE_ID, VI_QUEUE_ID,
38 BE_QUEUE_ID, BK_QUEUE_ID
39 };
40
IsFcThreadNeedStop(struct FlowControlModule * fcm,FlowDir dir)41 static bool IsFcThreadNeedStop(struct FlowControlModule *fcm, FlowDir dir)
42 {
43 if (fcm->threadStatus[dir] > THREAD_RUNNING) {
44 return true;
45 }
46 return false;
47 }
48
FlowControlTxTreadProcess(struct FlowControlModule * fcm)49 static void FlowControlTxTreadProcess(struct FlowControlModule *fcm)
50 {
51 bool isSta = false;
52 int i;
53 if (fcm->op != NULL && fcm->op->isDeviceStaOrP2PClient != NULL) {
54 isSta = fcm->op->isDeviceStaOrP2PClient();
55 }
56 if (isSta) {
57 for (i = 0; i < FLOW_CONTROL_MAP_SIZE; i++) {
58 SendFlowControlQueue(fcm, g_staPriorityMapTx[i], FLOW_TX);
59 }
60 } else {
61 for (i = 0; i < FLOW_CONTROL_MAP_SIZE; i++) {
62 SendFlowControlQueue(fcm, g_priorityMapTx[i], FLOW_TX);
63 }
64 }
65 }
66
FlowControlRxTreadProcess(struct FlowControlModule * fcm)67 static void FlowControlRxTreadProcess(struct FlowControlModule *fcm)
68 {
69 bool isSta = false;
70 int i;
71 if (fcm->op != NULL && fcm->op->isDeviceStaOrP2PClient != NULL) {
72 isSta = fcm->op->isDeviceStaOrP2PClient();
73 }
74 if (isSta) {
75 for (i = 0; i < QUEUE_ID_COUNT; i++) {
76 SendFlowControlQueue(fcm, g_staPriorityMapRx[i], FLOW_RX);
77 }
78 } else {
79 for (i = 0; i < QUEUE_ID_COUNT; i++) {
80 SendFlowControlQueue(fcm, g_priorityMapRx[i], FLOW_RX);
81 }
82 }
83 }
84
RunWiFiFlowControl(void * para,FlowDir dir)85 static int32_t RunWiFiFlowControl(void *para, FlowDir dir)
86 {
87 struct FlowControlModule *fcm = (struct FlowControlModule *)para;
88 if (para == NULL || dir >= FLOW_DIR_COUNT) {
89 HDF_LOGE("%s fail: para = null or dir=%d!", __func__, dir);
90 return HDF_ERR_INVALID_PARAM;
91 }
92 HDF_LOGE("%s Enter flow control dir =%d!", __func__, dir);
93 fcm->threadStatus[dir] = THREAD_STARTING;
94 while (true) {
95 fcm->threadStatus[dir] = THREAD_WAITING;
96 if (OsalSemWait(&fcm->sem[dir], HDF_WAIT_FOREVER) != HDF_SUCCESS) {
97 HDF_LOGE("%s exit: OsalSemWait return false!", __func__);
98 continue;
99 }
100 if (IsFcThreadNeedStop(fcm, dir)) {
101 HDF_LOGE("%s exit: because threadStatus[%d] > THREAD_RUNNING!", __func__, dir);
102 break;
103 }
104 fcm->threadStatus[dir] = THREAD_RUNNING;
105 if (dir == FLOW_TX) {
106 FlowControlTxTreadProcess(fcm);
107 } else if (dir == FLOW_RX) {
108 FlowControlRxTreadProcess(fcm);
109 }
110 }
111 HDF_LOGE("%s Exit!", __func__);
112 fcm->threadStatus[dir] = THREAD_STOPPED;
113 return HDF_SUCCESS;
114 }
115
RunWiFiTxFlowControl(void * para)116 static int32_t RunWiFiTxFlowControl(void *para)
117 {
118 return RunWiFiFlowControl(para, FLOW_TX);
119 }
120
RunWiFiRxFlowControl(void * para)121 static int32_t RunWiFiRxFlowControl(void *para)
122 {
123 return RunWiFiFlowControl(para, FLOW_RX);
124 }
125
CreateTask(struct OsalThread * thread,char * taskName,OsalThreadEntry threadEntry,struct OsalThreadParam * para,void * entryPara)126 static int32_t CreateTask(struct OsalThread *thread, char *taskName, OsalThreadEntry threadEntry,
127 struct OsalThreadParam *para, void *entryPara)
128 {
129 int32_t status = OsalThreadCreate(thread, threadEntry, entryPara);
130 para->name = taskName;
131 if (status != HDF_SUCCESS) {
132 HDF_LOGE("%s:OsalThreadCreate failed!status=%d", __func__, status);
133 return HDF_FAILURE;
134 }
135 status = OsalThreadStart(thread, para);
136 if (status != HDF_SUCCESS) {
137 HDF_LOGE("%s:OsalThreadStart failed!status=%d", __func__, status);
138 OsalThreadDestroy(thread);
139 return HDF_FAILURE;
140 }
141 return HDF_SUCCESS;
142 }
143
DestroyTask(struct FlowControlModule * fcm,FlowDir dir)144 static void DestroyTask(struct FlowControlModule *fcm, FlowDir dir)
145 {
146 int count = 0;
147 if (fcm == NULL || dir >= FLOW_DIR_COUNT) {
148 HDF_LOGE("%s fail: fcm = null or dir not right!", __func__);
149 return;
150 }
151 if (fcm->threadStatus[dir] == THREAD_INIT_FAIL || fcm->threadStatus[dir] == THREAD_DESTROYED) {
152 HDF_LOGE("%s,delete thread not need!", __func__);
153 return;
154 }
155 fcm->threadStatus[dir] = THREAD_STOPPING;
156 OsalSemPost(&fcm->sem[dir]);
157
158 /* wait until RunWiFiFlowControl exit */
159 while ((fcm->threadStatus[dir] != THREAD_STOPPED) && (count < MAX_EXIT_THREAD_COUNT)) {
160 OsalMSleep(1);
161 count++;
162 }
163 if (dir == FLOW_TX) {
164 OsalThreadDestroy(&fcm->txTransferThread);
165 } else if (dir == FLOW_RX) {
166 OsalThreadDestroy(&fcm->rxTransferThread);
167 }
168 fcm->threadStatus[dir] = THREAD_DESTROYED;
169 HDF_LOGE("%s delete thread[%d] success!", __func__, dir);
170 return;
171 }
172
CreateFlowControlTask(struct FlowControlModule * fcm)173 int32_t CreateFlowControlTask(struct FlowControlModule *fcm)
174 {
175 int32_t ret;
176 struct OsalThreadParam config;
177 (void)memset_s(&config, sizeof(config), 0, sizeof(config));
178 config.priority = OSAL_THREAD_PRI_HIGHEST;
179 config.stackSize = 0;
180
181 if (fcm == NULL) {
182 HDF_LOGE("%s fail: fcm = null!", __func__);
183 return HDF_ERR_INVALID_PARAM;
184 }
185 ret = CreateTask(&fcm->txTransferThread, RX_THREAD_NAME, RunWiFiTxFlowControl, &config, fcm);
186 if (ret == HDF_FAILURE) {
187 fcm->threadStatus[FLOW_TX] = THREAD_INIT_FAIL;
188 return HDF_FAILURE;
189 }
190 ret = CreateTask(&fcm->rxTransferThread, TX_THREAD_NAME, RunWiFiRxFlowControl, &config, fcm);
191 if (ret == HDF_FAILURE) {
192 fcm->threadStatus[FLOW_TX] = THREAD_INIT_FAIL;
193 fcm->threadStatus[FLOW_RX] = THREAD_INIT_FAIL;
194 DestroyTask(fcm, FLOW_TX);
195 }
196 fcm->threadStatus[FLOW_TX] = THREAD_INIT_SUCCESS;
197 fcm->threadStatus[FLOW_RX] = THREAD_INIT_SUCCESS;
198 return HDF_SUCCESS;
199 }
200
DestroyFlowControlTask(struct FlowControlModule * fcm)201 void DestroyFlowControlTask(struct FlowControlModule *fcm)
202 {
203 if (fcm == NULL) {
204 HDF_LOGE("%s fcm = null", __func__);
205 return;
206 }
207 DestroyTask(fcm, FLOW_TX);
208 DestroyTask(fcm, FLOW_RX);
209 return;
210 }