OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [ia64/] [kernel/] [palinfo.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * palinfo.c
3
 *
4
 * Prints processor specific information reported by PAL.
5
 * This code is based on specification of PAL as of the
6
 * Intel IA-64 Architecture Software Developer's Manual v1.0.
7
 *
8
 *
9
 * Copyright (C) 2000-2001, 2003 Hewlett-Packard Co
10
 *      Stephane Eranian <eranian@hpl.hp.com>
11
 *
12
 * 05/26/2000   S.Eranian       initial release
13
 * 08/21/2000   S.Eranian       updated to July 2000 PAL specs
14
 * 02/05/2001   S.Eranian       fixed module support
15
 * 10/23/2001   S.Eranian       updated pal_perf_mon_info bug fixes
16
 */
17
#include <linux/config.h>
18
#include <linux/types.h>
19
#include <linux/errno.h>
20
#include <linux/init.h>
21
#include <linux/proc_fs.h>
22
#include <linux/mm.h>
23
#include <linux/module.h>
24
#include <linux/efi.h>
25
 
26
#include <asm/pal.h>
27
#include <asm/sal.h>
28
#include <asm/page.h>
29
#include <asm/processor.h>
30
#include <linux/smp.h>
31
 
32
MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
33
MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
34
MODULE_LICENSE("GPL");
35
 
36
#define PALINFO_VERSION "0.5"
37
 
38
typedef int (*palinfo_func_t)(char*);
39
 
40
typedef struct {
41
        const char              *name;          /* name of the proc entry */
42
        palinfo_func_t          proc_read;      /* function to call for reading */
43
        struct proc_dir_entry   *entry;         /* registered entry (removal) */
44
} palinfo_entry_t;
45
 
46
 
47
/*
48
 *  A bunch of string array to get pretty printing
49
 */
50
 
51
static char *cache_types[] = {
52
        "",                     /* not used */
53
        "Instruction",
54
        "Data",
55
        "Data/Instruction"      /* unified */
56
};
57
 
58
static const char *cache_mattrib[]={
59
        "WriteThrough",
60
        "WriteBack",
61
        "",             /* reserved */
62
        ""              /* reserved */
63
};
64
 
65
static const char *cache_st_hints[]={
66
        "Temporal, level 1",
67
        "Reserved",
68
        "Reserved",
69
        "Non-temporal, all levels",
70
        "Reserved",
71
        "Reserved",
72
        "Reserved",
73
        "Reserved"
74
};
75
 
76
static const char *cache_ld_hints[]={
77
        "Temporal, level 1",
78
        "Non-temporal, level 1",
79
        "Reserved",
80
        "Non-temporal, all levels",
81
        "Reserved",
82
        "Reserved",
83
        "Reserved",
84
        "Reserved"
85
};
86
 
87
static const char *rse_hints[]={
88
        "enforced lazy",
89
        "eager stores",
90
        "eager loads",
91
        "eager loads and stores"
92
};
93
 
94
#define RSE_HINTS_COUNT ARRAY_SIZE(rse_hints)
95
 
96
static const char *mem_attrib[]={
97
        "WB",           /* 000 */
98
        "SW",           /* 001 */
99
        "010",          /* 010 */
100
        "011",          /* 011 */
101
        "UC",           /* 100 */
102
        "UCE",          /* 101 */
103
        "WC",           /* 110 */
104
        "NaTPage"       /* 111 */
105
};
106
 
107
/*
108
 * Take a 64bit vector and produces a string such that
109
 * if bit n is set then 2^n in clear text is generated. The adjustment
110
 * to the right unit is also done.
111
 *
112
 * Input:
113
 *      - a pointer to a buffer to hold the string
114
 *      - a 64-bit vector
115
 * Ouput:
116
 *      - a pointer to the end of the buffer
117
 *
118
 */
119
static char *
120
bitvector_process(char *p, u64 vector)
121
{
122
        int i,j;
123
        const char *units[]={ "", "K", "M", "G", "T" };
124
 
125
        for (i=0, j=0; i < 64; i++ , j=i/10) {
126
                if (vector & 0x1) {
127
                        p += sprintf(p, "%d%s ", 1 << (i-j*10), units[j]);
128
                }
129
                vector >>= 1;
130
        }
131
        return p;
132
}
133
 
134
/*
135
 * Take a 64bit vector and produces a string such that
136
 * if bit n is set then register n is present. The function
137
 * takes into account consecutive registers and prints out ranges.
138
 *
139
 * Input:
140
 *      - a pointer to a buffer to hold the string
141
 *      - a 64-bit vector
142
 * Ouput:
143
 *      - a pointer to the end of the buffer
144
 *
145
 */
146
static char *
147
bitregister_process(char *p, u64 *reg_info, int max)
148
{
149
        int i, begin, skip = 0;
150
        u64 value = reg_info[0];
151
 
152
        value >>= i = begin = ffs(value) - 1;
153
 
154
        for(; i < max; i++ ) {
155
 
156
                if (i != 0 && (i%64) == 0) value = *++reg_info;
157
 
158
                if ((value & 0x1) == 0 && skip == 0) {
159
                        if (begin  <= i - 2)
160
                                p += sprintf(p, "%d-%d ", begin, i-1);
161
                        else
162
                                p += sprintf(p, "%d ", i-1);
163
                        skip  = 1;
164
                        begin = -1;
165
                } else if ((value & 0x1) && skip == 1) {
166
                        skip = 0;
167
                        begin = i;
168
                }
169
                value >>=1;
170
        }
171
        if (begin > -1) {
172
                if (begin < 127)
173
                        p += sprintf(p, "%d-127", begin);
174
                else
175
                        p += sprintf(p, "127");
176
        }
177
 
178
        return p;
179
}
180
 
181
static int
182
power_info(char *page)
183
{
184
        s64 status;
185
        char *p = page;
186
        u64 halt_info_buffer[8];
187
        pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer;
188
        int i;
189
 
190
        status = ia64_pal_halt_info(halt_info);
191
        if (status != 0) return 0;
192
 
193
        for (i=0; i < 8 ; i++ ) {
194
                if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
195
                        p += sprintf(p, "Power level %d:\n"
196
                                     "\tentry_latency       : %d cycles\n"
197
                                     "\texit_latency        : %d cycles\n"
198
                                     "\tpower consumption   : %d mW\n"
199
                                     "\tCache+TLB coherency : %s\n", i,
200
                                     halt_info[i].pal_power_mgmt_info_s.entry_latency,
201
                                     halt_info[i].pal_power_mgmt_info_s.exit_latency,
202
                                     halt_info[i].pal_power_mgmt_info_s.power_consumption,
203
                                     halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
204
                } else {
205
                        p += sprintf(p,"Power level %d: not implemented\n",i);
206
                }
207
        }
208
        return p - page;
209
}
210
 
211
static int
212
cache_info(char *page)
213
{
214
        char *p = page;
215
        u64 i, levels, unique_caches;
216
        pal_cache_config_info_t cci;
217
        int j, k;
218
        s64 status;
219
 
220
        if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
221
                printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status);
222
                return 0;
223
        }
224
 
225
        p += sprintf(p, "Cache levels  : %ld\nUnique caches : %ld\n\n", levels, unique_caches);
226
 
227
        for (i=0; i < levels; i++) {
228
 
229
                for (j=2; j >0 ; j--) {
230
 
231
                        /* even without unification some level may not be present */
232
                        if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) {
233
                                continue;
234
                        }
235
                        p += sprintf(p,
236
                                     "%s Cache level %lu:\n"
237
                                     "\tSize           : %lu bytes\n"
238
                                     "\tAttributes     : ",
239
                                     cache_types[j+cci.pcci_unified], i+1,
240
                                     cci.pcci_cache_size);
241
 
242
                        if (cci.pcci_unified) p += sprintf(p, "Unified ");
243
 
244
                        p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
245
 
246
                        p += sprintf(p,
247
                                     "\tAssociativity  : %d\n"
248
                                     "\tLine size      : %d bytes\n"
249
                                     "\tStride         : %d bytes\n",
250
                                     cci.pcci_assoc, 1<<cci.pcci_line_size, 1<<cci.pcci_stride);
251
                        if (j == 1)
252
                                p += sprintf(p, "\tStore latency  : N/A\n");
253
                        else
254
                                p += sprintf(p, "\tStore latency  : %d cycle(s)\n",
255
                                                cci.pcci_st_latency);
256
 
257
                        p += sprintf(p,
258
                                     "\tLoad latency   : %d cycle(s)\n"
259
                                     "\tStore hints    : ", cci.pcci_ld_latency);
260
 
261
                        for(k=0; k < 8; k++ ) {
262
                                if ( cci.pcci_st_hints & 0x1)
263
                                        p += sprintf(p, "[%s]", cache_st_hints[k]);
264
                                cci.pcci_st_hints >>=1;
265
                        }
266
                        p += sprintf(p, "\n\tLoad hints     : ");
267
 
268
                        for(k=0; k < 8; k++ ) {
269
                                if (cci.pcci_ld_hints & 0x1)
270
                                        p += sprintf(p, "[%s]", cache_ld_hints[k]);
271
                                cci.pcci_ld_hints >>=1;
272
                        }
273
                        p += sprintf(p,
274
                                     "\n\tAlias boundary : %d byte(s)\n"
275
                                     "\tTag LSB        : %d\n"
276
                                     "\tTag MSB        : %d\n",
277
                                     1<<cci.pcci_alias_boundary, cci.pcci_tag_lsb,
278
                                     cci.pcci_tag_msb);
279
 
280
                        /* when unified, data(j=2) is enough */
281
                        if (cci.pcci_unified) break;
282
                }
283
        }
284
        return p - page;
285
}
286
 
287
 
288
static int
289
vm_info(char *page)
290
{
291
        char *p = page;
292
        u64 tr_pages =0, vw_pages=0, tc_pages;
293
        u64 attrib;
294
        pal_vm_info_1_u_t vm_info_1;
295
        pal_vm_info_2_u_t vm_info_2;
296
        pal_tc_info_u_t tc_info;
297
        ia64_ptce_info_t ptce;
298
        const char *sep;
299
        int i, j;
300
        s64 status;
301
 
302
        if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
303
                printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
304
                return 0;
305
        }
306
 
307
 
308
        p += sprintf(p,
309
                     "Physical Address Space         : %d bits\n"
310
                     "Virtual Address Space          : %d bits\n"
311
                     "Protection Key Registers(PKR)  : %d\n"
312
                     "Implemented bits in PKR.key    : %d\n"
313
                     "Hash Tag ID                    : 0x%x\n"
314
                     "Size of RR.rid                 : %d\n",
315
                     vm_info_1.pal_vm_info_1_s.phys_add_size,
316
                     vm_info_2.pal_vm_info_2_s.impl_va_msb+1, vm_info_1.pal_vm_info_1_s.max_pkr+1,
317
                     vm_info_1.pal_vm_info_1_s.key_size, vm_info_1.pal_vm_info_1_s.hash_tag_id,
318
                     vm_info_2.pal_vm_info_2_s.rid_size);
319
 
320
        if (ia64_pal_mem_attrib(&attrib) != 0)
321
                return 0;
322
 
323
        p += sprintf(p, "Supported memory attributes    : ");
324
        sep = "";
325
        for (i = 0; i < 8; i++) {
326
                if (attrib & (1 << i)) {
327
                        p += sprintf(p, "%s%s", sep, mem_attrib[i]);
328
                        sep = ", ";
329
                }
330
        }
331
        p += sprintf(p, "\n");
332
 
333
        if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
334
                printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status);
335
                return 0;
336
        }
337
 
338
        p += sprintf(p,
339
                     "\nTLB walker                     : %simplemented\n"
340
                     "Number of DTR                  : %d\n"
341
                     "Number of ITR                  : %d\n"
342
                     "TLB insertable page sizes      : ",
343
                     vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
344
                     vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
345
                     vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
346
 
347
 
348
        p = bitvector_process(p, tr_pages);
349
 
350
        p += sprintf(p, "\nTLB purgeable page sizes       : ");
351
 
352
        p = bitvector_process(p, vw_pages);
353
 
354
        if ((status=ia64_get_ptce(&ptce)) != 0) {
355
                printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
356
                return 0;
357
        }
358
 
359
        p += sprintf(p,
360
                     "\nPurge base address             : 0x%016lx\n"
361
                     "Purge outer loop count         : %d\n"
362
                     "Purge inner loop count         : %d\n"
363
                     "Purge outer loop stride        : %d\n"
364
                     "Purge inner loop stride        : %d\n",
365
                     ptce.base, ptce.count[0], ptce.count[1], ptce.stride[0], ptce.stride[1]);
366
 
367
        p += sprintf(p,
368
                     "TC Levels                      : %d\n"
369
                     "Unique TC(s)                   : %d\n",
370
                     vm_info_1.pal_vm_info_1_s.num_tc_levels,
371
                     vm_info_1.pal_vm_info_1_s.max_unique_tcs);
372
 
373
        for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
374
                for (j=2; j>0 ; j--) {
375
                        tc_pages = 0; /* just in case */
376
 
377
 
378
                        /* even without unification, some levels may not be present */
379
                        if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
380
                                continue;
381
                        }
382
 
383
                        p += sprintf(p,
384
                                     "\n%s Translation Cache Level %d:\n"
385
                                     "\tHash sets           : %d\n"
386
                                     "\tAssociativity       : %d\n"
387
                                     "\tNumber of entries   : %d\n"
388
                                     "\tFlags               : ",
389
                                     cache_types[j+tc_info.tc_unified], i+1, tc_info.tc_num_sets,
390
                                     tc_info.tc_associativity, tc_info.tc_num_entries);
391
 
392
                        if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized ");
393
                        if (tc_info.tc_unified) p += sprintf(p, "Unified ");
394
                        if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction");
395
 
396
                        p += sprintf(p, "\n\tSupported page sizes: ");
397
 
398
                        p = bitvector_process(p, tc_pages);
399
 
400
                        /* when unified date (j=2) is enough */
401
                        if (tc_info.tc_unified) break;
402
                }
403
        }
404
        p += sprintf(p, "\n");
405
 
406
        return p - page;
407
}
408
 
409
 
410
static int
411
register_info(char *page)
412
{
413
        char *p = page;
414
        u64 reg_info[2];
415
        u64 info;
416
        u64 phys_stacked;
417
        pal_hints_u_t hints;
418
        u64 iregs, dregs;
419
        char *info_type[]={
420
                "Implemented AR(s)",
421
                "AR(s) with read side-effects",
422
                "Implemented CR(s)",
423
                "CR(s) with read side-effects",
424
        };
425
 
426
        for(info=0; info < 4; info++) {
427
 
428
                if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
429
 
430
                p += sprintf(p, "%-32s : ", info_type[info]);
431
 
432
                p = bitregister_process(p, reg_info, 128);
433
 
434
                p += sprintf(p, "\n");
435
        }
436
 
437
        if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0;
438
 
439
        p += sprintf(p,
440
                     "RSE stacked physical registers   : %ld\n"
441
                     "RSE load/store hints             : %ld (%s)\n",
442
                     phys_stacked, hints.ph_data,
443
                     hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
444
 
445
        if (ia64_pal_debug_info(&iregs, &dregs))
446
                return 0;
447
 
448
        p += sprintf(p,
449
                     "Instruction debug register pairs : %ld\n"
450
                     "Data debug register pairs        : %ld\n", iregs, dregs);
451
 
452
        return p - page;
453
}
454
 
455
static const char *proc_features[]={
456
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
457
        NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
458
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
459
        NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,
460
        NULL,NULL,NULL,NULL,NULL,
461
        "XIP,XPSR,XFS implemented",
462
        "XR1-XR3 implemented",
463
        "Disable dynamic predicate prediction",
464
        "Disable processor physical number",
465
        "Disable dynamic data cache prefetch",
466
        "Disable dynamic inst cache prefetch",
467
        "Disable dynamic branch prediction",
468
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
469
        "Disable BINIT on processor time-out",
470
        "Disable dynamic power management (DPM)",
471
        "Disable coherency",
472
        "Disable cache",
473
        "Enable CMCI promotion",
474
        "Enable MCA to BINIT promotion",
475
        "Enable MCA promotion",
476
        "Enable BEER promotion"
477
};
478
 
479
 
480
static int
481
processor_info(char *page)
482
{
483
        char *p = page;
484
        const char **v = proc_features;
485
        u64 avail=1, status=1, control=1;
486
        int i;
487
        s64 ret;
488
 
489
        if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0;
490
 
491
        for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) {
492
                if ( ! *v ) continue;
493
                p += sprintf(p, "%-40s : %s%s %s\n", *v,
494
                                avail & 0x1 ? "" : "NotImpl",
495
                                avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "",
496
                                avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
497
        }
498
        return p - page;
499
}
500
 
501
static const char *bus_features[]={
502
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
503
        NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
504
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
505
        NULL,NULL,
506
        "Request  Bus Parking",
507
        "Bus Lock Mask",
508
        "Enable Half Transfer",
509
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
510
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
511
        NULL, NULL, NULL, NULL,
512
        "Enable Cache Line Repl. Exclusive",
513
        "Enable Cache Line Repl. Shared",
514
        "Disable Transaction Queuing",
515
        "Disable Reponse Error Checking",
516
        "Disable Bus Error Checking",
517
        "Disable Bus Requester Internal Error Signalling",
518
        "Disable Bus Requester Error Signalling",
519
        "Disable Bus Initialization Event Checking",
520
        "Disable Bus Initialization Event Signalling",
521
        "Disable Bus Address Error Checking",
522
        "Disable Bus Address Error Signalling",
523
        "Disable Bus Data Error Checking"
524
};
525
 
526
 
527
static int
528
bus_info(char *page)
529
{
530
        char *p = page;
531
        const char **v = bus_features;
532
        pal_bus_features_u_t av, st, ct;
533
        u64 avail, status, control;
534
        int i;
535
        s64 ret;
536
 
537
        if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0;
538
 
539
        avail   = av.pal_bus_features_val;
540
        status  = st.pal_bus_features_val;
541
        control = ct.pal_bus_features_val;
542
 
543
        for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
544
                if ( ! *v ) continue;
545
                p += sprintf(p, "%-48s : %s%s %s\n", *v,
546
                                avail & 0x1 ? "" : "NotImpl",
547
                                avail & 0x1 ? (status  & 0x1 ? "On" : "Off"): "",
548
                                avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
549
        }
550
        return p - page;
551
}
552
 
553
static int
554
version_info(char *page)
555
{
556
        pal_version_u_t min_ver, cur_ver;
557
        char *p = page;
558
 
559
        /* The PAL_VERSION call is advertised as being able to support
560
         * both physical and virtual mode calls. This seems to be a documentation
561
         * bug rather than firmware bug. In fact, it does only support physical mode.
562
         * So now the code reflects this fact and the pal_version() has been updated
563
         * accordingly.
564
         */
565
        if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0;
566
 
567
        p += sprintf(p,
568
                     "PAL_vendor : 0x%02x (min=0x%02x)\n"
569
                     "PAL_A      : %x.%x.%x (min=%x.%x.%x)\n"
570
                     "PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",
571
                     cur_ver.pal_version_s.pv_pal_vendor, min_ver.pal_version_s.pv_pal_vendor,
572
 
573
                     cur_ver.pal_version_s.pv_pal_a_model>>4,
574
                     cur_ver.pal_version_s.pv_pal_a_model&0xf, cur_ver.pal_version_s.pv_pal_a_rev,
575
                     min_ver.pal_version_s.pv_pal_a_model>>4,
576
                     min_ver.pal_version_s.pv_pal_a_model&0xf, min_ver.pal_version_s.pv_pal_a_rev,
577
 
578
                     cur_ver.pal_version_s.pv_pal_b_model>>4,
579
                     cur_ver.pal_version_s.pv_pal_b_model&0xf, cur_ver.pal_version_s.pv_pal_b_rev,
580
                     min_ver.pal_version_s.pv_pal_b_model>>4,
581
                     min_ver.pal_version_s.pv_pal_b_model&0xf, min_ver.pal_version_s.pv_pal_b_rev);
582
        return p - page;
583
}
584
 
585
static int
586
perfmon_info(char *page)
587
{
588
        char *p = page;
589
        u64 pm_buffer[16];
590
        pal_perf_mon_info_u_t pm_info;
591
 
592
        if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
593
 
594
        p += sprintf(p,
595
                     "PMC/PMD pairs                 : %d\n"
596
                     "Counter width                 : %d bits\n"
597
                     "Cycle event number            : %d\n"
598
                     "Retired event number          : %d\n"
599
                     "Implemented PMC               : ",
600
                     pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width,
601
                     pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired);
602
 
603
        p = bitregister_process(p, pm_buffer, 256);
604
        p += sprintf(p, "\nImplemented PMD               : ");
605
        p = bitregister_process(p, pm_buffer+4, 256);
606
        p += sprintf(p, "\nCycles count capable          : ");
607
        p = bitregister_process(p, pm_buffer+8, 256);
608
        p += sprintf(p, "\nRetired bundles count capable : ");
609
 
610
#ifdef CONFIG_ITANIUM
611
        /*
612
         * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES
613
         * which is wrong, both PMC4 and PMD5 support it.
614
         */
615
        if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30;
616
#endif
617
 
618
        p = bitregister_process(p, pm_buffer+12, 256);
619
 
620
        p += sprintf(p, "\n");
621
 
622
        return p - page;
623
}
624
 
625
static int
626
frequency_info(char *page)
627
{
628
        char *p = page;
629
        struct pal_freq_ratio proc, itc, bus;
630
        u64 base;
631
 
632
        if (ia64_pal_freq_base(&base) == -1)
633
                p += sprintf(p, "Output clock            : not implemented\n");
634
        else
635
                p += sprintf(p, "Output clock            : %ld ticks/s\n", base);
636
 
637
        if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
638
 
639
        p += sprintf(p,
640
                     "Processor/Clock ratio   : %ld/%ld\n"
641
                     "Bus/Clock ratio         : %ld/%ld\n"
642
                     "ITC/Clock ratio         : %ld/%ld\n",
643
                     proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
644
 
645
        return p - page;
646
}
647
 
648
static int
649
tr_info(char *page)
650
{
651
        char *p = page;
652
        s64 status;
653
        pal_tr_valid_u_t tr_valid;
654
        u64 tr_buffer[4];
655
        pal_vm_info_1_u_t vm_info_1;
656
        pal_vm_info_2_u_t vm_info_2;
657
        u64 i, j;
658
        u64 max[3], pgm;
659
        struct ifa_reg {
660
                u64 valid:1;
661
                u64 ig:11;
662
                u64 vpn:52;
663
        } *ifa_reg;
664
        struct itir_reg {
665
                u64 rv1:2;
666
                u64 ps:6;
667
                u64 key:24;
668
                u64 rv2:32;
669
        } *itir_reg;
670
        struct gr_reg {
671
                u64 p:1;
672
                u64 rv1:1;
673
                u64 ma:3;
674
                u64 a:1;
675
                u64 d:1;
676
                u64 pl:2;
677
                u64 ar:3;
678
                u64 ppn:38;
679
                u64 rv2:2;
680
                u64 ed:1;
681
                u64 ig:11;
682
        } *gr_reg;
683
        struct rid_reg {
684
                u64 ig1:1;
685
                u64 rv1:1;
686
                u64 ig2:6;
687
                u64 rid:24;
688
                u64 rv2:32;
689
        } *rid_reg;
690
 
691
        if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
692
                printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
693
                return 0;
694
        }
695
        max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
696
        max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
697
 
698
        for (i=0; i < 2; i++ ) {
699
                for (j=0; j < max[i]; j++) {
700
 
701
                status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
702
                if (status != 0) {
703
                        printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
704
                               i, j, status);
705
                        continue;
706
                }
707
 
708
                ifa_reg  = (struct ifa_reg *)&tr_buffer[2];
709
 
710
                if (ifa_reg->valid == 0) continue;
711
 
712
                gr_reg   = (struct gr_reg *)tr_buffer;
713
                itir_reg = (struct itir_reg *)&tr_buffer[1];
714
                rid_reg  = (struct rid_reg *)&tr_buffer[3];
715
 
716
                pgm      = -1 << (itir_reg->ps - 12);
717
                p += sprintf(p,
718
                             "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
719
                             "\tppn  : 0x%lx\n"
720
                             "\tvpn  : 0x%lx\n"
721
                             "\tps   : ",
722
                             "ID"[i], j,
723
                             tr_valid.pal_tr_valid_s.access_rights_valid,
724
                             tr_valid.pal_tr_valid_s.priv_level_valid,
725
                             tr_valid.pal_tr_valid_s.dirty_bit_valid,
726
                             tr_valid.pal_tr_valid_s.mem_attr_valid,
727
                             (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
728
 
729
                p = bitvector_process(p, 1<< itir_reg->ps);
730
 
731
                p += sprintf(p,
732
                             "\n\tpl   : %d\n"
733
                             "\tar   : %d\n"
734
                             "\trid  : %x\n"
735
                             "\tp    : %d\n"
736
                             "\tma   : %d\n"
737
                             "\td    : %d\n",
738
                             gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
739
                             gr_reg->d);
740
                }
741
        }
742
        return p - page;
743
}
744
 
745
 
746
 
747
/*
748
 * List {name,function} pairs for every entry in /proc/palinfo/cpu*
749
 */
750
static palinfo_entry_t palinfo_entries[]={
751
        { "version_info",       version_info, },
752
        { "vm_info",            vm_info, },
753
        { "cache_info",         cache_info, },
754
        { "power_info",         power_info, },
755
        { "register_info",      register_info, },
756
        { "processor_info",     processor_info, },
757
        { "perfmon_info",       perfmon_info, },
758
        { "frequency_info",     frequency_info, },
759
        { "bus_info",           bus_info },
760
        { "tr_info",            tr_info, }
761
};
762
 
763
#define NR_PALINFO_ENTRIES      (int) ARRAY_SIZE(palinfo_entries)
764
 
765
/*
766
 * this array is used to keep track of the proc entries we create. This is
767
 * required in the module mode when we need to remove all entries. The procfs code
768
 * does not do recursion of deletion
769
 *
770
 * Notes:
771
 *      - first +1 accounts for the cpuN entry
772
 *      - second +1 account for toplevel palinfo
773
 *
774
 */
775
#define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1)
776
 
777
static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
778
 
779
/*
780
 * This data structure is used to pass which cpu,function is being requested
781
 * It must fit in a 64bit quantity to be passed to the proc callback routine
782
 *
783
 * In SMP mode, when we get a request for another CPU, we must call that
784
 * other CPU using IPI and wait for the result before returning.
785
 */
786
typedef union {
787
        u64 value;
788
        struct {
789
                unsigned        req_cpu: 32;    /* for which CPU this info is */
790
                unsigned        func_id: 32;    /* which function is requested */
791
        } pal_func_cpu;
792
} pal_func_cpu_u_t;
793
 
794
#define req_cpu pal_func_cpu.req_cpu
795
#define func_id pal_func_cpu.func_id
796
 
797
#ifdef CONFIG_SMP
798
 
799
/*
800
 * used to hold information about final function to call
801
 */
802
typedef struct {
803
        palinfo_func_t  func;   /* pointer to function to call */
804
        char            *page;  /* buffer to store results */
805
        int             ret;    /* return value from call */
806
} palinfo_smp_data_t;
807
 
808
 
809
/*
810
 * this function does the actual final call and he called
811
 * from the smp code, i.e., this is the palinfo callback routine
812
 */
813
static void
814
palinfo_smp_call(void *info)
815
{
816
        palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
817
        if (data == NULL) {
818
                printk(KERN_ERR "palinfo: data pointer is NULL\n");
819
                data->ret = 0; /* no output */
820
                return;
821
        }
822
        /* does this actual call */
823
        data->ret = (*data->func)(data->page);
824
}
825
 
826
/*
827
 * function called to trigger the IPI, we need to access a remote CPU
828
 * Return:
829
 *      0 : error or nothing to output
830
 *      otherwise how many bytes in the "page" buffer were written
831
 */
832
static
833
int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
834
{
835
        palinfo_smp_data_t ptr;
836
        int ret;
837
 
838
        ptr.func = palinfo_entries[f->func_id].proc_read;
839
        ptr.page = page;
840
        ptr.ret  = 0; /* just in case */
841
 
842
 
843
        /* will send IPI to other CPU and wait for completion of remote call */
844
        if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
845
                printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
846
                       "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
847
                return 0;
848
        }
849
        return ptr.ret;
850
}
851
#else /* ! CONFIG_SMP */
852
static
853
int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
854
{
855
        printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
856
        return 0;
857
}
858
#endif /* CONFIG_SMP */
859
 
860
/*
861
 * Entry point routine: all calls go through this function
862
 */
863
static int
864
palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
865
{
866
        int len=0;
867
        pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
868
 
869
        MOD_INC_USE_COUNT;
870
        /*
871
         * in SMP mode, we may need to call another CPU to get correct
872
         * information. PAL, by definition, is processor specific
873
         */
874
        if (f->req_cpu == smp_processor_id())
875
                len = (*palinfo_entries[f->func_id].proc_read)(page);
876
        else
877
                len = palinfo_handle_smp(f, page);
878
 
879
        if (len <= off+count) *eof = 1;
880
 
881
        *start = page + off;
882
        len   -= off;
883
 
884
        if (len>count) len = count;
885
        if (len<0) len = 0;
886
 
887
        MOD_DEC_USE_COUNT;
888
 
889
        return len;
890
}
891
 
892
static int __init
893
palinfo_init(void)
894
{
895
#       define CPUSTR   "cpu%d"
896
 
897
        pal_func_cpu_u_t f;
898
        struct proc_dir_entry **pdir = palinfo_proc_entries;
899
        struct proc_dir_entry *palinfo_dir, *cpu_dir;
900
        int i, j;
901
        char cpustr[sizeof(CPUSTR)];
902
 
903
        printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
904
 
905
        palinfo_dir = proc_mkdir("pal", NULL);
906
 
907
        /*
908
         * we keep track of created entries in a depth-first order for
909
         * cleanup purposes. Each entry is stored into palinfo_proc_entries
910
         */
911
        for (i=0; i < NR_CPUS; i++) {
912
 
913
                if (!cpu_online(i)) continue;
914
 
915
                sprintf(cpustr,CPUSTR, i);
916
 
917
                cpu_dir = proc_mkdir(cpustr, palinfo_dir);
918
 
919
                f.req_cpu = i;
920
 
921
                for (j=0; j < NR_PALINFO_ENTRIES; j++) {
922
                        f.func_id = j;
923
                        *pdir = create_proc_read_entry(
924
                                        palinfo_entries[j].name, 0, cpu_dir,
925
                                        palinfo_read_entry, (void *)f.value);
926
                        pdir++;
927
                }
928
                *pdir++ = cpu_dir;
929
        }
930
        *pdir = palinfo_dir;
931
 
932
        return 0;
933
}
934
 
935
static void __exit
936
palinfo_exit(void)
937
{
938
        int i = 0;
939
 
940
        /* remove all nodes: depth first pass. Could optimize this  */
941
        for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) {
942
                if (palinfo_proc_entries[i])
943
                        remove_proc_entry (palinfo_proc_entries[i]->name, NULL);
944
        }
945
}
946
 
947
module_init(palinfo_init);
948
module_exit(palinfo_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.