xref: /linux/tools/testing/selftests/powerpc/papr_sysparm/papr_sysparm.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <sys/ioctl.h>
6 #include <unistd.h>
7 #include <asm/papr-sysparm.h>
8 
9 #include "utils.h"
10 
11 #define DEVPATH "/dev/papr-sysparm"
12 
open_close(void)13 static int open_close(void)
14 {
15 	const int devfd = open(DEVPATH, O_RDONLY);
16 
17 	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
18 		    DEVPATH " not present");
19 
20 	FAIL_IF(devfd < 0);
21 	FAIL_IF(close(devfd) != 0);
22 
23 	return 0;
24 }
25 
get_splpar(void)26 static int get_splpar(void)
27 {
28 	struct papr_sysparm_io_block sp = {
29 		.parameter = 20, // SPLPAR characteristics
30 	};
31 	const int devfd = open(DEVPATH, O_RDONLY);
32 
33 	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
34 		    DEVPATH " not present");
35 
36 	FAIL_IF(devfd < 0);
37 	FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_GET, &sp) != 0);
38 	FAIL_IF(sp.length == 0);
39 	FAIL_IF(sp.length > sizeof(sp.data));
40 	FAIL_IF(close(devfd) != 0);
41 
42 	return 0;
43 }
44 
get_bad_parameter(void)45 static int get_bad_parameter(void)
46 {
47 	struct papr_sysparm_io_block sp = {
48 		.parameter = UINT32_MAX, // there are only ~60 specified parameters
49 	};
50 	const int devfd = open(DEVPATH, O_RDONLY);
51 
52 	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
53 		    DEVPATH " not present");
54 
55 	FAIL_IF(devfd < 0);
56 
57 	// Ensure expected error
58 	FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_GET, &sp) != -1);
59 	FAIL_IF(errno != EOPNOTSUPP);
60 
61 	// Ensure the buffer is unchanged
62 	FAIL_IF(sp.length != 0);
63 	for (size_t i = 0; i < ARRAY_SIZE(sp.data); ++i)
64 		FAIL_IF(sp.data[i] != 0);
65 
66 	FAIL_IF(close(devfd) != 0);
67 
68 	return 0;
69 }
70 
check_efault_common(unsigned long cmd)71 static int check_efault_common(unsigned long cmd)
72 {
73 	const int devfd = open(DEVPATH, O_RDWR);
74 
75 	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
76 		    DEVPATH " not present");
77 
78 	FAIL_IF(devfd < 0);
79 
80 	// Ensure expected error
81 	FAIL_IF(ioctl(devfd, cmd, NULL) != -1);
82 	FAIL_IF(errno != EFAULT);
83 
84 	FAIL_IF(close(devfd) != 0);
85 
86 	return 0;
87 }
88 
check_efault_get(void)89 static int check_efault_get(void)
90 {
91 	return check_efault_common(PAPR_SYSPARM_IOC_GET);
92 }
93 
check_efault_set(void)94 static int check_efault_set(void)
95 {
96 	return check_efault_common(PAPR_SYSPARM_IOC_SET);
97 }
98 
set_hmc0(void)99 static int set_hmc0(void)
100 {
101 	struct papr_sysparm_io_block sp = {
102 		.parameter = 0, // HMC0, not a settable parameter
103 	};
104 	const int devfd = open(DEVPATH, O_RDWR);
105 
106 	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
107 		    DEVPATH " not present");
108 
109 	FAIL_IF(devfd < 0);
110 
111 	// Ensure expected error
112 	FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_SET, &sp) != -1);
113 	SKIP_IF_MSG(errno == EOPNOTSUPP, "operation not supported");
114 	FAIL_IF(errno != EPERM);
115 
116 	FAIL_IF(close(devfd) != 0);
117 
118 	return 0;
119 }
120 
set_with_ro_fd(void)121 static int set_with_ro_fd(void)
122 {
123 	struct papr_sysparm_io_block sp = {
124 		.parameter = 0, // HMC0, not a settable parameter.
125 	};
126 	const int devfd = open(DEVPATH, O_RDONLY);
127 
128 	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
129 		    DEVPATH " not present");
130 
131 	FAIL_IF(devfd < 0);
132 
133 	// Ensure expected error
134 	FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_SET, &sp) != -1);
135 	SKIP_IF_MSG(errno == EOPNOTSUPP, "operation not supported");
136 
137 	// HMC0 isn't a settable parameter and we would normally
138 	// expect to get EPERM on attempts to modify it. However, when
139 	// the file is open read-only, we expect the driver to prevent
140 	// the attempt with a distinct error.
141 	FAIL_IF(errno != EBADF);
142 
143 	FAIL_IF(close(devfd) != 0);
144 
145 	return 0;
146 }
147 
148 struct sysparm_test {
149 	int (*function)(void);
150 	const char *description;
151 };
152 
153 static const struct sysparm_test sysparm_tests[] = {
154 	{
155 		.function = open_close,
156 		.description = "open and close " DEVPATH " without issuing commands",
157 	},
158 	{
159 		.function = get_splpar,
160 		.description = "retrieve SPLPAR characteristics",
161 	},
162 	{
163 		.function = get_bad_parameter,
164 		.description = "verify EOPNOTSUPP for known-bad parameter",
165 	},
166 	{
167 		.function = check_efault_get,
168 		.description = "PAPR_SYSPARM_IOC_GET returns EFAULT on bad address",
169 	},
170 	{
171 		.function = check_efault_set,
172 		.description = "PAPR_SYSPARM_IOC_SET returns EFAULT on bad address",
173 	},
174 	{
175 		.function = set_hmc0,
176 		.description = "ensure EPERM on attempt to update HMC0",
177 	},
178 	{
179 		.function = set_with_ro_fd,
180 		.description = "PAPR_IOC_SYSPARM_SET returns EACCES on read-only fd",
181 	},
182 };
183 
main(void)184 int main(void)
185 {
186 	size_t fails = 0;
187 
188 	for (size_t i = 0; i < ARRAY_SIZE(sysparm_tests); ++i) {
189 		const struct sysparm_test *t = &sysparm_tests[i];
190 
191 		if (test_harness(t->function, t->description))
192 			++fails;
193 	}
194 
195 	return fails == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
196 }
197