1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2000 Tilmann Bitterberg
4 * (tilmann@bitterberg.de)
6 * RTAS (Runtime Abstraction Services) stuff
7 * Intention is to provide a clean user interface
11 * Split off a header file and maybe move it to a different
12 * location. Write Documentation on what the /proc/rtas/ entries
16 #include <linux/errno.h>
17 #include <linux/sched.h>
18 #include <linux/proc_fs.h>
19 #include <linux/stat.h>
20 #include <linux/ctype.h>
21 #include <linux/time.h>
22 #include <linux/string.h>
23 #include <linux/init.h>
24 #include <linux/seq_file.h>
25 #include <linux/bitops.h>
26 #include <linux/rtc.h>
28 #include <linux/uaccess.h>
29 #include <asm/processor.h>
33 #include <asm/machdep.h> /* for ppc_md */
36 /* Token for Sensors */
37 #define KEY_SWITCH 0x0001
38 #define ENCLOSURE_SWITCH 0x0002
39 #define THERMAL_SENSOR 0x0003
40 #define LID_STATUS 0x0004
41 #define POWER_SOURCE 0x0005
42 #define BATTERY_VOLTAGE 0x0006
43 #define BATTERY_REMAINING 0x0007
44 #define BATTERY_PERCENTAGE 0x0008
45 #define EPOW_SENSOR 0x0009
46 #define BATTERY_CYCLESTATE 0x000a
47 #define BATTERY_CHARGING 0x000b
49 /* IBM specific sensors */
50 #define IBM_SURVEILLANCE 0x2328 /* 9000 */
51 #define IBM_FANRPM 0x2329 /* 9001 */
52 #define IBM_VOLTAGE 0x232a /* 9002 */
53 #define IBM_DRCONNECTOR 0x232b /* 9003 */
54 #define IBM_POWERSUPPLY 0x232c /* 9004 */
56 /* Status return values */
57 #define SENSOR_CRITICAL_HIGH 13
58 #define SENSOR_WARNING_HIGH 12
59 #define SENSOR_NORMAL 11
60 #define SENSOR_WARNING_LOW 10
61 #define SENSOR_CRITICAL_LOW 9
62 #define SENSOR_SUCCESS 0
63 #define SENSOR_HW_ERROR -1
64 #define SENSOR_BUSY -2
65 #define SENSOR_NOT_EXIST -3
66 #define SENSOR_DR_ENTITY -9000
69 #define LOC_SCSI_DEV_ADDR 'A'
70 #define LOC_SCSI_DEV_LOC 'B'
72 #define LOC_DISKETTE 'D'
73 #define LOC_ETHERNET 'E'
75 #define LOC_GRAPHICS 'G'
76 /* reserved / not used 'H' */
77 #define LOC_IO_ADAPTER 'I'
78 /* reserved / not used 'J' */
79 #define LOC_KEYBOARD 'K'
81 #define LOC_MEMORY 'M'
82 #define LOC_NV_MEMORY 'N'
84 #define LOC_PLANAR 'P'
85 #define LOC_OTHER_IO 'Q'
86 #define LOC_PARALLEL 'R'
87 #define LOC_SERIAL 'S'
88 #define LOC_DEAD_RING 'T'
89 #define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */
90 #define LOC_VOLTAGE 'V'
91 #define LOC_SWITCH_ADAPTER 'W'
93 #define LOC_FIRMWARE 'Y'
96 /* Tokens for indicators */
97 #define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/
98 #define TONE_VOLUME 0x0002 /* 0 - 100 (%) */
99 #define SYSTEM_POWER_STATE 0x0003
100 #define WARNING_LIGHT 0x0004
101 #define DISK_ACTIVITY_LIGHT 0x0005
102 #define HEX_DISPLAY_UNIT 0x0006
103 #define BATTERY_WARNING_TIME 0x0007
104 #define CONDITION_CYCLE_REQUEST 0x0008
105 #define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */
106 #define DR_ACTION 0x2329 /* 9001 */
107 #define DR_INDICATOR 0x232a /* 9002 */
108 /* 9003 - 9004: Vendor specific */
109 /* 9006 - 9999: Vendor specific */
112 #define MAX_SENSORS 17 /* I only know of 17 sensors */
113 #define MAX_LINELENGTH 256
114 #define SENSOR_PREFIX "ibm,sensor-"
115 #define cel_to_fahr(x) ((x*9/5)+32)
117 struct individual_sensor
{
122 struct rtas_sensors
{
123 struct individual_sensor sensor
[MAX_SENSORS
];
128 static struct rtas_sensors sensors
;
129 static struct device_node
*rtas_node
= NULL
;
130 static unsigned long power_on_time
= 0; /* Save the time the user set */
131 static char progress_led
[MAX_LINELENGTH
];
133 static unsigned long rtas_tone_frequency
= 1000;
134 static unsigned long rtas_tone_volume
= 0;
136 /* ****************************************************************** */
138 static int ppc_rtas_sensors_show(struct seq_file
*m
, void *v
);
139 static int ppc_rtas_clock_show(struct seq_file
*m
, void *v
);
140 static ssize_t
ppc_rtas_clock_write(struct file
*file
,
141 const char __user
*buf
, size_t count
, loff_t
*ppos
);
142 static int ppc_rtas_progress_show(struct seq_file
*m
, void *v
);
143 static ssize_t
ppc_rtas_progress_write(struct file
*file
,
144 const char __user
*buf
, size_t count
, loff_t
*ppos
);
145 static int ppc_rtas_poweron_show(struct seq_file
*m
, void *v
);
146 static ssize_t
ppc_rtas_poweron_write(struct file
*file
,
147 const char __user
*buf
, size_t count
, loff_t
*ppos
);
149 static ssize_t
ppc_rtas_tone_freq_write(struct file
*file
,
150 const char __user
*buf
, size_t count
, loff_t
*ppos
);
151 static int ppc_rtas_tone_freq_show(struct seq_file
*m
, void *v
);
152 static ssize_t
ppc_rtas_tone_volume_write(struct file
*file
,
153 const char __user
*buf
, size_t count
, loff_t
*ppos
);
154 static int ppc_rtas_tone_volume_show(struct seq_file
*m
, void *v
);
155 static int ppc_rtas_rmo_buf_show(struct seq_file
*m
, void *v
);
157 static int sensors_open(struct inode
*inode
, struct file
*file
)
159 return single_open(file
, ppc_rtas_sensors_show
, NULL
);
162 static const struct file_operations ppc_rtas_sensors_operations
= {
163 .open
= sensors_open
,
166 .release
= single_release
,
169 static int poweron_open(struct inode
*inode
, struct file
*file
)
171 return single_open(file
, ppc_rtas_poweron_show
, NULL
);
174 static const struct file_operations ppc_rtas_poweron_operations
= {
175 .open
= poweron_open
,
178 .write
= ppc_rtas_poweron_write
,
179 .release
= single_release
,
182 static int progress_open(struct inode
*inode
, struct file
*file
)
184 return single_open(file
, ppc_rtas_progress_show
, NULL
);
187 static const struct file_operations ppc_rtas_progress_operations
= {
188 .open
= progress_open
,
191 .write
= ppc_rtas_progress_write
,
192 .release
= single_release
,
195 static int clock_open(struct inode
*inode
, struct file
*file
)
197 return single_open(file
, ppc_rtas_clock_show
, NULL
);
200 static const struct file_operations ppc_rtas_clock_operations
= {
204 .write
= ppc_rtas_clock_write
,
205 .release
= single_release
,
208 static int tone_freq_open(struct inode
*inode
, struct file
*file
)
210 return single_open(file
, ppc_rtas_tone_freq_show
, NULL
);
213 static const struct file_operations ppc_rtas_tone_freq_operations
= {
214 .open
= tone_freq_open
,
217 .write
= ppc_rtas_tone_freq_write
,
218 .release
= single_release
,
221 static int tone_volume_open(struct inode
*inode
, struct file
*file
)
223 return single_open(file
, ppc_rtas_tone_volume_show
, NULL
);
226 static const struct file_operations ppc_rtas_tone_volume_operations
= {
227 .open
= tone_volume_open
,
230 .write
= ppc_rtas_tone_volume_write
,
231 .release
= single_release
,
234 static int rmo_buf_open(struct inode
*inode
, struct file
*file
)
236 return single_open(file
, ppc_rtas_rmo_buf_show
, NULL
);
239 static const struct file_operations ppc_rtas_rmo_buf_ops
= {
240 .open
= rmo_buf_open
,
243 .release
= single_release
,
246 static int ppc_rtas_find_all_sensors(void);
247 static void ppc_rtas_process_sensor(struct seq_file
*m
,
248 struct individual_sensor
*s
, int state
, int error
, const char *loc
);
249 static char *ppc_rtas_process_error(int error
);
250 static void get_location_code(struct seq_file
*m
,
251 struct individual_sensor
*s
, const char *loc
);
252 static void check_location_string(struct seq_file
*m
, const char *c
);
253 static void check_location(struct seq_file
*m
, const char *c
);
255 static int __init
proc_rtas_init(void)
257 if (!machine_is(pseries
))
260 rtas_node
= of_find_node_by_name(NULL
, "rtas");
261 if (rtas_node
== NULL
)
264 proc_create("powerpc/rtas/progress", 0644, NULL
,
265 &ppc_rtas_progress_operations
);
266 proc_create("powerpc/rtas/clock", 0644, NULL
,
267 &ppc_rtas_clock_operations
);
268 proc_create("powerpc/rtas/poweron", 0644, NULL
,
269 &ppc_rtas_poweron_operations
);
270 proc_create("powerpc/rtas/sensors", 0444, NULL
,
271 &ppc_rtas_sensors_operations
);
272 proc_create("powerpc/rtas/frequency", 0644, NULL
,
273 &ppc_rtas_tone_freq_operations
);
274 proc_create("powerpc/rtas/volume", 0644, NULL
,
275 &ppc_rtas_tone_volume_operations
);
276 proc_create("powerpc/rtas/rmo_buffer", 0400, NULL
,
277 &ppc_rtas_rmo_buf_ops
);
281 __initcall(proc_rtas_init
);
283 static int parse_number(const char __user
*p
, size_t count
, unsigned long *val
)
291 if (copy_from_user(buf
, p
, count
))
296 *val
= simple_strtoul(buf
, &end
, 10);
297 if (*end
&& *end
!= '\n')
303 /* ****************************************************************** */
305 /* ****************************************************************** */
306 static ssize_t
ppc_rtas_poweron_write(struct file
*file
,
307 const char __user
*buf
, size_t count
, loff_t
*ppos
)
310 unsigned long nowtime
;
311 int error
= parse_number(buf
, count
, &nowtime
);
315 power_on_time
= nowtime
; /* save the time */
319 error
= rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL
,
320 tm
.tm_year
, tm
.tm_mon
, tm
.tm_mday
,
321 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, 0 /* nano */);
323 printk(KERN_WARNING
"error: setting poweron time returned: %s\n",
324 ppc_rtas_process_error(error
));
327 /* ****************************************************************** */
328 static int ppc_rtas_poweron_show(struct seq_file
*m
, void *v
)
330 if (power_on_time
== 0)
331 seq_printf(m
, "Power on time not set\n");
333 seq_printf(m
, "%lu\n",power_on_time
);
337 /* ****************************************************************** */
339 /* ****************************************************************** */
340 static ssize_t
ppc_rtas_progress_write(struct file
*file
,
341 const char __user
*buf
, size_t count
, loff_t
*ppos
)
345 if (count
>= MAX_LINELENGTH
)
346 count
= MAX_LINELENGTH
-1;
347 if (copy_from_user(progress_led
, buf
, count
)) { /* save the string */
350 progress_led
[count
] = 0;
352 /* Lets see if the user passed hexdigits */
353 hex
= simple_strtoul(progress_led
, NULL
, 10);
355 rtas_progress ((char *)progress_led
, hex
);
359 /* rtas_progress(" ", 0xffff);*/
361 /* ****************************************************************** */
362 static int ppc_rtas_progress_show(struct seq_file
*m
, void *v
)
365 seq_printf(m
, "%s\n", progress_led
);
369 /* ****************************************************************** */
371 /* ****************************************************************** */
372 static ssize_t
ppc_rtas_clock_write(struct file
*file
,
373 const char __user
*buf
, size_t count
, loff_t
*ppos
)
376 unsigned long nowtime
;
377 int error
= parse_number(buf
, count
, &nowtime
);
382 error
= rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL
,
383 tm
.tm_year
, tm
.tm_mon
, tm
.tm_mday
,
384 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, 0);
386 printk(KERN_WARNING
"error: setting the clock returned: %s\n",
387 ppc_rtas_process_error(error
));
390 /* ****************************************************************** */
391 static int ppc_rtas_clock_show(struct seq_file
*m
, void *v
)
394 int error
= rtas_call(rtas_token("get-time-of-day"), 0, 8, ret
);
397 printk(KERN_WARNING
"error: reading the clock returned: %s\n",
398 ppc_rtas_process_error(error
));
401 unsigned int year
, mon
, day
, hour
, min
, sec
;
402 year
= ret
[0]; mon
= ret
[1]; day
= ret
[2];
403 hour
= ret
[3]; min
= ret
[4]; sec
= ret
[5];
404 seq_printf(m
, "%lu\n",
405 mktime(year
, mon
, day
, hour
, min
, sec
));
410 /* ****************************************************************** */
412 /* ****************************************************************** */
413 static int ppc_rtas_sensors_show(struct seq_file
*m
, void *v
)
417 int get_sensor_state
= rtas_token("get-sensor-state");
419 seq_printf(m
, "RTAS (RunTime Abstraction Services) Sensor Information\n");
420 seq_printf(m
, "Sensor\t\tValue\t\tCondition\tLocation\n");
421 seq_printf(m
, "********************************************************\n");
423 if (ppc_rtas_find_all_sensors() != 0) {
424 seq_printf(m
, "\nNo sensors are available\n");
428 for (i
=0; i
<sensors
.quant
; i
++) {
429 struct individual_sensor
*p
= &sensors
.sensor
[i
];
434 sprintf (rstr
, SENSOR_PREFIX
"%04d", p
->token
);
435 loc
= of_get_property(rtas_node
, rstr
, &llen
);
437 /* A sensor may have multiple instances */
438 for (j
= 0, offs
= 0; j
<= p
->quant
; j
++) {
439 error
= rtas_call(get_sensor_state
, 2, 2, &state
,
442 ppc_rtas_process_sensor(m
, p
, state
, error
, loc
);
445 offs
+= strlen(loc
) + 1;
446 loc
+= strlen(loc
) + 1;
455 /* ****************************************************************** */
457 static int ppc_rtas_find_all_sensors(void)
459 const unsigned int *utmp
;
462 utmp
= of_get_property(rtas_node
, "rtas-sensors", &len
);
464 printk (KERN_ERR
"error: could not get rtas-sensors\n");
468 sensors
.quant
= len
/ 8; /* int + int */
470 for (i
=0; i
<sensors
.quant
; i
++) {
471 sensors
.sensor
[i
].token
= *utmp
++;
472 sensors
.sensor
[i
].quant
= *utmp
++;
477 /* ****************************************************************** */
479 * Builds a string of what rtas returned
481 static char *ppc_rtas_process_error(int error
)
484 case SENSOR_CRITICAL_HIGH
:
485 return "(critical high)";
486 case SENSOR_WARNING_HIGH
:
487 return "(warning high)";
490 case SENSOR_WARNING_LOW
:
491 return "(warning low)";
492 case SENSOR_CRITICAL_LOW
:
493 return "(critical low)";
496 case SENSOR_HW_ERROR
:
497 return "(hardware error)";
500 case SENSOR_NOT_EXIST
:
501 return "(non existent)";
502 case SENSOR_DR_ENTITY
:
503 return "(dr entity removed)";
509 /* ****************************************************************** */
511 * Builds a string out of what the sensor said
514 static void ppc_rtas_process_sensor(struct seq_file
*m
,
515 struct individual_sensor
*s
, int state
, int error
, const char *loc
)
517 /* Defined return vales */
518 const char * key_switch
[] = { "Off\t", "Normal\t", "Secure\t",
520 const char * enclosure_switch
[] = { "Closed", "Open" };
521 const char * lid_status
[] = { " ", "Open", "Closed" };
522 const char * power_source
[] = { "AC\t", "Battery",
524 const char * battery_remaining
[] = { "Very Low", "Low", "Mid", "High" };
525 const char * epow_sensor
[] = {
526 "EPOW Reset", "Cooling warning", "Power warning",
527 "System shutdown", "System halt", "EPOW main enclosure",
529 const char * battery_cyclestate
[] = { "None", "In progress",
531 const char * battery_charging
[] = { "Charging", "Discharching",
533 const char * ibm_drconnector
[] = { "Empty", "Present", "Unusable",
536 int have_strings
= 0;
541 /* What kind of sensor do we have here? */
545 seq_printf(m
, "Key switch:\t");
546 num_states
= sizeof(key_switch
) / sizeof(char *);
547 if (state
< num_states
) {
548 seq_printf(m
, "%s\t", key_switch
[state
]);
552 case ENCLOSURE_SWITCH
:
553 seq_printf(m
, "Enclosure switch:\t");
554 num_states
= sizeof(enclosure_switch
) / sizeof(char *);
555 if (state
< num_states
) {
556 seq_printf(m
, "%s\t",
557 enclosure_switch
[state
]);
562 seq_printf(m
, "Temp. (C/F):\t");
566 seq_printf(m
, "Lid status:\t");
567 num_states
= sizeof(lid_status
) / sizeof(char *);
568 if (state
< num_states
) {
569 seq_printf(m
, "%s\t", lid_status
[state
]);
574 seq_printf(m
, "Power source:\t");
575 num_states
= sizeof(power_source
) / sizeof(char *);
576 if (state
< num_states
) {
577 seq_printf(m
, "%s\t",
578 power_source
[state
]);
582 case BATTERY_VOLTAGE
:
583 seq_printf(m
, "Battery voltage:\t");
585 case BATTERY_REMAINING
:
586 seq_printf(m
, "Battery remaining:\t");
587 num_states
= sizeof(battery_remaining
) / sizeof(char *);
588 if (state
< num_states
)
590 seq_printf(m
, "%s\t",
591 battery_remaining
[state
]);
595 case BATTERY_PERCENTAGE
:
596 seq_printf(m
, "Battery percentage:\t");
599 seq_printf(m
, "EPOW Sensor:\t");
600 num_states
= sizeof(epow_sensor
) / sizeof(char *);
601 if (state
< num_states
) {
602 seq_printf(m
, "%s\t", epow_sensor
[state
]);
606 case BATTERY_CYCLESTATE
:
607 seq_printf(m
, "Battery cyclestate:\t");
608 num_states
= sizeof(battery_cyclestate
) /
610 if (state
< num_states
) {
611 seq_printf(m
, "%s\t",
612 battery_cyclestate
[state
]);
616 case BATTERY_CHARGING
:
617 seq_printf(m
, "Battery Charging:\t");
618 num_states
= sizeof(battery_charging
) / sizeof(char *);
619 if (state
< num_states
) {
620 seq_printf(m
, "%s\t",
621 battery_charging
[state
]);
625 case IBM_SURVEILLANCE
:
626 seq_printf(m
, "Surveillance:\t");
629 seq_printf(m
, "Fan (rpm):\t");
632 seq_printf(m
, "Voltage (mv):\t");
634 case IBM_DRCONNECTOR
:
635 seq_printf(m
, "DR connector:\t");
636 num_states
= sizeof(ibm_drconnector
) / sizeof(char *);
637 if (state
< num_states
) {
638 seq_printf(m
, "%s\t",
639 ibm_drconnector
[state
]);
643 case IBM_POWERSUPPLY
:
644 seq_printf(m
, "Powersupply:\t");
647 seq_printf(m
, "Unknown sensor (type %d), ignoring it\n",
653 if (have_strings
== 0) {
655 seq_printf(m
, "%4d /%4d\t", state
, cel_to_fahr(state
));
657 seq_printf(m
, "%10d\t", state
);
660 seq_printf(m
, "%s\t", ppc_rtas_process_error(error
));
661 get_location_code(m
, s
, loc
);
665 /* ****************************************************************** */
667 static void check_location(struct seq_file
*m
, const char *c
)
671 seq_printf(m
, "Planar #%c", c
[1]);
674 seq_printf(m
, "CPU #%c", c
[1]);
677 seq_printf(m
, "Fan #%c", c
[1]);
679 case LOC_RACKMOUNTED
:
680 seq_printf(m
, "Rack #%c", c
[1]);
683 seq_printf(m
, "Voltage #%c", c
[1]);
686 seq_printf(m
, "LCD #%c", c
[1]);
689 seq_printf(m
, "- %c", c
[1]);
692 seq_printf(m
, "Unknown location");
698 /* ****************************************************************** */
701 * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
702 * the '.' may be an abbreviation
704 static void check_location_string(struct seq_file
*m
, const char *c
)
707 if (isalpha(*c
) || *c
== '.')
708 check_location(m
, c
);
709 else if (*c
== '/' || *c
== '-')
710 seq_printf(m
, " at ");
716 /* ****************************************************************** */
718 static void get_location_code(struct seq_file
*m
, struct individual_sensor
*s
,
722 seq_printf(m
, "---");/* does not have a location */
724 check_location_string(m
, loc
);
728 /* ****************************************************************** */
729 /* INDICATORS - Tone Frequency */
730 /* ****************************************************************** */
731 static ssize_t
ppc_rtas_tone_freq_write(struct file
*file
,
732 const char __user
*buf
, size_t count
, loff_t
*ppos
)
735 int error
= parse_number(buf
, count
, &freq
);
739 rtas_tone_frequency
= freq
; /* save it for later */
740 error
= rtas_call(rtas_token("set-indicator"), 3, 1, NULL
,
741 TONE_FREQUENCY
, 0, freq
);
743 printk(KERN_WARNING
"error: setting tone frequency returned: %s\n",
744 ppc_rtas_process_error(error
));
747 /* ****************************************************************** */
748 static int ppc_rtas_tone_freq_show(struct seq_file
*m
, void *v
)
750 seq_printf(m
, "%lu\n", rtas_tone_frequency
);
753 /* ****************************************************************** */
754 /* INDICATORS - Tone Volume */
755 /* ****************************************************************** */
756 static ssize_t
ppc_rtas_tone_volume_write(struct file
*file
,
757 const char __user
*buf
, size_t count
, loff_t
*ppos
)
759 unsigned long volume
;
760 int error
= parse_number(buf
, count
, &volume
);
767 rtas_tone_volume
= volume
; /* save it for later */
768 error
= rtas_call(rtas_token("set-indicator"), 3, 1, NULL
,
769 TONE_VOLUME
, 0, volume
);
771 printk(KERN_WARNING
"error: setting tone volume returned: %s\n",
772 ppc_rtas_process_error(error
));
775 /* ****************************************************************** */
776 static int ppc_rtas_tone_volume_show(struct seq_file
*m
, void *v
)
778 seq_printf(m
, "%lu\n", rtas_tone_volume
);
782 #define RMO_READ_BUF_MAX 30
784 /* RTAS Userspace access */
785 static int ppc_rtas_rmo_buf_show(struct seq_file
*m
, void *v
)
787 seq_printf(m
, "%016lx %x\n", rtas_rmo_buf
, RTAS_RMOBUF_MAX
);