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 }