powerpc/pseries: Remove extraneous error reporting for hcall failures in lparcfg
[safe/jmp/linux-2.6] / arch / powerpc / kernel / lparcfg.c
1 /*
2  * PowerPC64 LPAR Configuration Information Driver
3  *
4  * Dave Engebretsen engebret@us.ibm.com
5  *    Copyright (c) 2003 Dave Engebretsen
6  * Will Schmidt willschm@us.ibm.com
7  *    SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation.
8  *    seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation.
9  * Nathan Lynch nathanl@austin.ibm.com
10  *    Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation.
11  *
12  *      This program is free software; you can redistribute it and/or
13  *      modify it under the terms of the GNU General Public License
14  *      as published by the Free Software Foundation; either version
15  *      2 of the License, or (at your option) any later version.
16  *
17  * This driver creates a proc file at /proc/ppc64/lparcfg which contains
18  * keyword - value pairs that specify the configuration of the partition.
19  */
20
21 #include <linux/module.h>
22 #include <linux/types.h>
23 #include <linux/errno.h>
24 #include <linux/proc_fs.h>
25 #include <linux/init.h>
26 #include <linux/seq_file.h>
27 #include <asm/uaccess.h>
28 #include <asm/iseries/hv_lp_config.h>
29 #include <asm/lppaca.h>
30 #include <asm/hvcall.h>
31 #include <asm/firmware.h>
32 #include <asm/rtas.h>
33 #include <asm/system.h>
34 #include <asm/time.h>
35 #include <asm/prom.h>
36 #include <asm/vdso_datapage.h>
37
38 #define MODULE_VERS "1.7"
39 #define MODULE_NAME "lparcfg"
40
41 /* #define LPARCFG_DEBUG */
42
43 static struct proc_dir_entry *proc_ppc64_lparcfg;
44
45 /*
46  * Track sum of all purrs across all processors. This is used to further
47  * calculate usage values by different applications
48  */
49 static unsigned long get_purr(void)
50 {
51         unsigned long sum_purr = 0;
52         int cpu;
53
54         for_each_possible_cpu(cpu) {
55                 if (firmware_has_feature(FW_FEATURE_ISERIES))
56                         sum_purr += lppaca[cpu].emulated_time_base;
57                 else {
58                         struct cpu_usage *cu;
59
60                         cu = &per_cpu(cpu_usage_array, cpu);
61                         sum_purr += cu->current_tb;
62                 }
63         }
64         return sum_purr;
65 }
66
67 #ifdef CONFIG_PPC_ISERIES
68
69 /*
70  * Methods used to fetch LPAR data when running on an iSeries platform.
71  */
72 static int iseries_lparcfg_data(struct seq_file *m, void *v)
73 {
74         unsigned long pool_id;
75         int shared, entitled_capacity, max_entitled_capacity;
76         int processors, max_processors;
77         unsigned long purr = get_purr();
78
79         shared = (int)(local_paca->lppaca_ptr->shared_proc);
80
81         seq_printf(m, "system_active_processors=%d\n",
82                    (int)HvLpConfig_getSystemPhysicalProcessors());
83
84         seq_printf(m, "system_potential_processors=%d\n",
85                    (int)HvLpConfig_getSystemPhysicalProcessors());
86
87         processors = (int)HvLpConfig_getPhysicalProcessors();
88         seq_printf(m, "partition_active_processors=%d\n", processors);
89
90         max_processors = (int)HvLpConfig_getMaxPhysicalProcessors();
91         seq_printf(m, "partition_potential_processors=%d\n", max_processors);
92
93         if (shared) {
94                 entitled_capacity = HvLpConfig_getSharedProcUnits();
95                 max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits();
96         } else {
97                 entitled_capacity = processors * 100;
98                 max_entitled_capacity = max_processors * 100;
99         }
100         seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity);
101
102         seq_printf(m, "partition_max_entitled_capacity=%d\n",
103                    max_entitled_capacity);
104
105         if (shared) {
106                 pool_id = HvLpConfig_getSharedPoolIndex();
107                 seq_printf(m, "pool=%d\n", (int)pool_id);
108                 seq_printf(m, "pool_capacity=%d\n",
109                            (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) *
110                                  100));
111                 seq_printf(m, "purr=%ld\n", purr);
112         }
113
114         seq_printf(m, "shared_processor_mode=%d\n", shared);
115
116         return 0;
117 }
118
119 #else                           /* CONFIG_PPC_ISERIES */
120
121 static int iseries_lparcfg_data(struct seq_file *m, void *v)
122 {
123         return 0;
124 }
125
126 #endif                          /* CONFIG_PPC_ISERIES */
127
128 #ifdef CONFIG_PPC_PSERIES
129 /*
130  * Methods used to fetch LPAR data when running on a pSeries platform.
131  */
132 /*
133  * H_GET_PPP hcall returns info in 4 parms.
134  *  entitled_capacity,unallocated_capacity,
135  *  aggregation, resource_capability).
136  *
137  *  R4 = Entitled Processor Capacity Percentage.
138  *  R5 = Unallocated Processor Capacity Percentage.
139  *  R6 (AABBCCDDEEFFGGHH).
140  *      XXXX - reserved (0)
141  *          XXXX - reserved (0)
142  *              XXXX - Group Number
143  *                  XXXX - Pool Number.
144  *  R7 (IIJJKKLLMMNNOOPP).
145  *      XX - reserved. (0)
146  *        XX - bit 0-6 reserved (0).   bit 7 is Capped indicator.
147  *          XX - variable processor Capacity Weight
148  *            XX - Unallocated Variable Processor Capacity Weight.
149  *              XXXX - Active processors in Physical Processor Pool.
150  *                  XXXX  - Processors active on platform.
151  */
152 static unsigned int h_get_ppp(unsigned long *entitled,
153                               unsigned long *unallocated,
154                               unsigned long *aggregation,
155                               unsigned long *resource)
156 {
157         unsigned long rc;
158         unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
159
160         rc = plpar_hcall(H_GET_PPP, retbuf);
161
162         *entitled = retbuf[0];
163         *unallocated = retbuf[1];
164         *aggregation = retbuf[2];
165         *resource = retbuf[3];
166
167         return rc;
168 }
169
170 static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)
171 {
172         unsigned long rc;
173         unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
174
175         rc = plpar_hcall(H_PIC, retbuf);
176
177         *pool_idle_time = retbuf[0];
178         *num_procs = retbuf[1];
179 }
180
181 #define SPLPAR_CHARACTERISTICS_TOKEN 20
182 #define SPLPAR_MAXLENGTH 1026*(sizeof(char))
183
184 /*
185  * parse_system_parameter_string()
186  * Retrieve the potential_processors, max_entitled_capacity and friends
187  * through the get-system-parameter rtas call.  Replace keyword strings as
188  * necessary.
189  */
190 static void parse_system_parameter_string(struct seq_file *m)
191 {
192         int call_status;
193
194         unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
195         if (!local_buffer) {
196                 printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
197                        __FILE__, __func__, __LINE__);
198                 return;
199         }
200
201         spin_lock(&rtas_data_buf_lock);
202         memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
203         call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
204                                 NULL,
205                                 SPLPAR_CHARACTERISTICS_TOKEN,
206                                 __pa(rtas_data_buf),
207                                 RTAS_DATA_BUF_SIZE);
208         memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
209         spin_unlock(&rtas_data_buf_lock);
210
211         if (call_status != 0) {
212                 printk(KERN_INFO
213                        "%s %s Error calling get-system-parameter (0x%x)\n",
214                        __FILE__, __func__, call_status);
215         } else {
216                 int splpar_strlen;
217                 int idx, w_idx;
218                 char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
219                 if (!workbuffer) {
220                         printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
221                                __FILE__, __func__, __LINE__);
222                         kfree(local_buffer);
223                         return;
224                 }
225 #ifdef LPARCFG_DEBUG
226                 printk(KERN_INFO "success calling get-system-parameter \n");
227 #endif
228                 splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
229                 local_buffer += 2;      /* step over strlen value */
230
231                 w_idx = 0;
232                 idx = 0;
233                 while ((*local_buffer) && (idx < splpar_strlen)) {
234                         workbuffer[w_idx++] = local_buffer[idx++];
235                         if ((local_buffer[idx] == ',')
236                             || (local_buffer[idx] == '\0')) {
237                                 workbuffer[w_idx] = '\0';
238                                 if (w_idx) {
239                                         /* avoid the empty string */
240                                         seq_printf(m, "%s\n", workbuffer);
241                                 }
242                                 memset(workbuffer, 0, SPLPAR_MAXLENGTH);
243                                 idx++;  /* skip the comma */
244                                 w_idx = 0;
245                         } else if (local_buffer[idx] == '=') {
246                                 /* code here to replace workbuffer contents
247                                    with different keyword strings */
248                                 if (0 == strcmp(workbuffer, "MaxEntCap")) {
249                                         strcpy(workbuffer,
250                                                "partition_max_entitled_capacity");
251                                         w_idx = strlen(workbuffer);
252                                 }
253                                 if (0 == strcmp(workbuffer, "MaxPlatProcs")) {
254                                         strcpy(workbuffer,
255                                                "system_potential_processors");
256                                         w_idx = strlen(workbuffer);
257                                 }
258                         }
259                 }
260                 kfree(workbuffer);
261                 local_buffer -= 2;      /* back up over strlen value */
262         }
263         kfree(local_buffer);
264 }
265
266 /* Return the number of processors in the system.
267  * This function reads through the device tree and counts
268  * the virtual processors, this does not include threads.
269  */
270 static int lparcfg_count_active_processors(void)
271 {
272         struct device_node *cpus_dn = NULL;
273         int count = 0;
274
275         while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) {
276 #ifdef LPARCFG_DEBUG
277                 printk(KERN_ERR "cpus_dn %p \n", cpus_dn);
278 #endif
279                 count++;
280         }
281         return count;
282 }
283
284 static int pseries_lparcfg_data(struct seq_file *m, void *v)
285 {
286         int partition_potential_processors;
287         int partition_active_processors;
288         struct device_node *rtas_node;
289         const int *lrdrp = NULL;
290
291         rtas_node = of_find_node_by_path("/rtas");
292         if (rtas_node)
293                 lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
294
295         if (lrdrp == NULL) {
296                 partition_potential_processors = vdso_data->processorCount;
297         } else {
298                 partition_potential_processors = *(lrdrp + 4);
299         }
300         of_node_put(rtas_node);
301
302         partition_active_processors = lparcfg_count_active_processors();
303
304         if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
305                 unsigned long h_entitled, h_unallocated;
306                 unsigned long h_aggregation, h_resource;
307                 unsigned long pool_idle_time, pool_procs;
308                 unsigned long purr;
309
310                 h_get_ppp(&h_entitled, &h_unallocated, &h_aggregation,
311                           &h_resource);
312
313                 seq_printf(m, "R4=0x%lx\n", h_entitled);
314                 seq_printf(m, "R5=0x%lx\n", h_unallocated);
315                 seq_printf(m, "R6=0x%lx\n", h_aggregation);
316                 seq_printf(m, "R7=0x%lx\n", h_resource);
317
318                 purr = get_purr();
319
320                 /* this call handles the ibm,get-system-parameter contents */
321                 parse_system_parameter_string(m);
322
323                 seq_printf(m, "partition_entitled_capacity=%ld\n", h_entitled);
324
325                 seq_printf(m, "group=%ld\n", (h_aggregation >> 2 * 8) & 0xffff);
326
327                 seq_printf(m, "system_active_processors=%ld\n",
328                            (h_resource >> 0 * 8) & 0xffff);
329
330                 /* pool related entries are apropriate for shared configs */
331                 if (lppaca[0].shared_proc) {
332
333                         h_pic(&pool_idle_time, &pool_procs);
334
335                         seq_printf(m, "pool=%ld\n",
336                                    (h_aggregation >> 0 * 8) & 0xffff);
337
338                         /* report pool_capacity in percentage */
339                         seq_printf(m, "pool_capacity=%ld\n",
340                                    ((h_resource >> 2 * 8) & 0xffff) * 100);
341
342                         seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time);
343
344                         seq_printf(m, "pool_num_procs=%ld\n", pool_procs);
345                 }
346
347                 seq_printf(m, "unallocated_capacity_weight=%ld\n",
348                            (h_resource >> 4 * 8) & 0xFF);
349
350                 seq_printf(m, "capacity_weight=%ld\n",
351                            (h_resource >> 5 * 8) & 0xFF);
352
353                 seq_printf(m, "capped=%ld\n", (h_resource >> 6 * 8) & 0x01);
354
355                 seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated);
356
357                 seq_printf(m, "purr=%ld\n", purr);
358
359         } else {                /* non SPLPAR case */
360
361                 seq_printf(m, "system_active_processors=%d\n",
362                            partition_potential_processors);
363
364                 seq_printf(m, "system_potential_processors=%d\n",
365                            partition_potential_processors);
366
367                 seq_printf(m, "partition_max_entitled_capacity=%d\n",
368                            partition_potential_processors * 100);
369
370                 seq_printf(m, "partition_entitled_capacity=%d\n",
371                            partition_active_processors * 100);
372         }
373
374         seq_printf(m, "partition_active_processors=%d\n",
375                    partition_active_processors);
376
377         seq_printf(m, "partition_potential_processors=%d\n",
378                    partition_potential_processors);
379
380         seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
381
382         return 0;
383 }
384
385 /*
386  * Interface for changing system parameters (variable capacity weight
387  * and entitled capacity).  Format of input is "param_name=value";
388  * anything after value is ignored.  Valid parameters at this time are
389  * "partition_entitled_capacity" and "capacity_weight".  We use
390  * H_SET_PPP to alter parameters.
391  *
392  * This function should be invoked only on systems with
393  * FW_FEATURE_SPLPAR.
394  */
395 static ssize_t lparcfg_write(struct file *file, const char __user * buf,
396                              size_t count, loff_t * off)
397 {
398         char *kbuf;
399         char *tmp;
400         u64 new_entitled, *new_entitled_ptr = &new_entitled;
401         u8 new_weight, *new_weight_ptr = &new_weight;
402
403         unsigned long current_entitled; /* parameters for h_get_ppp */
404         unsigned long dummy;
405         unsigned long resource;
406         u8 current_weight;
407
408         ssize_t retval = -ENOMEM;
409
410         if (!firmware_has_feature(FW_FEATURE_SPLPAR) ||
411                         firmware_has_feature(FW_FEATURE_ISERIES))
412                 return -EINVAL;
413
414         kbuf = kmalloc(count, GFP_KERNEL);
415         if (!kbuf)
416                 goto out;
417
418         retval = -EFAULT;
419         if (copy_from_user(kbuf, buf, count))
420                 goto out;
421
422         retval = -EINVAL;
423         kbuf[count - 1] = '\0';
424         tmp = strchr(kbuf, '=');
425         if (!tmp)
426                 goto out;
427
428         *tmp++ = '\0';
429
430         if (!strcmp(kbuf, "partition_entitled_capacity")) {
431                 char *endp;
432                 *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
433                 if (endp == tmp)
434                         goto out;
435                 new_weight_ptr = &current_weight;
436         } else if (!strcmp(kbuf, "capacity_weight")) {
437                 char *endp;
438                 *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
439                 if (endp == tmp)
440                         goto out;
441                 new_entitled_ptr = &current_entitled;
442         } else
443                 goto out;
444
445         /* Get our current parameters */
446         retval = h_get_ppp(&current_entitled, &dummy, &dummy, &resource);
447         if (retval) {
448                 retval = -EIO;
449                 goto out;
450         }
451
452         current_weight = (resource >> 5 * 8) & 0xFF;
453
454         pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
455                  __func__, current_entitled, current_weight);
456
457         pr_debug("%s: new_entitled = %lu, new_weight = %u\n",
458                  __func__, *new_entitled_ptr, *new_weight_ptr);
459
460         retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr,
461                                     *new_weight_ptr);
462
463         if (retval == H_SUCCESS || retval == H_CONSTRAINED) {
464                 retval = count;
465         } else if (retval == H_BUSY) {
466                 retval = -EBUSY;
467         } else if (retval == H_HARDWARE) {
468                 retval = -EIO;
469         } else if (retval == H_PARAMETER) {
470                 retval = -EINVAL;
471         } else {
472                 printk(KERN_WARNING "%s: received unknown hv return code %ld",
473                        __func__, retval);
474                 retval = -EIO;
475         }
476
477 out:
478         kfree(kbuf);
479         return retval;
480 }
481
482 #else                           /* CONFIG_PPC_PSERIES */
483
484 static int pseries_lparcfg_data(struct seq_file *m, void *v)
485 {
486         return 0;
487 }
488
489 static ssize_t lparcfg_write(struct file *file, const char __user * buf,
490                              size_t count, loff_t * off)
491 {
492         return -EINVAL;
493 }
494
495 #endif                          /* CONFIG_PPC_PSERIES */
496
497 static int lparcfg_data(struct seq_file *m, void *v)
498 {
499         struct device_node *rootdn;
500         const char *model = "";
501         const char *system_id = "";
502         const char *tmp;
503         const unsigned int *lp_index_ptr;
504         unsigned int lp_index = 0;
505
506         seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
507
508         rootdn = of_find_node_by_path("/");
509         if (rootdn) {
510                 tmp = of_get_property(rootdn, "model", NULL);
511                 if (tmp) {
512                         model = tmp;
513                         /* Skip "IBM," - see platforms/iseries/dt.c */
514                         if (firmware_has_feature(FW_FEATURE_ISERIES))
515                                 model += 4;
516                 }
517                 tmp = of_get_property(rootdn, "system-id", NULL);
518                 if (tmp) {
519                         system_id = tmp;
520                         /* Skip "IBM," - see platforms/iseries/dt.c */
521                         if (firmware_has_feature(FW_FEATURE_ISERIES))
522                                 system_id += 4;
523                 }
524                 lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
525                                         NULL);
526                 if (lp_index_ptr)
527                         lp_index = *lp_index_ptr;
528                 of_node_put(rootdn);
529         }
530         seq_printf(m, "serial_number=%s\n", system_id);
531         seq_printf(m, "system_type=%s\n", model);
532         seq_printf(m, "partition_id=%d\n", (int)lp_index);
533
534         if (firmware_has_feature(FW_FEATURE_ISERIES))
535                 return iseries_lparcfg_data(m, v);
536         return pseries_lparcfg_data(m, v);
537 }
538
539 static int lparcfg_open(struct inode *inode, struct file *file)
540 {
541         return single_open(file, lparcfg_data, NULL);
542 }
543
544 static const struct file_operations lparcfg_fops = {
545         .owner          = THIS_MODULE,
546         .read           = seq_read,
547         .write          = lparcfg_write,
548         .open           = lparcfg_open,
549         .release        = single_release,
550 };
551
552 static int __init lparcfg_init(void)
553 {
554         struct proc_dir_entry *ent;
555         mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
556
557         /* Allow writing if we have FW_FEATURE_SPLPAR */
558         if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
559                         !firmware_has_feature(FW_FEATURE_ISERIES))
560                 mode |= S_IWUSR;
561
562         ent = proc_create("ppc64/lparcfg", mode, NULL, &lparcfg_fops);
563         if (!ent) {
564                 printk(KERN_ERR "Failed to create ppc64/lparcfg\n");
565                 return -EIO;
566         }
567
568         proc_ppc64_lparcfg = ent;
569         return 0;
570 }
571
572 static void __exit lparcfg_cleanup(void)
573 {
574         if (proc_ppc64_lparcfg)
575                 remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent);
576 }
577
578 module_init(lparcfg_init);
579 module_exit(lparcfg_cleanup);
580 MODULE_DESCRIPTION("Interface for LPAR configuration data");
581 MODULE_AUTHOR("Dave Engebretsen");
582 MODULE_LICENSE("GPL");