@@ -107,8 +107,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
107
107
struct minstrel_ht_sta * mi = & msp -> ht ;
108
108
struct minstrel_debugfs_info * ms ;
109
109
unsigned int i ;
110
- char * p ;
111
110
int ret ;
111
+ char * p ;
112
112
113
113
if (!msp -> is_ht ) {
114
114
inode -> i_private = & msp -> legacy ;
@@ -146,7 +146,6 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
146
146
MINSTREL_TRUNC (mi -> avg_ampdu_len ),
147
147
MINSTREL_TRUNC (mi -> avg_ampdu_len * 10 ) % 10 );
148
148
ms -> len = p - ms -> buf ;
149
-
150
149
WARN_ON (ms -> len + sizeof (* ms ) > 32768 );
151
150
152
151
return nonseekable_open (inode , file );
@@ -160,13 +159,148 @@ static const struct file_operations minstrel_ht_stat_fops = {
160
159
.llseek = no_llseek ,
161
160
};
162
161
162
+ static char *
163
+ minstrel_ht_stats_csv_dump (struct minstrel_ht_sta * mi , int i , char * p )
164
+ {
165
+ const struct mcs_group * mg ;
166
+ unsigned int j , tp , prob , eprob , tx_time ;
167
+ char htmode = '2' ;
168
+ char gimode = 'L' ;
169
+ u32 gflags ;
170
+
171
+ if (!mi -> groups [i ].supported )
172
+ return p ;
173
+
174
+ mg = & minstrel_mcs_groups [i ];
175
+ gflags = mg -> flags ;
176
+
177
+ if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH )
178
+ htmode = '4' ;
179
+ else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH )
180
+ htmode = '8' ;
181
+ if (gflags & IEEE80211_TX_RC_SHORT_GI )
182
+ gimode = 'S' ;
183
+
184
+ for (j = 0 ; j < MCS_GROUP_RATES ; j ++ ) {
185
+ struct minstrel_rate_stats * mr = & mi -> groups [i ].rates [j ];
186
+ static const int bitrates [4 ] = { 10 , 20 , 55 , 110 };
187
+ int idx = i * MCS_GROUP_RATES + j ;
188
+
189
+ if (!(mi -> groups [i ].supported & BIT (j )))
190
+ continue ;
191
+
192
+ if (gflags & IEEE80211_TX_RC_MCS ) {
193
+ p += sprintf (p , "HT%c0," , htmode );
194
+ p += sprintf (p , "%cGI," , gimode );
195
+ p += sprintf (p , "%d," , mg -> streams );
196
+ } else if (gflags & IEEE80211_TX_RC_VHT_MCS ) {
197
+ p += sprintf (p , "VHT%c0," , htmode );
198
+ p += sprintf (p , "%cGI," , gimode );
199
+ p += sprintf (p , "%d," , mg -> streams );
200
+ } else {
201
+ p += sprintf (p , "CCK," );
202
+ p += sprintf (p , "%cP," , j < 4 ? 'L' : 'S' );
203
+ p += sprintf (p , "1," );
204
+ }
205
+
206
+ p += sprintf (p , "%s" ,((idx == mi -> max_tp_rate [0 ]) ? "A" : "" ));
207
+ p += sprintf (p , "%s" ,((idx == mi -> max_tp_rate [1 ]) ? "B" : "" ));
208
+ p += sprintf (p , "%s" ,((idx == mi -> max_tp_rate [2 ]) ? "C" : "" ));
209
+ p += sprintf (p , "%s" ,((idx == mi -> max_tp_rate [3 ]) ? "D" : "" ));
210
+ p += sprintf (p , "%s" ,((idx == mi -> max_prob_rate ) ? "P" : "" ));
211
+
212
+ if (gflags & IEEE80211_TX_RC_MCS ) {
213
+ p += sprintf (p , ",MCS%-2u," , (mg -> streams - 1 ) * 8 + j );
214
+ } else if (gflags & IEEE80211_TX_RC_VHT_MCS ) {
215
+ p += sprintf (p , ",MCS%-1u/%1u," , j , mg -> streams );
216
+ } else {
217
+ int r = bitrates [j % 4 ];
218
+ p += sprintf (p , ",%2u.%1uM," , r / 10 , r % 10 );
219
+ }
220
+
221
+ p += sprintf (p , "%u," , idx );
222
+ tx_time = DIV_ROUND_CLOSEST (mg -> duration [j ], 1000 );
223
+ p += sprintf (p , "%u," , tx_time );
224
+
225
+ tp = mr -> cur_tp / 10 ;
226
+ prob = MINSTREL_TRUNC (mr -> cur_prob * 1000 );
227
+ eprob = MINSTREL_TRUNC (mr -> probability * 1000 );
228
+
229
+ p += sprintf (p , "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu," ,
230
+ tp / 10 , tp % 10 ,
231
+ eprob / 10 , eprob % 10 ,
232
+ prob / 10 , prob % 10 ,
233
+ mr -> retry_count ,
234
+ mr -> last_success ,
235
+ mr -> last_attempts ,
236
+ (unsigned long long )mr -> succ_hist ,
237
+ (unsigned long long )mr -> att_hist );
238
+ p += sprintf (p , "%d,%d,%d.%d\n" ,
239
+ max (0 , (int ) mi -> total_packets -
240
+ (int ) mi -> sample_packets ),
241
+ mi -> sample_packets ,
242
+ MINSTREL_TRUNC (mi -> avg_ampdu_len ),
243
+ MINSTREL_TRUNC (mi -> avg_ampdu_len * 10 ) % 10 );
244
+ }
245
+
246
+ return p ;
247
+ }
248
+
249
+ static int
250
+ minstrel_ht_stats_csv_open (struct inode * inode , struct file * file )
251
+ {
252
+ struct minstrel_ht_sta_priv * msp = inode -> i_private ;
253
+ struct minstrel_ht_sta * mi = & msp -> ht ;
254
+ struct minstrel_debugfs_info * ms ;
255
+ unsigned int i ;
256
+ int ret ;
257
+ char * p ;
258
+
259
+ if (!msp -> is_ht ) {
260
+ inode -> i_private = & msp -> legacy ;
261
+ ret = minstrel_stats_csv_open (inode , file );
262
+ inode -> i_private = msp ;
263
+ return ret ;
264
+ }
265
+
266
+ ms = kmalloc (32768 , GFP_KERNEL );
267
+
268
+ if (!ms )
269
+ return - ENOMEM ;
270
+
271
+ file -> private_data = ms ;
272
+
273
+ p = ms -> buf ;
274
+
275
+ p = minstrel_ht_stats_csv_dump (mi , MINSTREL_CCK_GROUP , p );
276
+ for (i = 0 ; i < MINSTREL_CCK_GROUP ; i ++ )
277
+ p = minstrel_ht_stats_csv_dump (mi , i , p );
278
+ for (i ++ ; i < ARRAY_SIZE (mi -> groups ); i ++ )
279
+ p = minstrel_ht_stats_csv_dump (mi , i , p );
280
+
281
+ ms -> len = p - ms -> buf ;
282
+ WARN_ON (ms -> len + sizeof (* ms ) > 32768 );
283
+
284
+ return nonseekable_open (inode , file );
285
+ }
286
+
287
+ static const struct file_operations minstrel_ht_stat_csv_fops = {
288
+ .owner = THIS_MODULE ,
289
+ .open = minstrel_ht_stats_csv_open ,
290
+ .read = minstrel_stats_read ,
291
+ .release = minstrel_stats_release ,
292
+ .llseek = no_llseek ,
293
+ };
294
+
163
295
void
164
296
minstrel_ht_add_sta_debugfs (void * priv , void * priv_sta , struct dentry * dir )
165
297
{
166
298
struct minstrel_ht_sta_priv * msp = priv_sta ;
167
299
168
300
msp -> dbg_stats = debugfs_create_file ("rc_stats" , S_IRUGO , dir , msp ,
169
301
& minstrel_ht_stat_fops );
302
+ msp -> dbg_stats_csv = debugfs_create_file ("rc_stats_csv" , S_IRUGO ,
303
+ dir , msp , & minstrel_ht_stat_csv_fops );
170
304
}
171
305
172
306
void
@@ -175,4 +309,5 @@ minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
175
309
struct minstrel_ht_sta_priv * msp = priv_sta ;
176
310
177
311
debugfs_remove (msp -> dbg_stats );
312
+ debugfs_remove (msp -> dbg_stats_csv );
178
313
}
0 commit comments