1 /*****************************************************************************
3 * Copyright (c) 2014 - 2018 Samsung Electronics Co., Ltd. All rights reserved
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>
16 #include <linux/errno.h>
17 #include <linux/types.h>
19 #include <linux/version.h>
20 #include <linux/hardirq.h>
21 #include <linux/cpufreq.h>
23 #include <linux/ktime.h>
24 #include <linux/hrtimer.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>
32 #include <linux/delay.h>
33 #include <linux/mutex.h>
34 #include "hip4_sampler.h"
45 static atomic_t in_read
;
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
;
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)");
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)");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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
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
;
142 static bool hip4_sampler_in_htput
;
143 static u16 hip4_sampler_in_htput_seconds
;
145 #define DRV_NAME "hip4_sampler"
146 #define DEVICE_NAME "hip4_sampler"
149 #define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
155 DECLARE_BITMAP(bitmap_hip4_sampler_minor
, SCSC_HIP4_DEBUG_INTERFACES
);
157 enum hip4_dg_errors
{
169 struct hip4_sampler_dev
{
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 */
188 /* To profile kfifo num elements */
190 /* Sampler type streaming/offline */
192 /* reference to minor number */
197 * SCSC User Space debug sampler interface (singleton)
202 struct class *class_hip4_sampler
;
203 struct hip4_sampler_dev devs
[SCSC_HIP4_DEBUG_INTERFACES
];
206 void __hip4_sampler_update_record(struct hip4_sampler_dev
*hip4_dev
, u32 minor
, u8 param1
, u8 param2
, u8 param3
, u8 param4
, u32 param5
)
208 struct hip4_record ev
;
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);
223 ev
.record
= ((param1
& 0xff) << 24) | ((param2
& 0xff) << 16) | ((param3
& 0xff) << 8) | (param4
& 0xff);
225 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
226 kfifo_put(&hip4_dev
->fifo
, ev
);
228 kfifo_put(&hip4_dev
->fifo
, &ev
);
230 ret
= kfifo_len(&hip4_dev
->fifo
);
231 if (ret
> hip4_dev
->kfifo_max
)
232 hip4_dev
->kfifo_max
= ret
;
234 hip4_dev
->error
= KFIFO_FULL
;
237 wake_up_interruptible(&hip4_dev
->read_wait
);
238 /* If streaming buffer is not in use, put samples in offline buffer */
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);
252 ev
.record
= ((param1
& 0xff) << 24) | ((param2
& 0xff) << 16) | ((param3
& 0xff) << 8) | (param4
& 0xff);
254 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
255 kfifo_put(&hip4_dev
->fifo
, ev
);
257 kfifo_put(&hip4_dev
->fifo
, &ev
);
262 void hip4_sampler_update_record(u32 minor
, u8 param1
, u8 param2
, u8 param3
, u8 param4
, u32 param5
)
264 struct hip4_sampler_dev
*hip4_dev
;
267 if (!hip4_sampler_enable
|| !hip4_sampler
.init
)
270 if (atomic_read(&in_read
))
273 if (minor
>= SCSC_HIP4_INTERFACES
)
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
);
282 static void hip4_sampler_store_param(void)
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
;
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;
314 static void hip4_sampler_restore_param(void)
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
;
331 static void hip4_sampler_dynamic_switcher(u32 bps
)
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();
345 hip4_sampler_in_htput_seconds
= 0;
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();
358 hip4_sampler_in_htput_seconds
= 0;
363 static u32 g_tput_rx
;
364 static u32 g_tput_tx
;
366 void hip4_sampler_tput_monitor(void *client_ctx
, u32 state
, u32 tput_tx
, u32 tput_rx
)
368 struct hip4_sampler_dev
*hip4_sampler_dev
= (struct hip4_sampler_dev
*)client_ctx
;
370 if (!hip4_sampler_enable
)
373 if ((g_tput_tx
== tput_tx
) && (g_tput_rx
== tput_rx
))
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
384 if (tput_rx
> tput_tx
)
385 hip4_sampler_dynamic_switcher(tput_rx
);
387 hip4_sampler_dynamic_switcher(tput_tx
);
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);
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);
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);
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);
413 void hip4_sampler_tcp_decode(struct slsi_dev
*sdev
, struct net_device
*dev
, u8
*frame
, bool from_ba
)
415 struct tcphdr
*tcp_hdr
;
416 struct ethhdr
*ehdr
= (struct ethhdr
*)(frame
);
417 struct netdev_vif
*ndev_vif
= netdev_priv(dev
);
425 if (be16_to_cpu(ehdr
->h_proto
) != ETH_P_IP
)
428 ip_frame
= frame
+ ETH_HLEN
;
431 if (proto
!= IPPROTO_TCP
)
435 hlen
= ip_frame
[0] & 0x0F;
436 len
= ip_frame
[2] << 8 | ip_frame
[3];
439 ip_data_offset
+= (hlen
- 5) * 4;
441 tcp_hdr
= (struct tcphdr
*)(ip_frame
+ ip_data_offset
);
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
;
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;
455 if (tcp_hdr
->doff
> 5)
456 optlen
= (tcp_hdr
->doff
- 5) * 4;
458 options
= (u8
*)tcp_hdr
+ TCP_ACK_SUPPRESSION_OPTIONS_OFFSET
;
461 switch (options
[0]) {
462 case TCP_ACK_SUPPRESSION_OPTION_EOL
:
465 case TCP_ACK_SUPPRESSION_OPTION_NOP
:
468 case TCP_ACK_SUPPRESSION_OPTION_WINDOW
:
469 tcp_ack
->rx_window_scale
= options
[2];
476 /* if length field in TCP options is 0, or greater than
477 * total options length, then options are incorrect
479 if ((len
== 0) || (len
>= optlen
))
489 if (len
> ((hlen
* 4) + (tcp_hdr
->doff
* 4))) {
491 SCSC_HIP4_SAMPLER_TCP_DATA(sdev
->minor_prof
, tcp_ack
->stream_id
, tcp_hdr
->seq
);
493 SCSC_HIP4_SAMPLER_TCP_DATA_IN(sdev
->minor_prof
, tcp_ack
->stream_id
, tcp_hdr
->seq
);
495 if (tcp_ack
->rx_window_scale
)
496 rwnd
= be16_to_cpu(tcp_hdr
->window
) * (2 << tcp_ack
->rx_window_scale
);
498 rwnd
= be16_to_cpu(tcp_hdr
->window
);
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
);
503 SCSC_HIP4_SAMPLER_TCP_ACK_IN(sdev
->minor_prof
, tcp_ack
->stream_id
, be32_to_cpu(tcp_hdr
->ack_seq
));
506 slsi_spinlock_unlock(&tcp_ack
->lock
);
509 slsi_spinlock_unlock(&tcp_ack
->lock
);
513 #ifdef CONFIG_SCSC_LOG_COLLECTION
514 int hip4_collect_init(struct scsc_log_collector_client
*collect_client
)
517 atomic_set(&in_read
, 1);
521 int hip4_collect(struct scsc_log_collector_client
*collect_client
, size_t size
)
523 int i
= SCSC_HIP4_DEBUG_INTERFACES
;
527 struct hip4_sampler_dev
*hip4_dev
;
530 SLSI_INFO_NODEV("Triggered log collection in hip4_sampler\n");
532 if (!hip4_sampler_enable
)
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
);
541 buf
= vmalloc(num_samples
* sizeof(struct hip4_record
));
544 spin_lock_irqsave(&g_spinlock
, flags
);
545 ret
= kfifo_out(&hip4_dev
->fifo
, buf
, num_samples
);
546 spin_unlock_irqrestore(&g_spinlock
, flags
);
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);
561 int hip4_collect_end(struct scsc_log_collector_client
*collect_client
)
563 /* Restart sampling */
564 atomic_set(&in_read
, 0);
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
,
579 static int hip4_sampler_open(struct inode
*inode
, struct file
*filp
)
581 struct hip4_sampler_dev
*hip4_dev
;
584 hip4_dev
= container_of(inode
->i_cdev
, struct hip4_sampler_dev
, cdev
);
586 if (hip4_dev
->type
== OFFLINE
) {
587 /* Offline buffer skip open */
588 filp
->private_data
= hip4_dev
;
591 if (mutex_lock_interruptible(&hip4_dev
->mutex
))
594 if (filp
->private_data
) {
595 SLSI_INFO_NODEV("Service already started\n");
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;
605 ret
= kfifo_alloc(&hip4_dev
->fifo
, hip4_sampler_kfifo_len
, GFP_KERNEL
);
607 SLSI_ERR_NODEV("kfifo_alloc failed");
612 filp
->private_data
= hip4_dev
;
614 /* Clear any remaining error */
615 hip4_dev
->error
= NO_ERROR
;
617 hip4_dev
->record_num
= 0;
618 hip4_dev
->kfifo_max
= 0;
619 hip4_dev
->filp
= filp
;
621 SLSI_INFO_NODEV("%s: Sampling....\n", DRV_NAME
);
623 mutex_unlock(&hip4_dev
->mutex
);
627 static ssize_t
hip4_sampler_read(struct file
*filp
, char __user
*buf
, size_t len
, loff_t
*offset
)
631 struct hip4_sampler_dev
*hip4_dev
;
633 hip4_dev
= filp
->private_data
;
635 if (hip4_dev
->type
== OFFLINE
) {
636 /* Offline buffer skip open */
637 if (mutex_lock_interruptible(&hip4_dev
->mutex
))
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
;
645 if (mutex_lock_interruptible(&hip4_dev
->mutex
))
648 /* Check whether the device is in error */
649 if (hip4_dev
->error
!= NO_ERROR
) {
650 SLSI_ERR_NODEV("Device in error\n");
656 if (kfifo_len(&hip4_dev
->fifo
)) {
657 ret
= kfifo_to_user(&hip4_dev
->fifo
, buf
, len
, &copied
);
663 if (filp
->f_flags
& O_NONBLOCK
) {
668 ret
= wait_event_interruptible(hip4_dev
->read_wait
,
669 !kfifo_is_empty(&hip4_dev
->fifo
));
674 mutex_unlock(&hip4_dev
->mutex
);
678 static unsigned hip4_sampler_poll(struct file
*filp
, poll_table
*wait
)
680 struct hip4_sampler_dev
*hip4_dev
;
683 hip4_dev
= filp
->private_data
;
685 if (hip4_dev
->type
== OFFLINE
)
686 /* Offline buffer skip poll */
689 if (mutex_lock_interruptible(&hip4_dev
->mutex
))
692 if (hip4_dev
->error
!= NO_ERROR
) {
697 poll_wait(filp
, &hip4_dev
->read_wait
, wait
);
699 if (!kfifo_is_empty(&hip4_dev
->fifo
)) {
700 ret
= POLLIN
| POLLRDNORM
; /* readeable */
704 ret
= POLLOUT
| POLLWRNORM
; /* writable */
707 mutex_unlock(&hip4_dev
->mutex
);
711 static int hip4_sampler_release(struct inode
*inode
, struct file
*filp
)
713 struct hip4_sampler_dev
*hip4_dev
;
715 hip4_dev
= container_of(inode
->i_cdev
, struct hip4_sampler_dev
, cdev
);
717 if (hip4_dev
->type
== OFFLINE
) {
718 atomic_set(&in_read
, 0);
719 /* Offline buffer skip release */
723 if (mutex_lock_interruptible(&hip4_dev
->mutex
))
726 if (!hip4_dev
->filp
) {
727 SLSI_ERR_NODEV("Device already closed\n");
728 mutex_unlock(&hip4_dev
->mutex
);
732 if (hip4_dev
!= filp
->private_data
) {
733 SLSI_ERR_NODEV("Data mismatch\n");
734 mutex_unlock(&hip4_dev
->mutex
);
738 filp
->private_data
= NULL
;
739 hip4_dev
->filp
= NULL
;
740 kfifo_free(&hip4_dev
->fifo
);
742 mutex_unlock(&hip4_dev
->mutex
);
743 SLSI_INFO_NODEV("%s: Sampling... end. Kfifo_max = %d\n", DRV_NAME
, hip4_dev
->kfifo_max
);
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
,
755 /* Return minor (if exists) associated with this maxwell instance */
756 int hip4_sampler_register_hip(struct scsc_mx
*mx
)
758 int i
= SCSC_HIP4_DEBUG_INTERFACES
;
761 if (hip4_sampler
.devs
[i
].mx
== mx
&&
762 hip4_sampler
.devs
[i
].type
== STREAMING
)
767 void hip4_sampler_create(struct slsi_dev
*sdev
, struct scsc_mx
*mx
)
775 SLSI_INFO_NODEV("hip4_sampler version: %d.%d\n", VER_MAJOR
, VER_MINOR
);
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");
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
);
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
);
799 /* Create Stream channels */
800 /* Each Stream channel will have an associated Offline channel */
801 for (i
= 0; i
< SCSC_HIP4_STREAM_CH
; i
++) {
803 devn
= MKDEV(MAJOR(hip4_sampler
.device
), MINOR(minor
));
805 snprintf(dev_name
, sizeof(dev_name
), "%s_%d_%s", "hip4", i
, "sam_str");
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
;
811 ret
= cdev_add(&hip4_sampler
.devs
[minor
].cdev
, devn
, 1);
813 hip4_sampler
.devs
[minor
].cdev
.dev
= 0;
817 hip4_sampler
.devs
[minor
].dev
=
818 device_create(hip4_sampler
.class_hip4_sampler
, NULL
, hip4_sampler
.devs
[minor
].cdev
.dev
, NULL
, dev_name
);
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
);
827 hip4_sampler
.devs
[minor
].mx
= mx
;
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
;
834 init_waitqueue_head(&hip4_sampler
.devs
[minor
].read_wait
);
836 slsi_traffic_mon_client_register(
838 &hip4_sampler
.devs
[minor
],
839 TRAFFIC_MON_CLIENT_MODE_PERIODIC
,
842 hip4_sampler_tput_monitor
);
844 /* Update bit mask */
845 set_bit(minor
, bitmap_hip4_sampler_minor
);
849 /* Create associated offline channel */
850 devn
= MKDEV(MAJOR(hip4_sampler
.device
), MINOR(minor
));
852 snprintf(dev_name
, sizeof(dev_name
), "%s_%d_%s", "hip4", i
, "sam_off");
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
;
858 ret
= cdev_add(&hip4_sampler
.devs
[minor
].cdev
, devn
, 1);
860 hip4_sampler
.devs
[minor
].cdev
.dev
= 0;
864 hip4_sampler
.devs
[minor
].dev
=
865 device_create(hip4_sampler
.class_hip4_sampler
, NULL
, hip4_sampler
.devs
[minor
].cdev
.dev
, NULL
, dev_name
);
867 if (!hip4_sampler
.devs
[minor
].dev
) {
868 hip4_sampler
.devs
[minor
].cdev
.dev
= 0;
869 cdev_del(&hip4_sampler
.devs
[minor
].cdev
);
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;
877 ret
= kfifo_alloc(&hip4_sampler
.devs
[minor
].fifo
, hip4_sampler_static_kfifo_len
, GFP_KERNEL
);
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
);
886 hip4_sampler
.devs
[minor
].mx
= mx
;
888 mutex_init(&hip4_sampler
.devs
[minor
].mutex
);
889 hip4_sampler
.devs
[minor
].kfifo_max
= 0;
890 hip4_sampler
.devs
[minor
].type
= OFFLINE
;
892 /* Update bit mask */
893 set_bit(minor
, bitmap_hip4_sampler_minor
);
896 #ifdef CONFIG_SCSC_LOG_COLLECTION
897 hip4_collect_client
.prv
= mx
;
898 scsc_log_collector_register_client(&hip4_collect_client
);
900 spin_lock_init(&g_spinlock
);
901 hip4_sampler
.init
= true;
903 SLSI_INFO_NODEV("%s: Ready to start sampling....\n", DRV_NAME
);
908 unregister_chrdev_region(hip4_sampler
.device
, SCSC_HIP4_DEBUG_INTERFACES
);
909 hip4_sampler
.init
= false;
914 void hip4_sampler_destroy(struct slsi_dev
*sdev
, struct scsc_mx
*mx
)
916 int i
= SCSC_HIP4_DEBUG_INTERFACES
;
917 struct hip4_sampler_dev
*hip4_dev
;
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
925 if (hip4_sampler
.devs
[i
].filp
) {
926 hip4_sampler
.devs
[i
].filp
= NULL
;
927 kfifo_free(&hip4_sampler
.devs
[i
].fifo
);
929 if (hip4_sampler
.devs
[i
].type
== OFFLINE
)
930 kfifo_free(&hip4_sampler
.devs
[i
].fifo
);
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
);
939 #ifdef CONFIG_SCSC_LOG_COLLECTION
940 scsc_log_collector_unregister_client(&hip4_collect_client
);
942 class_destroy(hip4_sampler
.class_hip4_sampler
);
943 unregister_chrdev_region(hip4_sampler
.device
, SCSC_HIP4_DEBUG_INTERFACES
);
944 hip4_sampler
.init
= false;