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