aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorNishanth Aravamudan <nacc@us.ibm.com>2011-05-04 08:54:16 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-05-19 00:30:41 -0400
commitaf442a1baa6d00117cc7e7377ce7e6a545268684 (patch)
tree8f0670e0fa3358eb46afcae2b4e1b0197d8f7d72 /arch/powerpc
parent767303349e052ae0cb9e6495a70870da3459eeb6 (diff)
powerpc: Ensure dtl buffers do not cross 4k boundary
Future releases of fimrware will enforce a requirement that DTL buffers do not cross a 4k boundary. Commit 127493d5dc73589cbe00ea5ec8357cc2a4c0d82a satisfies this requirement for CONFIG_VIRT_CPU_ACCOUNTING=y kernels, but if !CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_DTL=y, the current code will fail at dtl registration time. Fix this by making the kmem cache from 127493d5dc73589cbe00ea5ec8357cc2a4c0d82a visible outside of setup.c and using the same cache in both dtl.c and setup.c. This requires a bit of reorganization to ensure ordering of the kmem cache and buffer allocations. Note: Since firmware now limits the size of the buffer, I made dtl_buf_entries read-only in debugfs. Tested with upcoming firmware with the 4 combinations of CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_DTL. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Anton Blanchard <anton@samba.org> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/lppaca.h2
-rw-r--r--arch/powerpc/platforms/pseries/dtl.c20
-rw-r--r--arch/powerpc/platforms/pseries/setup.c31
3 files changed, 35 insertions, 18 deletions
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index a077adc0b35e..e0298d26ce5d 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -210,6 +210,8 @@ struct dtl_entry {
210#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */ 210#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
211#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry)) 211#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
212 212
213extern struct kmem_cache *dtl_cache;
214
213/* 215/*
214 * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls 216 * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
215 * reading from the dispatch trace log. If other code wants to consume 217 * reading from the dispatch trace log. If other code wants to consume
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index c371bc06434b..e9190073bb97 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -52,10 +52,10 @@ static u8 dtl_event_mask = 0x7;
52 52
53 53
54/* 54/*
55 * Size of per-cpu log buffers. Default is just under 16 pages worth. 55 * Size of per-cpu log buffers. Firmware requires that the buffer does
56 * not cross a 4k boundary.
56 */ 57 */
57static int dtl_buf_entries = (16 * 85); 58static int dtl_buf_entries = N_DISPATCH_LOG;
58
59 59
60#ifdef CONFIG_VIRT_CPU_ACCOUNTING 60#ifdef CONFIG_VIRT_CPU_ACCOUNTING
61struct dtl_ring { 61struct dtl_ring {
@@ -151,7 +151,7 @@ static int dtl_start(struct dtl *dtl)
151 151
152 /* Register our dtl buffer with the hypervisor. The HV expects the 152 /* Register our dtl buffer with the hypervisor. The HV expects the
153 * 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 */
154 ((u32 *)dtl->buf)[1] = dtl->buf_entries * sizeof(struct dtl_entry); 154 ((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES;
155 155
156 hwcpu = get_hard_smp_processor_id(dtl->cpu); 156 hwcpu = get_hard_smp_processor_id(dtl->cpu);
157 addr = __pa(dtl->buf); 157 addr = __pa(dtl->buf);
@@ -196,13 +196,15 @@ static int dtl_enable(struct dtl *dtl)
196 long int rc; 196 long int rc;
197 struct dtl_entry *buf = NULL; 197 struct dtl_entry *buf = NULL;
198 198
199 if (!dtl_cache)
200 return -ENOMEM;
201
199 /* only allow one reader */ 202 /* only allow one reader */
200 if (dtl->buf) 203 if (dtl->buf)
201 return -EBUSY; 204 return -EBUSY;
202 205
203 n_entries = dtl_buf_entries; 206 n_entries = dtl_buf_entries;
204 buf = kmalloc_node(n_entries * sizeof(struct dtl_entry), 207 buf = kmem_cache_alloc_node(dtl_cache, GFP_KERNEL, cpu_to_node(dtl->cpu));
205 GFP_KERNEL, cpu_to_node(dtl->cpu));
206 if (!buf) { 208 if (!buf) {
207 printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", 209 printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
208 __func__, dtl->cpu); 210 __func__, dtl->cpu);
@@ -223,7 +225,7 @@ static int dtl_enable(struct dtl *dtl)
223 spin_unlock(&dtl->lock); 225 spin_unlock(&dtl->lock);
224 226
225 if (rc) 227 if (rc)
226 kfree(buf); 228 kmem_cache_free(dtl_cache, buf);
227 return rc; 229 return rc;
228} 230}
229 231
@@ -231,7 +233,7 @@ static void dtl_disable(struct dtl *dtl)
231{ 233{
232 spin_lock(&dtl->lock); 234 spin_lock(&dtl->lock);
233 dtl_stop(dtl); 235 dtl_stop(dtl);
234 kfree(dtl->buf); 236 kmem_cache_free(dtl_cache, dtl->buf);
235 dtl->buf = NULL; 237 dtl->buf = NULL;
236 dtl->buf_entries = 0; 238 dtl->buf_entries = 0;
237 spin_unlock(&dtl->lock); 239 spin_unlock(&dtl->lock);
@@ -365,7 +367,7 @@ static int dtl_init(void)
365 367
366 event_mask_file = debugfs_create_x8("dtl_event_mask", 0600, 368 event_mask_file = debugfs_create_x8("dtl_event_mask", 0600,
367 dtl_dir, &dtl_event_mask); 369 dtl_dir, &dtl_event_mask);
368 buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0600, 370 buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400,
369 dtl_dir, &dtl_buf_entries); 371 dtl_dir, &dtl_buf_entries);
370 372
371 if (!event_mask_file || !buf_entries_file) { 373 if (!event_mask_file || !buf_entries_file) {
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 1689adccc6d7..593acceeff96 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -278,6 +278,8 @@ static struct notifier_block pci_dn_reconfig_nb = {
278 .notifier_call = pci_dn_reconfig_notifier, 278 .notifier_call = pci_dn_reconfig_notifier,
279}; 279};
280 280
281struct kmem_cache *dtl_cache;
282
281#ifdef CONFIG_VIRT_CPU_ACCOUNTING 283#ifdef CONFIG_VIRT_CPU_ACCOUNTING
282/* 284/*
283 * Allocate space for the dispatch trace log for all possible cpus 285 * Allocate space for the dispatch trace log for all possible cpus
@@ -289,18 +291,12 @@ static int alloc_dispatch_logs(void)
289 int cpu, ret; 291 int cpu, ret;
290 struct paca_struct *pp; 292 struct paca_struct *pp;
291 struct dtl_entry *dtl; 293 struct dtl_entry *dtl;
292 struct kmem_cache *dtl_cache;
293 294
294 if (!firmware_has_feature(FW_FEATURE_SPLPAR)) 295 if (!firmware_has_feature(FW_FEATURE_SPLPAR))
295 return 0; 296 return 0;
296 297
297 dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES, 298 if (!dtl_cache)
298 DISPATCH_LOG_BYTES, 0, NULL);
299 if (!dtl_cache) {
300 pr_warn("Failed to create dispatch trace log buffer cache\n");
301 pr_warn("Stolen time statistics will be unreliable\n");
302 return 0; 299 return 0;
303 }
304 300
305 for_each_possible_cpu(cpu) { 301 for_each_possible_cpu(cpu) {
306 pp = &paca[cpu]; 302 pp = &paca[cpu];
@@ -334,10 +330,27 @@ static int alloc_dispatch_logs(void)
334 330
335 return 0; 331 return 0;
336} 332}
337 333#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
338early_initcall(alloc_dispatch_logs); 334static inline int alloc_dispatch_logs(void)
335{
336 return 0;
337}
339#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ 338#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
340 339
340static int alloc_dispatch_log_kmem_cache(void)
341{
342 dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
343 DISPATCH_LOG_BYTES, 0, NULL);
344 if (!dtl_cache) {
345 pr_warn("Failed to create dispatch trace log buffer cache\n");
346 pr_warn("Stolen time statistics will be unreliable\n");
347 return 0;
348 }
349
350 return alloc_dispatch_logs();
351}
352early_initcall(alloc_dispatch_log_kmem_cache);
353
341static void __init pSeries_setup_arch(void) 354static void __init pSeries_setup_arch(void)
342{ 355{
343 /* Discover PIC type and setup ppc_md accordingly */ 356 /* Discover PIC type and setup ppc_md accordingly */