~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/cavium-octeon/oct_ilm.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 #include <linux/fs.h>
  3 #include <linux/interrupt.h>
  4 #include <asm/octeon/octeon.h>
  5 #include <asm/octeon/cvmx-ciu-defs.h>
  6 #include <asm/octeon/cvmx.h>
  7 #include <linux/debugfs.h>
  8 #include <linux/kernel.h>
  9 #include <linux/module.h>
 10 #include <linux/seq_file.h>
 11 
 12 #define TIMER_NUM 3
 13 
 14 static bool reset_stats;
 15 
 16 struct latency_info {
 17         u64 io_interval;
 18         u64 cpu_interval;
 19         u64 timer_start1;
 20         u64 timer_start2;
 21         u64 max_latency;
 22         u64 min_latency;
 23         u64 latency_sum;
 24         u64 average_latency;
 25         u64 interrupt_cnt;
 26 };
 27 
 28 static struct latency_info li;
 29 static struct dentry *dir;
 30 
 31 static int oct_ilm_show(struct seq_file *m, void *v)
 32 {
 33         u64 cpuclk, avg, max, min;
 34         struct latency_info curr_li = li;
 35 
 36         cpuclk = octeon_get_clock_rate();
 37 
 38         max = (curr_li.max_latency * 1000000000) / cpuclk;
 39         min = (curr_li.min_latency * 1000000000) / cpuclk;
 40         avg = (curr_li.latency_sum * 1000000000) / (cpuclk * curr_li.interrupt_cnt);
 41 
 42         seq_printf(m, "cnt: %10lld, avg: %7lld ns, max: %7lld ns, min: %7lld ns\n",
 43                    curr_li.interrupt_cnt, avg, max, min);
 44         return 0;
 45 }
 46 DEFINE_SHOW_ATTRIBUTE(oct_ilm);
 47 
 48 static int reset_statistics(void *data, u64 value)
 49 {
 50         reset_stats = true;
 51         return 0;
 52 }
 53 
 54 DEFINE_DEBUGFS_ATTRIBUTE(reset_statistics_ops, NULL, reset_statistics, "%llu\n");
 55 
 56 static void init_debugfs(void)
 57 {
 58         dir = debugfs_create_dir("oct_ilm", 0);
 59         debugfs_create_file("statistics", 0222, dir, NULL, &oct_ilm_fops);
 60         debugfs_create_file("reset", 0222, dir, NULL, &reset_statistics_ops);
 61 }
 62 
 63 static void init_latency_info(struct latency_info *li, int startup)
 64 {
 65         /* interval in milli seconds after which the interrupt will
 66          * be triggered
 67          */
 68         int interval = 1;
 69 
 70         if (startup) {
 71                 /* Calculating by the amounts io clock and cpu clock would
 72                  *  increment in interval amount of ms
 73                  */
 74                 li->io_interval = (octeon_get_io_clock_rate() * interval) / 1000;
 75                 li->cpu_interval = (octeon_get_clock_rate() * interval) / 1000;
 76         }
 77         li->timer_start1 = 0;
 78         li->timer_start2 = 0;
 79         li->max_latency = 0;
 80         li->min_latency = (u64)-1;
 81         li->latency_sum = 0;
 82         li->interrupt_cnt = 0;
 83 }
 84 
 85 
 86 static void start_timer(int timer, u64 interval)
 87 {
 88         union cvmx_ciu_timx timx;
 89         unsigned long flags;
 90 
 91         timx.u64 = 0;
 92         timx.s.one_shot = 1;
 93         timx.s.len = interval;
 94         raw_local_irq_save(flags);
 95         li.timer_start1 = read_c0_cvmcount();
 96         cvmx_write_csr(CVMX_CIU_TIMX(timer), timx.u64);
 97         /* Read it back to force wait until register is written. */
 98         timx.u64 = cvmx_read_csr(CVMX_CIU_TIMX(timer));
 99         li.timer_start2 = read_c0_cvmcount();
100         raw_local_irq_restore(flags);
101 }
102 
103 
104 static irqreturn_t cvm_oct_ciu_timer_interrupt(int cpl, void *dev_id)
105 {
106         u64 last_latency;
107         u64 last_int_cnt;
108 
109         if (reset_stats) {
110                 init_latency_info(&li, 0);
111                 reset_stats = false;
112         } else {
113                 last_int_cnt = read_c0_cvmcount();
114                 last_latency = last_int_cnt - (li.timer_start1 + li.cpu_interval);
115                 li.interrupt_cnt++;
116                 li.latency_sum += last_latency;
117                 if (last_latency > li.max_latency)
118                         li.max_latency = last_latency;
119                 if (last_latency < li.min_latency)
120                         li.min_latency = last_latency;
121         }
122         start_timer(TIMER_NUM, li.io_interval);
123         return IRQ_HANDLED;
124 }
125 
126 static void disable_timer(int timer)
127 {
128         union cvmx_ciu_timx timx;
129 
130         timx.s.one_shot = 0;
131         timx.s.len = 0;
132         cvmx_write_csr(CVMX_CIU_TIMX(timer), timx.u64);
133         /* Read it back to force immediate write of timer register*/
134         timx.u64 = cvmx_read_csr(CVMX_CIU_TIMX(timer));
135 }
136 
137 static __init int oct_ilm_module_init(void)
138 {
139         int rc;
140         int irq = OCTEON_IRQ_TIMER0 + TIMER_NUM;
141 
142         init_debugfs();
143 
144         rc = request_irq(irq, cvm_oct_ciu_timer_interrupt, IRQF_NO_THREAD,
145                          "oct_ilm", 0);
146         if (rc) {
147                 WARN(1, "Could not acquire IRQ %d", irq);
148                 goto err_irq;
149         }
150 
151         init_latency_info(&li, 1);
152         start_timer(TIMER_NUM, li.io_interval);
153 
154         return 0;
155 err_irq:
156         debugfs_remove_recursive(dir);
157         return rc;
158 }
159 
160 static __exit void oct_ilm_module_exit(void)
161 {
162         disable_timer(TIMER_NUM);
163         debugfs_remove_recursive(dir);
164         free_irq(OCTEON_IRQ_TIMER0 + TIMER_NUM, 0);
165 }
166 
167 module_exit(oct_ilm_module_exit);
168 module_init(oct_ilm_module_init);
169 MODULE_AUTHOR("Venkat Subbiah, Cavium");
170 MODULE_DESCRIPTION("Measures interrupt latency on Octeon chips.");
171 MODULE_LICENSE("GPL");
172 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php