aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/lppaca.h8
-rw-r--r--arch/powerpc/kernel/time.c6
-rw-r--r--arch/powerpc/platforms/pseries/dtl.c206
3 files changed, 179 insertions, 41 deletions
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index cfb85ec8575..7f5e0fefebb 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -191,6 +191,14 @@ struct dtl_entry {
191#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */ 191#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
192#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry)) 192#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
193 193
194/*
195 * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
196 * reading from the dispatch trace log. If other code wants to consume
197 * DTL entries, it can set this pointer to a function that will get
198 * called once for each DTL entry that gets processed.
199 */
200extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
201
194#endif /* CONFIG_PPC_BOOK3S */ 202#endif /* CONFIG_PPC_BOOK3S */
195#endif /* __KERNEL__ */ 203#endif /* __KERNEL__ */
196#endif /* _ASM_POWERPC_LPPACA_H */ 204#endif /* _ASM_POWERPC_LPPACA_H */
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index fca20643c36..bcb738b9ff8 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -183,6 +183,8 @@ DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
183 183
184cputime_t cputime_one_jiffy; 184cputime_t cputime_one_jiffy;
185 185
186void (*dtl_consumer)(struct dtl_entry *, u64);
187
186static void calc_cputime_factors(void) 188static void calc_cputime_factors(void)
187{ 189{
188 struct div_result res; 190 struct div_result res;
@@ -218,7 +220,7 @@ static u64 read_spurr(u64 tb)
218 */ 220 */
219static u64 scan_dispatch_log(u64 stop_tb) 221static u64 scan_dispatch_log(u64 stop_tb)
220{ 222{
221 unsigned long i = local_paca->dtl_ridx; 223 u64 i = local_paca->dtl_ridx;
222 struct dtl_entry *dtl = local_paca->dtl_curr; 224 struct dtl_entry *dtl = local_paca->dtl_curr;
223 struct dtl_entry *dtl_end = local_paca->dispatch_log_end; 225 struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
224 struct lppaca *vpa = local_paca->lppaca_ptr; 226 struct lppaca *vpa = local_paca->lppaca_ptr;
@@ -229,6 +231,8 @@ static u64 scan_dispatch_log(u64 stop_tb)
229 if (i == vpa->dtl_idx) 231 if (i == vpa->dtl_idx)
230 return 0; 232 return 0;
231 while (i < vpa->dtl_idx) { 233 while (i < vpa->dtl_idx) {
234 if (dtl_consumer)
235 dtl_consumer(dtl, i);
232 dtb = dtl->timebase; 236 dtb = dtl->timebase;
233 tb_delta = dtl->enqueue_to_dispatch_time + 237 tb_delta = dtl->enqueue_to_dispatch_time +
234 dtl->ready_to_enqueue_time; 238 dtl->ready_to_enqueue_time;
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index 0357655db49..c371bc06434 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -23,6 +23,7 @@
23#include <linux/init.h> 23#include <linux/init.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/debugfs.h> 25#include <linux/debugfs.h>
26#include <linux/spinlock.h>
26#include <asm/smp.h> 27#include <asm/smp.h>
27#include <asm/system.h> 28#include <asm/system.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
@@ -37,6 +38,7 @@ struct dtl {
37 int cpu; 38 int cpu;
38 int buf_entries; 39 int buf_entries;
39 u64 last_idx; 40 u64 last_idx;
41 spinlock_t lock;
40}; 42};
41static DEFINE_PER_CPU(struct dtl, cpu_dtl); 43static DEFINE_PER_CPU(struct dtl, cpu_dtl);
42 44
@@ -55,25 +57,97 @@ static u8 dtl_event_mask = 0x7;
55static int dtl_buf_entries = (16 * 85); 57static int dtl_buf_entries = (16 * 85);
56 58
57 59
58static int dtl_enable(struct dtl *dtl) 60#ifdef CONFIG_VIRT_CPU_ACCOUNTING
61struct dtl_ring {
62 u64 write_index;
63 struct dtl_entry *write_ptr;
64 struct dtl_entry *buf;
65 struct dtl_entry *buf_end;
66 u8 saved_dtl_mask;
67};
68
69static DEFINE_PER_CPU(struct dtl_ring, dtl_rings);
70
71static atomic_t dtl_count;
72
73/*
74 * The cpu accounting code controls the DTL ring buffer, and we get
75 * given entries as they are processed.
76 */
77static void consume_dtle(struct dtl_entry *dtle, u64 index)
59{ 78{
60 unsigned long addr; 79 struct dtl_ring *dtlr = &__get_cpu_var(dtl_rings);
61 int ret, hwcpu; 80 struct dtl_entry *wp = dtlr->write_ptr;
81 struct lppaca *vpa = local_paca->lppaca_ptr;
62 82
63 /* only allow one reader */ 83 if (!wp)
64 if (dtl->buf) 84 return;
65 return -EBUSY;
66 85
67 /* we need to store the original allocation size for use during read */ 86 *wp = *dtle;
68 dtl->buf_entries = dtl_buf_entries; 87 barrier();
69 88
70 dtl->buf = kmalloc_node(dtl->buf_entries * sizeof(struct dtl_entry), 89 /* check for hypervisor ring buffer overflow, ignore this entry if so */
71 GFP_KERNEL, cpu_to_node(dtl->cpu)); 90 if (index + N_DISPATCH_LOG < vpa->dtl_idx)
72 if (!dtl->buf) { 91 return;
73 printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", 92
74 __func__, dtl->cpu); 93 ++wp;
75 return -ENOMEM; 94 if (wp == dtlr->buf_end)
76 } 95 wp = dtlr->buf;
96 dtlr->write_ptr = wp;
97
98 /* incrementing write_index makes the new entry visible */
99 smp_wmb();
100 ++dtlr->write_index;
101}
102
103static int dtl_start(struct dtl *dtl)
104{
105 struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu);
106
107 dtlr->buf = dtl->buf;
108 dtlr->buf_end = dtl->buf + dtl->buf_entries;
109 dtlr->write_index = 0;
110
111 /* setting write_ptr enables logging into our buffer */
112 smp_wmb();
113 dtlr->write_ptr = dtl->buf;
114
115 /* enable event logging */
116 dtlr->saved_dtl_mask = lppaca_of(dtl->cpu).dtl_enable_mask;
117 lppaca_of(dtl->cpu).dtl_enable_mask |= dtl_event_mask;
118
119 dtl_consumer = consume_dtle;
120 atomic_inc(&dtl_count);
121 return 0;
122}
123
124static void dtl_stop(struct dtl *dtl)
125{
126 struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu);
127
128 dtlr->write_ptr = NULL;
129 smp_wmb();
130
131 dtlr->buf = NULL;
132
133 /* restore dtl_enable_mask */
134 lppaca_of(dtl->cpu).dtl_enable_mask = dtlr->saved_dtl_mask;
135
136 if (atomic_dec_and_test(&dtl_count))
137 dtl_consumer = NULL;
138}
139
140static u64 dtl_current_index(struct dtl *dtl)
141{
142 return per_cpu(dtl_rings, dtl->cpu).write_index;
143}
144
145#else /* CONFIG_VIRT_CPU_ACCOUNTING */
146
147static int dtl_start(struct dtl *dtl)
148{
149 unsigned long addr;
150 int ret, hwcpu;
77 151
78 /* Register our dtl buffer with the hypervisor. The HV expects the 152 /* Register our dtl buffer with the hypervisor. The HV expects the
79 * buffer size to be passed in the second word of the buffer */ 153 * buffer size to be passed in the second word of the buffer */
@@ -85,12 +159,11 @@ static int dtl_enable(struct dtl *dtl)
85 if (ret) { 159 if (ret) {
86 printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) " 160 printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) "
87 "failed with %d\n", __func__, dtl->cpu, hwcpu, ret); 161 "failed with %d\n", __func__, dtl->cpu, hwcpu, ret);
88 kfree(dtl->buf);
89 return -EIO; 162 return -EIO;
90 } 163 }
91 164
92 /* set our initial buffer indices */ 165 /* set our initial buffer indices */
93 dtl->last_idx = lppaca_of(dtl->cpu).dtl_idx = 0; 166 lppaca_of(dtl->cpu).dtl_idx = 0;
94 167
95 /* ensure that our updates to the lppaca fields have occurred before 168 /* ensure that our updates to the lppaca fields have occurred before
96 * we actually enable the logging */ 169 * we actually enable the logging */
@@ -102,17 +175,66 @@ static int dtl_enable(struct dtl *dtl)
102 return 0; 175 return 0;
103} 176}
104 177
105static void dtl_disable(struct dtl *dtl) 178static void dtl_stop(struct dtl *dtl)
106{ 179{
107 int hwcpu = get_hard_smp_processor_id(dtl->cpu); 180 int hwcpu = get_hard_smp_processor_id(dtl->cpu);
108 181
109 lppaca_of(dtl->cpu).dtl_enable_mask = 0x0; 182 lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
110 183
111 unregister_dtl(hwcpu, __pa(dtl->buf)); 184 unregister_dtl(hwcpu, __pa(dtl->buf));
185}
186
187static u64 dtl_current_index(struct dtl *dtl)
188{
189 return lppaca_of(dtl->cpu).dtl_idx;
190}
191#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
112 192
193static int dtl_enable(struct dtl *dtl)
194{
195 long int n_entries;
196 long int rc;
197 struct dtl_entry *buf = NULL;
198
199 /* only allow one reader */
200 if (dtl->buf)
201 return -EBUSY;
202
203 n_entries = dtl_buf_entries;
204 buf = kmalloc_node(n_entries * sizeof(struct dtl_entry),
205 GFP_KERNEL, cpu_to_node(dtl->cpu));
206 if (!buf) {
207 printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
208 __func__, dtl->cpu);
209 return -ENOMEM;
210 }
211
212 spin_lock(&dtl->lock);
213 rc = -EBUSY;
214 if (!dtl->buf) {
215 /* store the original allocation size for use during read */
216 dtl->buf_entries = n_entries;
217 dtl->buf = buf;
218 dtl->last_idx = 0;
219 rc = dtl_start(dtl);
220 if (rc)
221 dtl->buf = NULL;
222 }
223 spin_unlock(&dtl->lock);
224
225 if (rc)
226 kfree(buf);
227 return rc;
228}
229
230static void dtl_disable(struct dtl *dtl)
231{
232 spin_lock(&dtl->lock);
233 dtl_stop(dtl);
113 kfree(dtl->buf); 234 kfree(dtl->buf);
114 dtl->buf = NULL; 235 dtl->buf = NULL;
115 dtl->buf_entries = 0; 236 dtl->buf_entries = 0;
237 spin_unlock(&dtl->lock);
116} 238}
117 239
118/* file interface */ 240/* file interface */
@@ -140,8 +262,9 @@ static int dtl_file_release(struct inode *inode, struct file *filp)
140static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len, 262static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len,
141 loff_t *pos) 263 loff_t *pos)
142{ 264{
143 int rc, cur_idx, last_idx, n_read, n_req, read_size; 265 long int rc, n_read, n_req, read_size;
144 struct dtl *dtl; 266 struct dtl *dtl;
267 u64 cur_idx, last_idx, i;
145 268
146 if ((len % sizeof(struct dtl_entry)) != 0) 269 if ((len % sizeof(struct dtl_entry)) != 0)
147 return -EINVAL; 270 return -EINVAL;
@@ -154,41 +277,48 @@ static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len,
154 /* actual number of entries read */ 277 /* actual number of entries read */
155 n_read = 0; 278 n_read = 0;
156 279
157 cur_idx = lppaca_of(dtl->cpu).dtl_idx; 280 spin_lock(&dtl->lock);
281
282 cur_idx = dtl_current_index(dtl);
158 last_idx = dtl->last_idx; 283 last_idx = dtl->last_idx;
159 284
160 if (cur_idx - last_idx > dtl->buf_entries) { 285 if (last_idx + dtl->buf_entries <= cur_idx)
161 pr_debug("%s: hv buffer overflow for cpu %d, samples lost\n", 286 last_idx = cur_idx - dtl->buf_entries + 1;
162 __func__, dtl->cpu); 287
163 } 288 if (last_idx + n_req > cur_idx)
289 n_req = cur_idx - last_idx;
164 290
165 cur_idx %= dtl->buf_entries; 291 if (n_req > 0)
166 last_idx %= dtl->buf_entries; 292 dtl->last_idx = last_idx + n_req;
293
294 spin_unlock(&dtl->lock);
295
296 if (n_req <= 0)
297 return 0;
298
299 i = last_idx % dtl->buf_entries;
167 300
168 /* read the tail of the buffer if we've wrapped */ 301 /* read the tail of the buffer if we've wrapped */
169 if (last_idx > cur_idx) { 302 if (i + n_req > dtl->buf_entries) {
170 read_size = min(n_req, dtl->buf_entries - last_idx); 303 read_size = dtl->buf_entries - i;
171 304
172 rc = copy_to_user(buf, &dtl->buf[last_idx], 305 rc = copy_to_user(buf, &dtl->buf[i],
173 read_size * sizeof(struct dtl_entry)); 306 read_size * sizeof(struct dtl_entry));
174 if (rc) 307 if (rc)
175 return -EFAULT; 308 return -EFAULT;
176 309
177 last_idx = 0; 310 i = 0;
178 n_req -= read_size; 311 n_req -= read_size;
179 n_read += read_size; 312 n_read += read_size;
180 buf += read_size * sizeof(struct dtl_entry); 313 buf += read_size * sizeof(struct dtl_entry);
181 } 314 }
182 315
183 /* .. and now the head */ 316 /* .. and now the head */
184 read_size = min(n_req, cur_idx - last_idx); 317 rc = copy_to_user(buf, &dtl->buf[i], n_req * sizeof(struct dtl_entry));
185 rc = copy_to_user(buf, &dtl->buf[last_idx],
186 read_size * sizeof(struct dtl_entry));
187 if (rc) 318 if (rc)
188 return -EFAULT; 319 return -EFAULT;
189 320
190 n_read += read_size; 321 n_read += n_req;
191 dtl->last_idx += n_read;
192 322
193 return n_read * sizeof(struct dtl_entry); 323 return n_read * sizeof(struct dtl_entry);
194} 324}
@@ -220,11 +350,6 @@ static int dtl_init(void)
220 struct dentry *event_mask_file, *buf_entries_file; 350 struct dentry *event_mask_file, *buf_entries_file;
221 int rc, i; 351 int rc, i;
222 352
223#ifdef CONFIG_VIRT_CPU_ACCOUNTING
224 /* disable this for now */
225 return -ENODEV;
226#endif
227
228 if (!firmware_has_feature(FW_FEATURE_SPLPAR)) 353 if (!firmware_has_feature(FW_FEATURE_SPLPAR))
229 return -ENODEV; 354 return -ENODEV;
230 355
@@ -251,6 +376,7 @@ static int dtl_init(void)
251 /* set up the per-cpu log structures */ 376 /* set up the per-cpu log structures */
252 for_each_possible_cpu(i) { 377 for_each_possible_cpu(i) {
253 struct dtl *dtl = &per_cpu(cpu_dtl, i); 378 struct dtl *dtl = &per_cpu(cpu_dtl, i);
379 spin_lock_init(&dtl->lock);
254 dtl->cpu = i; 380 dtl->cpu = i;
255 381
256 rc = dtl_setup_file(dtl); 382 rc = dtl_setup_file(dtl);