[RAMEN9610-20413][9610] wlbt: SCSC Driver version 10.6.1.0
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / drivers / net / wireless / scsc / hip4_sampler.c
1 /*****************************************************************************
2 *
3 * Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd. All rights reserved
4 *
5 ****************************************************************************/
6 #include <linux/module.h>
7 #include <linux/moduleparam.h>
8 #include <linux/init.h>
9 #include <linux/kfifo.h>
10 #include <linux/poll.h>
11 #include <linux/wait.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
15 #include <linux/fs.h>
16 #include <linux/errno.h>
17 #include <linux/types.h>
18 #include <linux/mm.h>
19 #include <linux/version.h>
20 #include <linux/hardirq.h>
21 #include <linux/cpufreq.h>
22
23 #include <linux/ktime.h>
24 #include <linux/hrtimer.h>
25 #include <asm/page.h>
26 #include <linux/cdev.h>
27 #include <linux/device.h>
28 #include <scsc/scsc_mx.h>
29 #ifdef CONFIG_SCSC_LOG_COLLECTION
30 #include <scsc/scsc_log_collector.h>
31 #endif
32 #include <linux/delay.h>
33 #include <linux/mutex.h>
34 #include "hip4_sampler.h"
35
36 #include "debug.h"
37
38 struct hip4_record {
39 u32 record_num;
40 ktime_t ts;
41 u32 record;
42 u32 record2;
43 } __packed;
44
45 static atomic_t in_read;
46
47 /* Create a global spinlock for all the instances */
48 /* It is less efficent, but we simplify the implementation */
49 static spinlock_t g_spinlock;
50
51 static bool hip4_sampler_enable = true;
52 module_param(hip4_sampler_enable, bool, S_IRUGO | S_IWUSR);
53 MODULE_PARM_DESC(hip4_sampler_enable, "Enable hip4_sampler_enable. Run-time option - (default: Y)");
54
55 static bool hip4_sampler_dynamic = true;
56 module_param(hip4_sampler_dynamic, bool, S_IRUGO | S_IWUSR);
57 MODULE_PARM_DESC(hip4_sampler_dynamic, "Enable hip4_sampler dynamic adaptation based on TPUT. Run-time option - (default: Y)");
58
59 static int hip4_sampler_kfifo_len = 128 * 1024;
60 module_param(hip4_sampler_kfifo_len, int, S_IRUGO | S_IWUSR);
61 MODULE_PARM_DESC(hip4_sampler_kfifo_len, "Streaming fifo buffer length in num of records- default: 262144 Max: 262144. Loaded at /dev open");
62
63 static int hip4_sampler_static_kfifo_len = 128 * 1024;
64 module_param(hip4_sampler_static_kfifo_len, int, S_IRUGO | S_IWUSR);
65 MODULE_PARM_DESC(hip4_sampler_static_kfifo_len, "Offline fifo buffer length in num of records- default: 262144 Max: 262144. Loaded at /dev open");
66
67 bool hip4_sampler_sample_q = true;
68 module_param(hip4_sampler_sample_q, bool, S_IRUGO | S_IWUSR);
69 MODULE_PARM_DESC(hip4_sampler_sample_q, "Sample Queues. Default: Y. Run time option");
70
71 bool hip4_sampler_sample_qref = true;
72 module_param(hip4_sampler_sample_qref, bool, S_IRUGO | S_IWUSR);
73 MODULE_PARM_DESC(hip4_sampler_sample_qref, "Sample Queue References. Default: Y. Run time option");
74
75 bool hip4_sampler_sample_int = true;
76 module_param(hip4_sampler_sample_int, bool, S_IRUGO | S_IWUSR);
77 MODULE_PARM_DESC(hip4_sampler_sample_int, "Sample WQ/Tasklet Intr BH in/out. Default: Y. Run time option");
78
79 bool hip4_sampler_sample_fapi = true;
80 module_param(hip4_sampler_sample_fapi, bool, S_IRUGO | S_IWUSR);
81 MODULE_PARM_DESC(hip4_sampler_sample_fapi, "Sample FAPI ctrl signals. Default: Y. Run time option");
82
83 bool hip4_sampler_sample_through = true;
84 module_param(hip4_sampler_sample_through, bool, S_IRUGO | S_IWUSR);
85 MODULE_PARM_DESC(hip4_sampler_sample_through, "Sample throughput. Default: Y. Run time option");
86
87 bool hip4_sampler_sample_tcp = true;
88 module_param(hip4_sampler_sample_tcp, bool, S_IRUGO | S_IWUSR);
89 MODULE_PARM_DESC(hip4_sampler_sample_tcp, "Sample TCP streams. Default: Y. Run time option");
90
91 bool hip4_sampler_sample_start_stop_q = true;
92 module_param(hip4_sampler_sample_start_stop_q, bool, S_IRUGO | S_IWUSR);
93 MODULE_PARM_DESC(hip4_sampler_sample_start_stop_q, "Sample Stop/Start queues. Default: Y. Run time option");
94
95 bool hip4_sampler_sample_mbulk = true;
96 module_param(hip4_sampler_sample_mbulk, bool, S_IRUGO | S_IWUSR);
97 MODULE_PARM_DESC(hip4_sampler_sample_mbulk, "Sample Mbulk counter. Default: Y. Run time option");
98
99 bool hip4_sampler_sample_qfull;
100 module_param(hip4_sampler_sample_qfull, bool, S_IRUGO | S_IWUSR);
101 MODULE_PARM_DESC(hip4_sampler_sample_qfull, "Sample Q full event. Default: N. Run time option");
102
103 bool hip4_sampler_sample_mfull = true;
104 module_param(hip4_sampler_sample_mfull, bool, S_IRUGO | S_IWUSR);
105 MODULE_PARM_DESC(hip4_sampler_sample_mfull, "Sample Mbulk full event. Default: Y. Run time option");
106
107 bool hip4_sampler_vif = true;
108 module_param(hip4_sampler_vif, bool, S_IRUGO | S_IWUSR);
109 MODULE_PARM_DESC(hip4_sampler_vif, "Sample VIF. Default: Y. Run time option");
110
111 bool hip4_sampler_bot = true;
112 module_param(hip4_sampler_bot, bool, S_IRUGO | S_IWUSR);
113 MODULE_PARM_DESC(hip4_sampler_bot, "Sample BOT. Default: Y. Run time option");
114
115 bool hip4_sampler_pkt_tx = true;
116 module_param(hip4_sampler_pkt_tx, bool, S_IRUGO | S_IWUSR);
117 MODULE_PARM_DESC(hip4_sampler_pkt_tx, "Track TX Data packet TX->HIP4->FB. Default: Y. Run time option");
118
119 bool hip4_sampler_suspend_resume = true;
120 module_param(hip4_sampler_suspend_resume, bool, S_IRUGO | S_IWUSR);
121 MODULE_PARM_DESC(hip4_sampler_suspend_resume, "Sample Suspend/Resume events. Default: Y. Run time option");
122
123 #define HIP4_TPUT_HLIMIT 400000000 /* 400Mbps */
124 #define HIP4_TPUT_LLIMIT 350000000 /* 350Mbps */
125 #define HIP4_TPUT_HSECONDS 1
126 #define HIP4_TPUT_LSECONDS 5
127
128 static bool hip4_sampler_sample_q_hput;
129 static bool hip4_sampler_sample_qref_hput;
130 static bool hip4_sampler_sample_int_hput;
131 static bool hip4_sampler_sample_fapi_hput;
132 /* static bool hip4_sampler_sample_through_hput; */
133 /* static bool hip4_sampler_sample_start_stop_q_hput; */
134 /* static bool hip4_sampler_sample_mbulk_hput; */
135 /* static bool hip4_sampler_sample_qfull_hput; */
136 /* static bool hip4_sampler_sample_mfull_hput; */
137 static bool hip4_sampler_vif_hput;
138 static bool hip4_sampler_bot_hput;
139 static bool hip4_sampler_pkt_tx_hput;
140 static bool hip4_sampler_suspend_resume_hput;
141
142 static bool hip4_sampler_in_htput;
143 static u16 hip4_sampler_in_htput_seconds;
144
145 #define DRV_NAME "hip4_sampler"
146 #define DEVICE_NAME "hip4_sampler"
147
148 #ifndef VM_RESERVED
149 #define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
150 #endif
151
152 #define VER_MAJOR 0
153 #define VER_MINOR 0
154
155 DECLARE_BITMAP(bitmap_hip4_sampler_minor, SCSC_HIP4_DEBUG_INTERFACES);
156
157 enum hip4_dg_errors {
158 NO_ERROR = 0,
159 BUFFER_OVERFLOW,
160 KFIFO_ERROR,
161 KFIFO_FULL,
162 };
163
164 enum hip4_type {
165 STREAMING = 0,
166 OFFLINE,
167 };
168
169 struct hip4_sampler_dev {
170 /* file pointer */
171 struct file *filp;
172 /* char device */
173 struct cdev cdev;
174 /*device pointer*/
175 struct device *dev;
176 /*mx pointer*/
177 struct scsc_mx *mx;
178 /* Associated kfifo */
179 DECLARE_KFIFO_PTR(fifo, struct hip4_record);
180 /* Associated read_wait queue.*/
181 wait_queue_head_t read_wait;
182 /* Device in error */
183 enum hip4_dg_errors error;
184 /* Device node mutex for fops */
185 struct mutex mutex;
186 /* Record number */
187 u32 record_num;
188 /* To profile kfifo num elements */
189 u32 kfifo_max;
190 /* Sampler type streaming/offline */
191 enum hip4_type type;
192 /* reference to minor number */
193 u32 minor;
194 };
195
196 /**
197 * SCSC User Space debug sampler interface (singleton)
198 */
199 static struct {
200 bool init;
201 dev_t device;
202 struct class *class_hip4_sampler;
203 struct hip4_sampler_dev devs[SCSC_HIP4_DEBUG_INTERFACES];
204 } hip4_sampler;
205
206 void __hip4_sampler_update_record(struct hip4_sampler_dev *hip4_dev, u32 minor, u8 param1, u8 param2, u8 param3, u8 param4, u32 param5)
207 {
208 struct hip4_record ev;
209 u32 ret;
210 u32 cpu;
211 u32 freq = 0;
212
213 /* If char device if open, use streaming buffer */
214 if (hip4_dev->filp) {
215 /* put string into the Streaming fifo */
216 if (kfifo_avail(&hip4_dev->fifo)) {
217 /* Push values in Fifo*/
218 cpu = smp_processor_id();
219 if (hip4_dev->record_num % 64 == 0)
220 freq = (cpufreq_quick_get(cpu) / 1000) & 0xfff;
221 ev.record_num = (0x0000ffff & hip4_dev->record_num++) | (cpu << 28) | (freq << 16);
222 ev.ts = ktime_get();
223 ev.record = ((param1 & 0xff) << 24) | ((param2 & 0xff) << 16) | ((param3 & 0xff) << 8) | (param4 & 0xff);
224 ev.record2 = param5;
225 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
226 kfifo_put(&hip4_dev->fifo, ev);
227 #else
228 kfifo_put(&hip4_dev->fifo, &ev);
229 #endif
230 ret = kfifo_len(&hip4_dev->fifo);
231 if (ret > hip4_dev->kfifo_max)
232 hip4_dev->kfifo_max = ret;
233 } else {
234 hip4_dev->error = KFIFO_FULL;
235 return;
236 }
237 wake_up_interruptible(&hip4_dev->read_wait);
238 /* If streaming buffer is not in use, put samples in offline buffer */
239 } else {
240 /* Get associated Offline buffer */
241 hip4_dev = &hip4_sampler.devs[minor + 1];
242 /* Record in offline fifo */
243 /* if fifo is full, remove last item */
244 if (kfifo_is_full(&hip4_dev->fifo))
245 ret = kfifo_get(&hip4_dev->fifo, &ev);
246 cpu = smp_processor_id();
247 if (hip4_dev->record_num % 64 == 0)
248 freq = (cpufreq_quick_get(cpu) / 1000) & 0xfff;
249 /* Push values in Static Fifo*/
250 ev.record_num = (0x0000ffff & hip4_dev->record_num++) | (cpu << 28) | (freq << 16);
251 ev.ts = ktime_get();
252 ev.record = ((param1 & 0xff) << 24) | ((param2 & 0xff) << 16) | ((param3 & 0xff) << 8) | (param4 & 0xff);
253 ev.record2 = param5;
254 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
255 kfifo_put(&hip4_dev->fifo, ev);
256 #else
257 kfifo_put(&hip4_dev->fifo, &ev);
258 #endif
259 }
260 }
261
262 void hip4_sampler_update_record(u32 minor, u8 param1, u8 param2, u8 param3, u8 param4, u32 param5)
263 {
264 struct hip4_sampler_dev *hip4_dev;
265 unsigned long flags;
266
267 if (!hip4_sampler_enable || !hip4_sampler.init)
268 return;
269
270 if (atomic_read(&in_read))
271 return;
272
273 if (minor >= SCSC_HIP4_INTERFACES)
274 return;
275
276 spin_lock_irqsave(&g_spinlock, flags);
277 hip4_dev = &hip4_sampler.devs[minor];
278 __hip4_sampler_update_record(hip4_dev, minor, param1, param2, param3, param4, param5);
279 spin_unlock_irqrestore(&g_spinlock, flags);
280 }
281
282 static void hip4_sampler_store_param(void)
283 {
284 hip4_sampler_sample_q_hput = hip4_sampler_sample_q;
285 hip4_sampler_sample_qref_hput = hip4_sampler_sample_qref;
286 hip4_sampler_sample_int_hput = hip4_sampler_sample_int;
287 hip4_sampler_sample_fapi_hput = hip4_sampler_sample_fapi;
288 /* hip4_sampler_sample_through_hput = hip4_sampler_sample_through; */
289 /* hip4_sampler_sample_start_stop_q_hput = hip4_sampler_sample_start_stop_q; */
290 /* hip4_sampler_sample_mbulk_hput = hip4_sampler_sample_mbulk; */
291 /* hip4_sampler_sample_qfull_hput = hip4_sampler_sample_qfull; */
292 /* hip4_sampler_sample_mfull_hput = hip4_sampler_sample_mfull; */
293 hip4_sampler_vif_hput = hip4_sampler_vif;
294 hip4_sampler_bot_hput = hip4_sampler_bot;
295 hip4_sampler_pkt_tx_hput = hip4_sampler_pkt_tx;
296 hip4_sampler_suspend_resume_hput = hip4_sampler_suspend_resume;
297
298 /* Reset values to avoid contention */
299 hip4_sampler_sample_q = false;
300 hip4_sampler_sample_qref = false;
301 hip4_sampler_sample_int = false;
302 hip4_sampler_sample_fapi = false;
303 /* hip4_sampler_sample_through_hput = false; */
304 /* hip4_sampler_sample_start_stop_q_hput = false; */
305 /* hip4_sampler_sample_mbulk = false; */
306 /* hip4_sampler_sample_qfull_hput = false; */
307 /* hip4_sampler_sample_mfull_hput = false; */
308 hip4_sampler_vif = false;
309 hip4_sampler_bot = false;
310 hip4_sampler_pkt_tx = false;
311 hip4_sampler_suspend_resume = false;
312 }
313
314 static void hip4_sampler_restore_param(void)
315 {
316 hip4_sampler_sample_q = hip4_sampler_sample_q_hput;
317 hip4_sampler_sample_qref = hip4_sampler_sample_qref_hput;
318 hip4_sampler_sample_int = hip4_sampler_sample_int_hput;
319 hip4_sampler_sample_fapi = hip4_sampler_sample_fapi_hput;
320 /* hip4_sampler_sample_through = hip4_sampler_sample_through_hput; */
321 /* hip4_sampler_sample_start_stop_q = hip4_sampler_sample_start_stop_q_hput; */
322 /* hip4_sampler_sample_mbulk = hip4_sampler_sample_mbulk_hput; */
323 /* hip4_sampler_sample_qfull = hip4_sampler_sample_qfull_hput; */
324 /* hip4_sampler_sample_mfull = hip4_sampler_sample_mfull_hput; */
325 hip4_sampler_vif = hip4_sampler_vif_hput;
326 hip4_sampler_bot = hip4_sampler_bot_hput;
327 hip4_sampler_pkt_tx = hip4_sampler_pkt_tx_hput;
328 hip4_sampler_suspend_resume = hip4_sampler_suspend_resume_hput;
329 }
330
331 static void hip4_sampler_dynamic_switcher(u32 bps)
332 {
333 /* Running in htput, */
334 if (hip4_sampler_in_htput) {
335 if (bps < HIP4_TPUT_LLIMIT) {
336 /* bps went down , count number of times to switch */
337 hip4_sampler_in_htput_seconds++;
338 if (hip4_sampler_in_htput_seconds >= HIP4_TPUT_LSECONDS) {
339 /* HIP4_TPUT_LSECONDS have passed, switch to low tput samples */
340 hip4_sampler_in_htput = false;
341 hip4_sampler_in_htput_seconds = 0;
342 hip4_sampler_restore_param();
343 }
344 } else {
345 hip4_sampler_in_htput_seconds = 0;
346 }
347 } else {
348 if (bps > HIP4_TPUT_HLIMIT) {
349 /* bps went up, count number of times to switch */
350 hip4_sampler_in_htput_seconds++;
351 if (hip4_sampler_in_htput_seconds >= HIP4_TPUT_HSECONDS) {
352 /* HIP4_TPUT_LSECONDS have passed, switch to high tput samples */
353 hip4_sampler_in_htput = true;
354 hip4_sampler_in_htput_seconds = 0;
355 hip4_sampler_store_param();
356 }
357 } else {
358 hip4_sampler_in_htput_seconds = 0;
359 }
360 }
361 }
362
363 static u32 g_tput_rx;
364 static u32 g_tput_tx;
365
366 void hip4_sampler_tput_monitor(void *client_ctx, u32 state, u32 tput_tx, u32 tput_rx)
367 {
368 struct hip4_sampler_dev *hip4_sampler_dev = (struct hip4_sampler_dev *)client_ctx;
369
370 if (!hip4_sampler_enable)
371 return;
372
373 if ((g_tput_tx == tput_tx) && (g_tput_rx == tput_rx))
374 return;
375
376 g_tput_tx = tput_tx;
377 g_tput_rx = tput_rx;
378
379 if (hip4_sampler_dynamic) {
380 /* Call the dynamic switcher with the computed bps
381 * The algorithm will decide to not change, decrease
382 * or increase the sampler verbosity
383 */
384 if (tput_rx > tput_tx)
385 hip4_sampler_dynamic_switcher(tput_rx);
386 else
387 hip4_sampler_dynamic_switcher(tput_tx);
388 }
389
390 /* Generate the TX sample, in bps, Kbps, or Mbps */
391 if (tput_tx < 1000) {
392 SCSC_HIP4_SAMPLER_THROUG(hip4_sampler_dev->minor, 1, (tput_tx & 0xff00) >> 8, tput_tx & 0xff);
393 } else if ((tput_tx >= 1000) && (tput_tx < (1000 * 1000))) {
394 tput_tx = tput_tx / 1000;
395 SCSC_HIP4_SAMPLER_THROUG_K(hip4_sampler_dev->minor, 1, (tput_tx & 0xff00) >> 8, tput_tx & 0xff);
396 } else {
397 tput_tx = tput_tx / (1000 * 1000);
398 SCSC_HIP4_SAMPLER_THROUG_M(hip4_sampler_dev->minor, 1, (tput_tx & 0xff00) >> 8, tput_tx & 0xff);
399 }
400
401 /* Generate the RX sample, in bps, Kbps, or Mbps */
402 if (tput_rx < 1000) {
403 SCSC_HIP4_SAMPLER_THROUG(hip4_sampler_dev->minor, 0, (tput_rx & 0xff00) >> 8, tput_rx & 0xff);
404 } else if ((tput_rx >= 1000) && (tput_rx < (1000 * 1000))) {
405 tput_rx = tput_rx / 1000;
406 SCSC_HIP4_SAMPLER_THROUG_K(hip4_sampler_dev->minor, 0, (tput_rx & 0xff00) >> 8, tput_rx & 0xff);
407 } else {
408 tput_rx = tput_rx / (1000 * 1000);
409 SCSC_HIP4_SAMPLER_THROUG_M(hip4_sampler_dev->minor, 0, (tput_rx & 0xff00) >> 8, tput_rx & 0xff);
410 }
411 }
412
413 void hip4_sampler_tcp_decode(struct slsi_dev *sdev, struct net_device *dev, u8 *frame, bool from_ba)
414 {
415 struct tcphdr *tcp_hdr;
416 struct ethhdr *ehdr = (struct ethhdr *)(frame);
417 struct netdev_vif *ndev_vif = netdev_priv(dev);
418 u8 *ip_frame;
419 u16 ip_data_offset;
420 u8 hlen;
421 u16 len;
422 u8 proto;
423 u8 idx;
424
425 if (be16_to_cpu(ehdr->h_proto) != ETH_P_IP)
426 return;
427
428 ip_frame = frame + ETH_HLEN;
429 proto = ip_frame[9];
430
431 if (proto != IPPROTO_TCP)
432 return;
433
434 ip_data_offset = 20;
435 hlen = ip_frame[0] & 0x0F;
436 len = ip_frame[2] << 8 | ip_frame[3];
437
438 if (hlen > 5)
439 ip_data_offset += (hlen - 5) * 4;
440
441 tcp_hdr = (struct tcphdr *)(ip_frame + ip_data_offset);
442
443 /* Search for an existing record on this connection. */
444 for (idx = 0; idx < TCP_ACK_SUPPRESSION_RECORDS_MAX; idx++) {
445 struct slsi_tcp_ack_s *tcp_ack;
446 u32 rwnd = 0;
447
448 tcp_ack = &ndev_vif->ack_suppression[idx];
449 slsi_spinlock_lock(&tcp_ack->lock);
450 if ((tcp_ack->dport == tcp_hdr->source) && (tcp_ack->sport == tcp_hdr->dest)) {
451 if (from_ba && tcp_hdr->syn && tcp_hdr->ack) {
452 unsigned char *options;
453 u32 optlen = 0, len = 0;
454
455 if (tcp_hdr->doff > 5)
456 optlen = (tcp_hdr->doff - 5) * 4;
457
458 options = (u8 *)tcp_hdr + TCP_ACK_SUPPRESSION_OPTIONS_OFFSET;
459
460 while (optlen > 0) {
461 switch (options[0]) {
462 case TCP_ACK_SUPPRESSION_OPTION_EOL:
463 len = 1;
464 break;
465 case TCP_ACK_SUPPRESSION_OPTION_NOP:
466 len = 1;
467 break;
468 case TCP_ACK_SUPPRESSION_OPTION_WINDOW:
469 tcp_ack->rx_window_scale = options[2];
470 len = options[1];
471 break;
472 default:
473 len = options[1];
474 break;
475 }
476 /* if length field in TCP options is 0, or greater than
477 * total options length, then options are incorrect
478 */
479 if ((len == 0) || (len >= optlen))
480 break;
481
482 if (optlen >= len)
483 optlen -= len;
484 else
485 optlen = 0;
486 options += len;
487 }
488 }
489 if (len > ((hlen * 4) + (tcp_hdr->doff * 4))) {
490 if (from_ba)
491 SCSC_HIP4_SAMPLER_TCP_DATA(sdev->minor_prof, tcp_ack->stream_id, tcp_hdr->seq);
492 else
493 SCSC_HIP4_SAMPLER_TCP_DATA_IN(sdev->minor_prof, tcp_ack->stream_id, tcp_hdr->seq);
494 } else {
495 if (tcp_ack->rx_window_scale)
496 rwnd = be16_to_cpu(tcp_hdr->window) * (2 << tcp_ack->rx_window_scale);
497 else
498 rwnd = be16_to_cpu(tcp_hdr->window);
499 if (from_ba) {
500 SCSC_HIP4_SAMPLER_TCP_ACK(sdev->minor_prof, tcp_ack->stream_id, be32_to_cpu(tcp_hdr->ack_seq));
501 SCSC_HIP4_SAMPLER_TCP_RWND(sdev->minor_prof, tcp_ack->stream_id, rwnd);
502 } else {
503 SCSC_HIP4_SAMPLER_TCP_ACK_IN(sdev->minor_prof, tcp_ack->stream_id, be32_to_cpu(tcp_hdr->ack_seq));
504 }
505 }
506 slsi_spinlock_unlock(&tcp_ack->lock);
507 break;
508 }
509 slsi_spinlock_unlock(&tcp_ack->lock);
510 }
511 }
512
513 #ifdef CONFIG_SCSC_LOG_COLLECTION
514 int hip4_collect_init(struct scsc_log_collector_client *collect_client)
515 {
516 /* Stop Sampling */
517 atomic_set(&in_read, 1);
518 return 0;
519 }
520
521 int hip4_collect(struct scsc_log_collector_client *collect_client, size_t size)
522 {
523 int i = SCSC_HIP4_DEBUG_INTERFACES;
524 int ret = 0;
525 unsigned long flags;
526 u32 num_samples;
527 struct hip4_sampler_dev *hip4_dev;
528 void *buf;
529
530 SLSI_INFO_NODEV("Triggered log collection in hip4_sampler\n");
531
532 if (!hip4_sampler_enable)
533 return 0;
534
535 while (i--)
536 if (hip4_sampler.devs[i].mx == collect_client->prv && hip4_sampler.devs[i].type == OFFLINE) {
537 hip4_dev = &hip4_sampler.devs[i];
538 num_samples = kfifo_len(&hip4_dev->fifo);
539 if (!num_samples)
540 continue;
541 buf = vmalloc(num_samples * sizeof(struct hip4_record));
542 if (!buf)
543 continue;
544 spin_lock_irqsave(&g_spinlock, flags);
545 ret = kfifo_out(&hip4_dev->fifo, buf, num_samples);
546 spin_unlock_irqrestore(&g_spinlock, flags);
547 if (!ret)
548 goto error;
549 SLSI_DBG1_NODEV(SLSI_HIP, "num_samples %d ret %d size of hip4_record %zu\n", num_samples, ret, sizeof(struct hip4_record));
550 ret = scsc_log_collector_write(buf, ret * sizeof(struct hip4_record), 1);
551 if (ret)
552 goto error;
553 vfree(buf);
554 }
555 return 0;
556 error:
557 vfree(buf);
558 return ret;
559 }
560
561 int hip4_collect_end(struct scsc_log_collector_client *collect_client)
562 {
563 /* Restart sampling */
564 atomic_set(&in_read, 0);
565 return 0;
566 }
567
568 /* Collect client registration */
569 struct scsc_log_collector_client hip4_collect_client = {
570 .name = "HIP4 Sampler",
571 .type = SCSC_LOG_CHUNK_HIP4_SAMPLER,
572 .collect_init = hip4_collect_init,
573 .collect = hip4_collect,
574 .collect_end = hip4_collect_end,
575 .prv = NULL,
576 };
577 #endif
578
579 static int hip4_sampler_open(struct inode *inode, struct file *filp)
580 {
581 struct hip4_sampler_dev *hip4_dev;
582 int ret = 0;
583
584 hip4_dev = container_of(inode->i_cdev, struct hip4_sampler_dev, cdev);
585
586 if (hip4_dev->type == OFFLINE) {
587 /* Offline buffer skip open */
588 filp->private_data = hip4_dev;
589 return 0;
590 }
591 if (mutex_lock_interruptible(&hip4_dev->mutex))
592 return -ERESTARTSYS;
593
594 if (filp->private_data) {
595 SLSI_INFO_NODEV("Service already started\n");
596 ret = 0;
597 goto end;
598 }
599
600 if (hip4_sampler_kfifo_len > 256 * 1024) {
601 SLSI_DBG1_NODEV(SLSI_HIP, "hip4_sampler_kfifo_len %d > 2262144. Set to MAX", hip4_sampler_kfifo_len);
602 hip4_sampler_kfifo_len = 256 * 1024;
603 }
604
605 ret = kfifo_alloc(&hip4_dev->fifo, hip4_sampler_kfifo_len, GFP_KERNEL);
606 if (ret) {
607 SLSI_ERR_NODEV("kfifo_alloc failed");
608 ret = -ENOMEM;
609 goto end;
610 }
611
612 filp->private_data = hip4_dev;
613
614 /* Clear any remaining error */
615 hip4_dev->error = NO_ERROR;
616
617 hip4_dev->record_num = 0;
618 hip4_dev->kfifo_max = 0;
619 hip4_dev->filp = filp;
620
621 SLSI_INFO_NODEV("%s: Sampling....\n", DRV_NAME);
622 end:
623 mutex_unlock(&hip4_dev->mutex);
624 return ret;
625 }
626
627 static ssize_t hip4_sampler_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
628 {
629 unsigned int copied;
630 int ret = 0;
631 struct hip4_sampler_dev *hip4_dev;
632
633 hip4_dev = filp->private_data;
634
635 if (hip4_dev->type == OFFLINE) {
636 /* Offline buffer skip open */
637 if (mutex_lock_interruptible(&hip4_dev->mutex))
638 return -EINTR;
639 atomic_set(&in_read, 1);
640 ret = kfifo_to_user(&hip4_dev->fifo, buf, len, &copied);
641 mutex_unlock(&hip4_dev->mutex);
642 return ret ? ret : copied;
643 }
644
645 if (mutex_lock_interruptible(&hip4_dev->mutex))
646 return -EINTR;
647
648 /* Check whether the device is in error */
649 if (hip4_dev->error != NO_ERROR) {
650 SLSI_ERR_NODEV("Device in error\n");
651 ret = -EIO;
652 goto end;
653 }
654
655 while (len) {
656 if (kfifo_len(&hip4_dev->fifo)) {
657 ret = kfifo_to_user(&hip4_dev->fifo, buf, len, &copied);
658 if (!ret)
659 ret = copied;
660 break;
661 }
662
663 if (filp->f_flags & O_NONBLOCK) {
664 ret = -EAGAIN;
665 break;
666 }
667
668 ret = wait_event_interruptible(hip4_dev->read_wait,
669 !kfifo_is_empty(&hip4_dev->fifo));
670 if (ret < 0)
671 break;
672 }
673 end:
674 mutex_unlock(&hip4_dev->mutex);
675 return ret;
676 }
677
678 static unsigned hip4_sampler_poll(struct file *filp, poll_table *wait)
679 {
680 struct hip4_sampler_dev *hip4_dev;
681 int ret;
682
683 hip4_dev = filp->private_data;
684
685 if (hip4_dev->type == OFFLINE)
686 /* Offline buffer skip poll */
687 return 0;
688
689 if (mutex_lock_interruptible(&hip4_dev->mutex))
690 return -EINTR;
691
692 if (hip4_dev->error != NO_ERROR) {
693 ret = POLLERR;
694 goto end;
695 }
696
697 poll_wait(filp, &hip4_dev->read_wait, wait);
698
699 if (!kfifo_is_empty(&hip4_dev->fifo)) {
700 ret = POLLIN | POLLRDNORM; /* readeable */
701 goto end;
702 }
703
704 ret = POLLOUT | POLLWRNORM; /* writable */
705
706 end:
707 mutex_unlock(&hip4_dev->mutex);
708 return ret;
709 }
710
711 static int hip4_sampler_release(struct inode *inode, struct file *filp)
712 {
713 struct hip4_sampler_dev *hip4_dev;
714
715 hip4_dev = container_of(inode->i_cdev, struct hip4_sampler_dev, cdev);
716
717 if (hip4_dev->type == OFFLINE) {
718 atomic_set(&in_read, 0);
719 /* Offline buffer skip release */
720 return 0;
721 }
722
723 if (mutex_lock_interruptible(&hip4_dev->mutex))
724 return -EINTR;
725
726 if (!hip4_dev->filp) {
727 SLSI_ERR_NODEV("Device already closed\n");
728 mutex_unlock(&hip4_dev->mutex);
729 return -EIO;
730 }
731
732 if (hip4_dev != filp->private_data) {
733 SLSI_ERR_NODEV("Data mismatch\n");
734 mutex_unlock(&hip4_dev->mutex);
735 return -EIO;
736 }
737
738 filp->private_data = NULL;
739 hip4_dev->filp = NULL;
740 kfifo_free(&hip4_dev->fifo);
741
742 mutex_unlock(&hip4_dev->mutex);
743 SLSI_INFO_NODEV("%s: Sampling... end. Kfifo_max = %d\n", DRV_NAME, hip4_dev->kfifo_max);
744 return 0;
745 }
746
747 static const struct file_operations hip4_sampler_fops = {
748 .owner = THIS_MODULE,
749 .open = hip4_sampler_open,
750 .read = hip4_sampler_read,
751 .release = hip4_sampler_release,
752 .poll = hip4_sampler_poll,
753 };
754
755 /* Return minor (if exists) associated with this maxwell instance */
756 int hip4_sampler_register_hip(struct scsc_mx *mx)
757 {
758 int i = SCSC_HIP4_DEBUG_INTERFACES;
759
760 while (i--)
761 if (hip4_sampler.devs[i].mx == mx &&
762 hip4_sampler.devs[i].type == STREAMING)
763 return i;
764 return -ENODEV;
765 }
766
767 void hip4_sampler_create(struct slsi_dev *sdev, struct scsc_mx *mx)
768 {
769 dev_t devn;
770 int ret;
771 char dev_name[20];
772 int minor;
773 int i;
774
775 SLSI_INFO_NODEV("hip4_sampler version: %d.%d\n", VER_MAJOR, VER_MINOR);
776
777 memset(&hip4_sampler, 0, sizeof(hip4_sampler));
778 /* Check whether exists */
779 if (!hip4_sampler.init) {
780 ret = alloc_chrdev_region(&hip4_sampler.device, 0, SCSC_HIP4_DEBUG_INTERFACES, "hip4_sampler_char");
781 if (ret)
782 goto error;
783
784 hip4_sampler.class_hip4_sampler = class_create(THIS_MODULE, DEVICE_NAME);
785 if (IS_ERR(hip4_sampler.class_hip4_sampler)) {
786 SLSI_ERR_NODEV("hip4_sampler class creation failed\n");
787 ret = PTR_ERR(hip4_sampler.class_hip4_sampler);
788 goto error_class;
789 }
790 }
791
792 /* Search for free minors */
793 minor = find_first_zero_bit(bitmap_hip4_sampler_minor, SCSC_HIP4_DEBUG_INTERFACES);
794 if (minor == SCSC_HIP4_DEBUG_INTERFACES) {
795 SLSI_INFO_NODEV("minor %d > SCSC_TTY_MINORS\n", minor);
796 return;
797 }
798
799 /* Create Stream channels */
800 /* Each Stream channel will have an associated Offline channel */
801 for (i = 0; i < SCSC_HIP4_STREAM_CH; i++) {
802 minor += i;
803 devn = MKDEV(MAJOR(hip4_sampler.device), MINOR(minor));
804
805 snprintf(dev_name, sizeof(dev_name), "%s_%d_%s", "hip4", i, "sam_str");
806
807 cdev_init(&hip4_sampler.devs[minor].cdev, &hip4_sampler_fops);
808 hip4_sampler.devs[minor].cdev.owner = THIS_MODULE;
809 hip4_sampler.devs[minor].cdev.ops = &hip4_sampler_fops;
810
811 ret = cdev_add(&hip4_sampler.devs[minor].cdev, devn, 1);
812 if (ret) {
813 hip4_sampler.devs[minor].cdev.dev = 0;
814 return;
815 }
816
817 hip4_sampler.devs[minor].dev =
818 device_create(hip4_sampler.class_hip4_sampler, NULL, hip4_sampler.devs[minor].cdev.dev, NULL, dev_name);
819
820 if (!hip4_sampler.devs[minor].dev) {
821 SLSI_ERR_NODEV("dev is NULL\n");
822 hip4_sampler.devs[minor].cdev.dev = 0;
823 cdev_del(&hip4_sampler.devs[minor].cdev);
824 return;
825 }
826
827 hip4_sampler.devs[minor].mx = mx;
828
829 mutex_init(&hip4_sampler.devs[minor].mutex);
830 hip4_sampler.devs[minor].kfifo_max = 0;
831 hip4_sampler.devs[minor].type = STREAMING;
832 hip4_sampler.devs[minor].minor = minor;
833
834 init_waitqueue_head(&hip4_sampler.devs[minor].read_wait);
835
836 slsi_traffic_mon_client_register(
837 sdev,
838 &hip4_sampler.devs[minor],
839 TRAFFIC_MON_CLIENT_MODE_PERIODIC,
840 0,
841 0,
842 hip4_sampler_tput_monitor);
843
844 /* Update bit mask */
845 set_bit(minor, bitmap_hip4_sampler_minor);
846
847 minor++;
848
849 /* Create associated offline channel */
850 devn = MKDEV(MAJOR(hip4_sampler.device), MINOR(minor));
851
852 snprintf(dev_name, sizeof(dev_name), "%s_%d_%s", "hip4", i, "sam_off");
853
854 cdev_init(&hip4_sampler.devs[minor].cdev, &hip4_sampler_fops);
855 hip4_sampler.devs[minor].cdev.owner = THIS_MODULE;
856 hip4_sampler.devs[minor].cdev.ops = &hip4_sampler_fops;
857
858 ret = cdev_add(&hip4_sampler.devs[minor].cdev, devn, 1);
859 if (ret) {
860 hip4_sampler.devs[minor].cdev.dev = 0;
861 return;
862 }
863
864 hip4_sampler.devs[minor].dev =
865 device_create(hip4_sampler.class_hip4_sampler, NULL, hip4_sampler.devs[minor].cdev.dev, NULL, dev_name);
866
867 if (!hip4_sampler.devs[minor].dev) {
868 hip4_sampler.devs[minor].cdev.dev = 0;
869 cdev_del(&hip4_sampler.devs[minor].cdev);
870 return;
871 }
872
873 if (hip4_sampler_static_kfifo_len > 256 * 1024) {
874 SLSI_DBG1_NODEV(SLSI_HIP, "hip4_sampler_static_kfifo_len %d > 2262144. Set to MAX", hip4_sampler_static_kfifo_len);
875 hip4_sampler_static_kfifo_len = 256 * 1024;
876 }
877 ret = kfifo_alloc(&hip4_sampler.devs[minor].fifo, hip4_sampler_static_kfifo_len, GFP_KERNEL);
878 if (ret) {
879 SLSI_ERR_NODEV("kfifo_alloc failed");
880 hip4_sampler.devs[minor].dev = NULL;
881 hip4_sampler.devs[minor].cdev.dev = 0;
882 cdev_del(&hip4_sampler.devs[minor].cdev);
883 return;
884 }
885
886 hip4_sampler.devs[minor].mx = mx;
887
888 mutex_init(&hip4_sampler.devs[minor].mutex);
889 hip4_sampler.devs[minor].kfifo_max = 0;
890 hip4_sampler.devs[minor].type = OFFLINE;
891
892 /* Update bit mask */
893 set_bit(minor, bitmap_hip4_sampler_minor);
894 }
895
896 #ifdef CONFIG_SCSC_LOG_COLLECTION
897 hip4_collect_client.prv = mx;
898 scsc_log_collector_register_client(&hip4_collect_client);
899 #endif
900 spin_lock_init(&g_spinlock);
901 hip4_sampler.init = true;
902
903 SLSI_INFO_NODEV("%s: Ready to start sampling....\n", DRV_NAME);
904
905 return;
906
907 error_class:
908 unregister_chrdev_region(hip4_sampler.device, SCSC_HIP4_DEBUG_INTERFACES);
909 hip4_sampler.init = false;
910 error:
911 return;
912 }
913
914 void hip4_sampler_destroy(struct slsi_dev *sdev, struct scsc_mx *mx)
915 {
916 int i = SCSC_HIP4_DEBUG_INTERFACES;
917 struct hip4_sampler_dev *hip4_dev;
918
919 while (i--)
920 if (hip4_sampler.devs[i].cdev.dev && hip4_sampler.devs[i].mx) {
921 hip4_dev = &hip4_sampler.devs[i];
922 /* This should be never be true - as knod should prevent unloading while
923 * the service (device node) is open
924 */
925 if (hip4_sampler.devs[i].filp) {
926 hip4_sampler.devs[i].filp = NULL;
927 kfifo_free(&hip4_sampler.devs[i].fifo);
928 }
929 if (hip4_sampler.devs[i].type == OFFLINE)
930 kfifo_free(&hip4_sampler.devs[i].fifo);
931
932 slsi_traffic_mon_client_unregister(sdev, hip4_dev);
933 device_destroy(hip4_sampler.class_hip4_sampler, hip4_sampler.devs[i].cdev.dev);
934 cdev_del(&hip4_sampler.devs[i].cdev);
935 memset(&hip4_sampler.devs[i].cdev, 0, sizeof(struct cdev));
936 hip4_sampler.devs[i].mx = NULL;
937 clear_bit(i, bitmap_hip4_sampler_minor);
938 }
939 #ifdef CONFIG_SCSC_LOG_COLLECTION
940 scsc_log_collector_unregister_client(&hip4_collect_client);
941 #endif
942 class_destroy(hip4_sampler.class_hip4_sampler);
943 unregister_chrdev_region(hip4_sampler.device, SCSC_HIP4_DEBUG_INTERFACES);
944 hip4_sampler.init = false;
945 }