1 /*
2  * Copyright © 2016 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "igt.h"
25 #include "drmtest.h"
26 #include <errno.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31 
32 struct additional_test {
33 	const char *name;
34 	uint32_t obj_type;
35 	void (*prop_test)(int fd, uint32_t id, uint32_t type, drmModePropertyPtr prop,
36 			  uint32_t prop_id, uint64_t prop_value, bool atomic);
37 };
38 
prepare_pipe(igt_display_t * display,enum pipe pipe,igt_output_t * output,struct igt_fb * fb)39 static void prepare_pipe(igt_display_t *display, enum pipe pipe, igt_output_t *output, struct igt_fb *fb)
40 {
41 	drmModeModeInfo *mode = igt_output_get_mode(output);
42 
43 	igt_create_pattern_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
44 			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, fb);
45 
46 	igt_output_set_pipe(output, pipe);
47 
48 	igt_plane_set_fb(igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY), fb);
49 
50 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
51 }
52 
cleanup_pipe(igt_display_t * display,enum pipe pipe,igt_output_t * output,struct igt_fb * fb)53 static void cleanup_pipe(igt_display_t *display, enum pipe pipe, igt_output_t *output, struct igt_fb *fb)
54 {
55 	igt_plane_t *plane;
56 
57 	for_each_plane_on_pipe(display, pipe, plane)
58 		igt_plane_set_fb(plane, NULL);
59 
60 	igt_output_set_pipe(output, PIPE_NONE);
61 
62 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
63 
64 	igt_remove_fb(display->drm_fd, fb);
65 }
66 
ignore_property(uint32_t obj_type,uint32_t prop_flags,const char * name,bool atomic)67 static bool ignore_property(uint32_t obj_type, uint32_t prop_flags,
68 			    const char *name, bool atomic)
69 {
70 	if (prop_flags & DRM_MODE_PROP_IMMUTABLE)
71 		return true;
72 
73 	switch (obj_type) {
74 	case DRM_MODE_OBJECT_CONNECTOR:
75 		if (atomic && !strcmp(name, "DPMS"))
76 			return true;
77 		break;
78 	default:
79 		break;
80 	}
81 
82 	return false;
83 }
84 
max_bpc_prop_test(int fd,uint32_t id,uint32_t type,drmModePropertyPtr prop,uint32_t prop_id,uint64_t prop_value,bool atomic)85 static void max_bpc_prop_test(int fd, uint32_t id, uint32_t type, drmModePropertyPtr prop,
86 			      uint32_t prop_id, uint64_t prop_value, bool atomic)
87 {
88 	drmModeAtomicReqPtr req = NULL;
89 	int i, ret;
90 
91 	if (atomic)
92 		req = drmModeAtomicAlloc();
93 
94 	for (i = prop->values[0]; i <= prop->values[1]; i++) {
95 		if (!atomic) {
96 			ret = drmModeObjectSetProperty(fd, id, type, prop_id, i);
97 
98 			igt_assert_eq(ret, 0);
99 		} else {
100 			ret = drmModeAtomicAddProperty(req, id, prop_id, i);
101 			igt_assert(ret >= 0);
102 
103 			ret = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
104 			igt_assert_eq(ret, 0);
105 		}
106 	}
107 
108 	if (atomic)
109 		drmModeAtomicFree(req);
110 }
111 
112 static const struct additional_test property_functional_test[] = {
113 									{"max bpc", DRM_MODE_OBJECT_CONNECTOR,
114 									 max_bpc_prop_test},
115 								 };
116 
has_additional_test_lookup(uint32_t obj_type,const char * name,bool atomic,int * index)117 static bool has_additional_test_lookup(uint32_t obj_type, const char *name,
118 				bool atomic, int *index)
119 {
120 	int i;
121 
122 	for (i = 0; i < ARRAY_SIZE(property_functional_test); i++)
123 		if (property_functional_test[i].obj_type == obj_type &&
124 		    !strcmp(name, property_functional_test[i].name)) {
125 			*index = i;
126 			return true;
127 		}
128 
129 	return false;
130 }
test_properties(int fd,uint32_t type,uint32_t id,bool atomic)131 static void test_properties(int fd, uint32_t type, uint32_t id, bool atomic)
132 {
133 	drmModeObjectPropertiesPtr props =
134 		drmModeObjectGetProperties(fd, id, type);
135 	int i, j, ret;
136 	drmModeAtomicReqPtr req = NULL;
137 
138 	igt_assert(props);
139 
140 	if (atomic)
141 		req = drmModeAtomicAlloc();
142 
143 	for (i = 0; i < props->count_props; i++) {
144 		uint32_t prop_id = props->props[i];
145 		uint64_t prop_value = props->prop_values[i];
146 		drmModePropertyPtr prop = drmModeGetProperty(fd, prop_id);
147 
148 		igt_assert(prop);
149 
150 		if (ignore_property(type, prop->flags, prop->name, atomic)) {
151 			igt_debug("Ignoring property \"%s\"\n", prop->name);
152 
153 			continue;
154 		}
155 
156 		igt_debug("Testing property \"%s\"\n", prop->name);
157 
158 		if (!atomic) {
159 			ret = drmModeObjectSetProperty(fd, id, type, prop_id, prop_value);
160 
161 			igt_assert_eq(ret, 0);
162 		} else {
163 			ret = drmModeAtomicAddProperty(req, id, prop_id, prop_value);
164 			igt_assert(ret >= 0);
165 
166 			ret = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
167 			igt_assert_eq(ret, 0);
168 		}
169 
170 		if (has_additional_test_lookup(type, prop->name, atomic, &j))
171 			property_functional_test[j].prop_test(fd, id, type, prop, prop_id, prop_value, atomic);
172 
173 		drmModeFreeProperty(prop);
174 	}
175 
176 	drmModeFreeObjectProperties(props);
177 
178 	if (atomic) {
179 		ret = drmModeAtomicCommit(fd, req, 0, NULL);
180 		igt_assert_eq(ret, 0);
181 
182 		drmModeAtomicFree(req);
183 	}
184 }
185 
run_plane_property_tests(igt_display_t * display,enum pipe pipe,igt_output_t * output,bool atomic)186 static void run_plane_property_tests(igt_display_t *display, enum pipe pipe, igt_output_t *output, bool atomic)
187 {
188 	struct igt_fb fb;
189 	igt_plane_t *plane;
190 
191 	prepare_pipe(display, pipe, output, &fb);
192 
193 	for_each_plane_on_pipe(display, pipe, plane) {
194 		igt_info("Testing plane properties on %s.#%d-%s (output: %s)\n",
195 			 kmstest_pipe_name(pipe), plane->index, kmstest_plane_type_name(plane->type), output->name);
196 
197 		test_properties(display->drm_fd, DRM_MODE_OBJECT_PLANE, plane->drm_plane->plane_id, atomic);
198 	}
199 
200 	cleanup_pipe(display, pipe, output, &fb);
201 }
202 
run_crtc_property_tests(igt_display_t * display,enum pipe pipe,igt_output_t * output,bool atomic)203 static void run_crtc_property_tests(igt_display_t *display, enum pipe pipe, igt_output_t *output, bool atomic)
204 {
205 	struct igt_fb fb;
206 
207 	prepare_pipe(display, pipe, output, &fb);
208 
209 	igt_info("Testing crtc properties on %s (output: %s)\n", kmstest_pipe_name(pipe), output->name);
210 
211 	test_properties(display->drm_fd, DRM_MODE_OBJECT_CRTC, display->pipes[pipe].crtc_id, atomic);
212 
213 	cleanup_pipe(display, pipe, output, &fb);
214 }
215 
run_connector_property_tests(igt_display_t * display,enum pipe pipe,igt_output_t * output,bool atomic)216 static void run_connector_property_tests(igt_display_t *display, enum pipe pipe, igt_output_t *output, bool atomic)
217 {
218 	struct igt_fb fb;
219 
220 	if (pipe != PIPE_NONE)
221 		prepare_pipe(display, pipe, output, &fb);
222 
223 	igt_info("Testing connector properties on output %s (pipe: %s)\n", output->name, kmstest_pipe_name(pipe));
224 
225 	test_properties(display->drm_fd, DRM_MODE_OBJECT_CONNECTOR, output->id, atomic);
226 
227 	if (pipe != PIPE_NONE)
228 		cleanup_pipe(display, pipe, output, &fb);
229 }
230 
plane_properties(igt_display_t * display,bool atomic)231 static void plane_properties(igt_display_t *display, bool atomic)
232 {
233 	bool found_any = false, found;
234 	igt_output_t *output;
235 	enum pipe pipe;
236 
237 	if (atomic)
238 		igt_skip_on(!display->is_atomic);
239 
240 	for_each_pipe(display, pipe) {
241 		found = false;
242 
243 		for_each_valid_output_on_pipe(display, pipe, output) {
244 			found_any = found = true;
245 
246 			run_plane_property_tests(display, pipe, output, atomic);
247 			break;
248 		}
249 	}
250 
251 	igt_skip_on(!found_any);
252 }
253 
crtc_properties(igt_display_t * display,bool atomic)254 static void crtc_properties(igt_display_t *display, bool atomic)
255 {
256 	bool found_any_valid_pipe = false, found;
257 	enum pipe pipe;
258 	igt_output_t *output;
259 
260 	if (atomic)
261 		igt_skip_on(!display->is_atomic);
262 
263 	for_each_pipe(display, pipe) {
264 		found = false;
265 
266 		for_each_valid_output_on_pipe(display, pipe, output) {
267 			found_any_valid_pipe = found = true;
268 
269 			run_crtc_property_tests(display, pipe, output, atomic);
270 			break;
271 		}
272 	}
273 
274 	igt_skip_on(!found_any_valid_pipe);
275 }
276 
connector_properties(igt_display_t * display,bool atomic)277 static void connector_properties(igt_display_t *display, bool atomic)
278 {
279 	int i;
280 	enum pipe pipe;
281 	igt_output_t *output;
282 
283 	if (atomic)
284 		igt_skip_on(!display->is_atomic);
285 
286 	for_each_connected_output(display, output) {
287 		bool found = false;
288 
289 		for_each_pipe(display, pipe) {
290 			if (!igt_pipe_connector_valid(pipe, output))
291 				continue;
292 
293 			found = true;
294 			run_connector_property_tests(display, pipe, output, atomic);
295 			break;
296 		}
297 
298 		igt_assert_f(found, "Connected output should have at least 1 valid crtc\n");
299 	}
300 
301 	for (i = 0; i < display->n_outputs; i++)
302 		if (!igt_output_is_connected(&display->outputs[i]))
303 			run_connector_property_tests(display, PIPE_NONE, &display->outputs[i], atomic);
304 }
305 
test_invalid_properties(int fd,uint32_t id1,uint32_t type1,uint32_t id2,uint32_t type2,bool atomic)306 static void test_invalid_properties(int fd,
307 				    uint32_t id1,
308 				    uint32_t type1,
309 				    uint32_t id2,
310 				    uint32_t type2,
311 				    bool atomic)
312 {
313 	drmModeObjectPropertiesPtr props1 =
314 		drmModeObjectGetProperties(fd, id1, type1);
315 	drmModeObjectPropertiesPtr props2 =
316 		drmModeObjectGetProperties(fd, id2, type2);
317 
318 	int i, j, ret;
319 	drmModeAtomicReqPtr req;
320 
321 	igt_assert(props1 && props2);
322 
323 	for (i = 0; i < props2->count_props; i++) {
324 		uint32_t prop_id = props2->props[i];
325 		uint64_t prop_value = props2->prop_values[i];
326 		drmModePropertyPtr prop = drmModeGetProperty(fd, prop_id);
327 		bool found = false;
328 
329 		igt_assert(prop);
330 
331 		for (j = 0; j < props1->count_props; j++)
332 			if (props1->props[j] == prop_id) {
333 				found = true;
334 				break;
335 			}
336 
337 		if (found)
338 			continue;
339 
340 		igt_debug("Testing property \"%s\" on [%x:%u]\n", prop->name, type1, id1);
341 
342 		if (!atomic) {
343 			ret = drmModeObjectSetProperty(fd, id1, type1, prop_id, prop_value);
344 
345 			igt_assert_eq(ret, -EINVAL);
346 		} else {
347 			req = drmModeAtomicAlloc();
348 			igt_assert(req);
349 
350 			ret = drmModeAtomicAddProperty(req, id1, prop_id, prop_value);
351 			igt_assert(ret >= 0);
352 
353 			ret = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
354 			igt_assert_eq(ret, -ENOENT);
355 
356 			drmModeAtomicFree(req);
357 		}
358 
359 		drmModeFreeProperty(prop);
360 	}
361 
362 	drmModeFreeObjectProperties(props1);
363 	drmModeFreeObjectProperties(props2);
364 }
test_object_invalid_properties(igt_display_t * display,uint32_t id,uint32_t type,bool atomic)365 static void test_object_invalid_properties(igt_display_t *display,
366 					   uint32_t id, uint32_t type, bool atomic)
367 {
368 	igt_output_t *output;
369 	igt_plane_t *plane;
370 	enum pipe pipe;
371 	int i;
372 
373 	for_each_pipe(display, pipe)
374 		test_invalid_properties(display->drm_fd, id, type, display->pipes[pipe].crtc_id, DRM_MODE_OBJECT_CRTC, atomic);
375 
376 	for_each_pipe(display, pipe)
377 		for_each_plane_on_pipe(display, pipe, plane)
378 			test_invalid_properties(display->drm_fd, id, type, plane->drm_plane->plane_id, DRM_MODE_OBJECT_PLANE, atomic);
379 
380 	for (i = 0, output = &display->outputs[0]; i < display->n_outputs; output = &display->outputs[++i])
381 		test_invalid_properties(display->drm_fd, id, type, output->id, DRM_MODE_OBJECT_CONNECTOR, atomic);
382 }
383 
validate_range_prop(const struct drm_mode_get_property * prop,uint64_t value)384 static void validate_range_prop(const struct drm_mode_get_property *prop,
385 				uint64_t value)
386 {
387 	const uint64_t *values = from_user_pointer(prop->values_ptr);
388 	bool is_unsigned = prop->flags & DRM_MODE_PROP_RANGE;
389 	bool immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
390 
391 	igt_assert_eq(prop->count_values, 2);
392 	igt_assert_eq(prop->count_enum_blobs, 0);
393 	igt_assert(values[0] != values[1] || immutable);
394 
395 	if (is_unsigned) {
396 		igt_assert_lte_u64(values[0], values[1]);
397 		igt_assert_lte_u64(values[0], value);
398 		igt_assert_lte_u64(value, values[1]);
399 	} else {
400 		igt_assert_lte_s64(values[0], values[1]);
401 		igt_assert_lte_s64(values[0], value);
402 		igt_assert_lte_s64(value, values[1]);
403 	}
404 
405 }
406 
validate_enums(const struct drm_mode_get_property * prop)407 static void validate_enums(const struct drm_mode_get_property *prop)
408 {
409 	const uint64_t *values = from_user_pointer(prop->values_ptr);
410 	const struct drm_mode_property_enum *enums =
411 		from_user_pointer(prop->enum_blob_ptr);
412 
413 	for (int i = 0; i < prop->count_enum_blobs; i++) {
414 		int name_len = strnlen(enums[i].name,
415 				       sizeof(enums[i].name));
416 
417 		igt_assert_lte(1, name_len);
418 		igt_assert_lte(name_len, sizeof(enums[i].name) - 1);
419 
420 		/* no idea why we have this duplicated */
421 		igt_assert_eq_u64(values[i], enums[i].value);
422 	}
423 }
424 
validate_enum_prop(const struct drm_mode_get_property * prop,uint64_t value)425 static void validate_enum_prop(const struct drm_mode_get_property *prop,
426 			       uint64_t value)
427 {
428 	const uint64_t *values = from_user_pointer(prop->values_ptr);
429 	bool immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
430 	int i;
431 
432 	igt_assert_lte(1, prop->count_values);
433 	igt_assert_eq(prop->count_enum_blobs, prop->count_values);
434 	igt_assert(prop->count_values != 1 || immutable);
435 
436 	for (i = 0; i < prop->count_values; i++) {
437 		if (value == values[i])
438 			break;
439 	}
440 	igt_assert(i != prop->count_values);
441 
442 	validate_enums(prop);
443 }
444 
validate_bitmask_prop(const struct drm_mode_get_property * prop,uint64_t value)445 static void validate_bitmask_prop(const struct drm_mode_get_property *prop,
446 				  uint64_t value)
447 {
448 	const uint64_t *values = from_user_pointer(prop->values_ptr);
449 	bool immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
450 	uint64_t mask = 0;
451 
452 	igt_assert_lte(1, prop->count_values);
453 	igt_assert_eq(prop->count_enum_blobs, prop->count_values);
454 	igt_assert(prop->count_values != 1 || immutable);
455 
456 	for (int i = 0; i < prop->count_values; i++) {
457 		igt_assert_lte_u64(values[i], 63);
458 		mask |= 1ULL << values[i];
459 	}
460 
461 	igt_assert_eq_u64(value & ~mask, 0);
462 	igt_assert_neq_u64(value & mask, 0);
463 
464 	validate_enums(prop);
465 }
466 
validate_blob_prop(int fd,const struct drm_mode_get_property * prop,uint64_t value)467 static void validate_blob_prop(int fd,
468 			       const struct drm_mode_get_property *prop,
469 			       uint64_t value)
470 {
471 	struct drm_mode_get_blob blob;
472 
473 	/*
474 	 * Despite what libdrm makes you believe, we never supply
475 	 * additional information for BLOB properties, only for enums
476 	 * and bitmasks
477 	 */
478 	igt_assert_eq(prop->count_values, 0);
479 	igt_assert_eq(prop->count_enum_blobs, 0);
480 
481 	igt_assert_lte_u64(value, 0xffffffff);
482 
483 	/*
484 	 * Immutable blob properties can have value==0.
485 	 * Happens for example with the "EDID" property
486 	 * when there is nothing hooked up to the connector.
487 	 */
488 
489 	if (!value)
490 		return;
491 
492 	memset(&blob, 0, sizeof(blob));
493 	blob.blob_id = value;
494 
495 	do_ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob);
496 }
497 
validate_object_prop(int fd,const struct drm_mode_get_property * prop,uint64_t value)498 static void validate_object_prop(int fd,
499 				 const struct drm_mode_get_property *prop,
500 				 uint64_t value)
501 {
502 	const uint64_t *values = from_user_pointer(prop->values_ptr);
503 	bool immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
504 	struct drm_mode_crtc crtc;
505 	struct drm_mode_fb_cmd fb;
506 
507 	igt_assert_eq(prop->count_values, 1);
508 	igt_assert_eq(prop->count_enum_blobs, 0);
509 
510 	igt_assert_lte_u64(value, 0xffffffff);
511 	igt_assert(!immutable || value != 0);
512 
513 	switch (values[0]) {
514 	case DRM_MODE_OBJECT_CRTC:
515 		if (!value)
516 			break;
517 		memset(&crtc, 0, sizeof(crtc));
518 		crtc.crtc_id = value;
519 		do_ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc);
520 		break;
521 	case DRM_MODE_OBJECT_FB:
522 		if (!value)
523 			break;
524 		memset(&fb, 0, sizeof(fb));
525 		fb.fb_id = value;
526 		do_ioctl(fd, DRM_IOCTL_MODE_GETFB, &fb);
527 		break;
528 	default:
529 		/* These are the only types we have so far */
530 		igt_assert(0);
531 	}
532 }
533 
validate_property(int fd,const struct drm_mode_get_property * prop,uint64_t value,bool atomic)534 static void validate_property(int fd,
535 			      const struct drm_mode_get_property *prop,
536 			      uint64_t value, bool atomic)
537 {
538 	uint32_t flags = prop->flags;
539 	uint32_t legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
540 	uint32_t ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
541 
542 	igt_assert_eq((flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
543 				 DRM_MODE_PROP_EXTENDED_TYPE |
544 				 DRM_MODE_PROP_IMMUTABLE |
545 				 DRM_MODE_PROP_ATOMIC)), 0);
546 
547 	igt_assert(atomic ||
548 		   (flags & DRM_MODE_PROP_ATOMIC) == 0);
549 
550 	igt_assert_neq(!legacy_type, !ext_type);
551 
552 	igt_assert(legacy_type == 0 ||
553 		   is_power_of_two(legacy_type));
554 
555 	switch (legacy_type) {
556 	case DRM_MODE_PROP_RANGE:
557 		validate_range_prop(prop, value);
558 		break;
559 	case DRM_MODE_PROP_ENUM:
560 		validate_enum_prop(prop, value);
561 		break;
562 	case DRM_MODE_PROP_BITMASK:
563 		validate_bitmask_prop(prop, value);
564 		break;
565 	case DRM_MODE_PROP_BLOB:
566 		validate_blob_prop(fd, prop, value);
567 		break;
568 	default:
569 		igt_assert_eq(legacy_type, 0);
570 	}
571 
572 	switch (ext_type) {
573 	case DRM_MODE_PROP_OBJECT:
574 		validate_object_prop(fd, prop, value);
575 		break;
576 	case DRM_MODE_PROP_SIGNED_RANGE:
577 		validate_range_prop(prop, value);
578 		break;
579 	default:
580 		igt_assert_eq(ext_type, 0);
581 	}
582 }
583 
validate_prop(int fd,uint32_t prop_id,uint64_t value,bool atomic)584 static void validate_prop(int fd, uint32_t prop_id, uint64_t value, bool atomic)
585 {
586 	struct drm_mode_get_property prop;
587 	struct drm_mode_property_enum *enums = NULL;
588 	uint64_t *values = NULL;
589 
590 	memset(&prop, 0, sizeof(prop));
591 	prop.prop_id = prop_id;
592 
593 	do_ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop);
594 
595 	if (prop.count_values) {
596 		values = calloc(prop.count_values, sizeof(values[0]));
597 		igt_assert(values);
598 		memset(values, 0x5c, sizeof(values[0])*prop.count_values);
599 		prop.values_ptr = to_user_pointer(values);
600 	}
601 
602 	if (prop.count_enum_blobs) {
603 		enums = calloc(prop.count_enum_blobs, sizeof(enums[0]));
604 		memset(enums, 0x5c, sizeof(enums[0])*prop.count_enum_blobs);
605 		igt_assert(enums);
606 		prop.enum_blob_ptr = to_user_pointer(enums);
607 	}
608 
609 	do_ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop);
610 
611 	for (int i = 0; i < prop.count_values; i++)
612 		igt_assert_neq_u64(values[i], 0x5c5c5c5c5c5c5c5cULL);
613 
614 	for (int i = 0; i < prop.count_enum_blobs; i++)
615 		igt_assert_neq_u64(enums[i].value, 0x5c5c5c5c5c5c5c5cULL);
616 
617 	validate_property(fd, &prop, value, atomic);
618 
619 	free(values);
620 	free(enums);
621 }
622 
validate_props(int fd,uint32_t obj_type,uint32_t obj_id,bool atomic)623 static void validate_props(int fd, uint32_t obj_type, uint32_t obj_id, bool atomic)
624 {
625 	struct drm_mode_obj_get_properties properties;
626 	uint32_t *props = NULL;
627 	uint64_t *values = NULL;
628 	uint32_t count;
629 
630 	memset(&properties, 0, sizeof(properties));
631 	properties.obj_type = obj_type;
632 	properties.obj_id = obj_id;
633 
634 	do_ioctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties);
635 
636 	count = properties.count_props;
637 
638 	if (count) {
639 		props = calloc(count, sizeof(props[0]));
640 		memset(props, 0x5c, sizeof(props[0])*count);
641 		igt_assert(props);
642 		properties.props_ptr = to_user_pointer(props);
643 
644 		values = calloc(count, sizeof(values[0]));
645 		memset(values, 0x5c, sizeof(values[0])*count);
646 		igt_assert(values);
647 		properties.prop_values_ptr = to_user_pointer(values);
648 	}
649 
650 	do_ioctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties);
651 
652 	igt_assert(properties.count_props == count);
653 
654 	for (int i = 0; i < count; i++)
655 		validate_prop(fd, props[i], values[i], atomic);
656 
657 	free(values);
658 	free(props);
659 }
660 
expect_no_props(int fd,uint32_t obj_type,uint32_t obj_id)661 static void expect_no_props(int fd, uint32_t obj_type, uint32_t obj_id)
662 {
663 	struct drm_mode_obj_get_properties properties;
664 
665 	memset(&properties, 0, sizeof(properties));
666 	properties.obj_type = obj_type;
667 	properties.obj_id = obj_id;
668 
669 	igt_assert_neq(drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties), 0);
670 }
671 
get_prop_sanity(igt_display_t * display,bool atomic)672 static void get_prop_sanity(igt_display_t *display, bool atomic)
673 {
674 	int fd = display->drm_fd;
675 	drmModePlaneResPtr plane_res;
676 	drmModeResPtr res;
677 
678 	res = drmModeGetResources(fd);
679 	plane_res = drmModeGetPlaneResources(fd);
680 
681 	for (int i = 0; i < plane_res->count_planes; i++) {
682 		validate_props(fd, DRM_MODE_OBJECT_PLANE,
683 			       plane_res->planes[i], atomic);
684 	}
685 
686 	for (int i = 0; i < res->count_crtcs; i++) {
687 		validate_props(fd, DRM_MODE_OBJECT_CRTC,
688 			       res->crtcs[i], atomic);
689 	}
690 
691 	for (int i = 0; i < res->count_connectors; i++) {
692 		validate_props(fd, DRM_MODE_OBJECT_CONNECTOR,
693 			       res->connectors[i], atomic);
694 	}
695 
696 	for (int i = 0; i < res->count_encoders; i++) {
697 		expect_no_props(fd, DRM_MODE_OBJECT_ENCODER,
698 				res->encoders[i]);
699 	}
700 
701 	drmModeFreePlaneResources(plane_res);
702 	drmModeFreeResources(res);
703 }
704 
invalid_properties(igt_display_t * display,bool atomic)705 static void invalid_properties(igt_display_t *display, bool atomic)
706 {
707 	igt_output_t *output;
708 	igt_plane_t *plane;
709 	enum pipe pipe;
710 	int i;
711 
712 	if (atomic)
713 		igt_skip_on(!display->is_atomic);
714 
715 	for_each_pipe(display, pipe)
716 		test_object_invalid_properties(display, display->pipes[pipe].crtc_id, DRM_MODE_OBJECT_CRTC, atomic);
717 
718 	for_each_pipe(display, pipe)
719 		for_each_plane_on_pipe(display, pipe, plane)
720 			test_object_invalid_properties(display, plane->drm_plane->plane_id, DRM_MODE_OBJECT_PLANE, atomic);
721 
722 	for (i = 0, output = &display->outputs[0]; i < display->n_outputs; output = &display->outputs[++i])
723 		test_object_invalid_properties(display, output->id, DRM_MODE_OBJECT_CONNECTOR, atomic);
724 }
725 
726 igt_main
727 {
728 	igt_display_t display;
729 
730 	igt_skip_on_simulation();
731 
732 	igt_fixture {
733 		display.drm_fd = drm_open_driver_master(DRIVER_ANY);
734 
735 		kmstest_set_vt_graphics_mode();
736 
737 		igt_display_require(&display, display.drm_fd);
738 	}
739 
740 	igt_subtest("plane-properties-legacy")
741 		plane_properties(&display, false);
742 
743 	igt_subtest("plane-properties-atomic")
744 		plane_properties(&display, true);
745 
746 	igt_subtest("crtc-properties-legacy")
747 		crtc_properties(&display, false);
748 
749 	igt_subtest("crtc-properties-atomic")
750 		crtc_properties(&display, true);
751 
752 	igt_subtest("connector-properties-legacy")
753 		connector_properties(&display, false);
754 
755 	igt_subtest("connector-properties-atomic")
756 		connector_properties(&display, true);
757 
758 	igt_subtest("invalid-properties-legacy")
759 		invalid_properties(&display, false);
760 
761 	igt_subtest("invalid-properties-atomic")
762 		invalid_properties(&display, true);
763 
764 	igt_subtest("get_properties-sanity-atomic") {
765 		igt_skip_on(!display.is_atomic);
766 		get_prop_sanity(&display, true);
767 	}
768 
769 	igt_subtest("get_properties-sanity-non-atomic") {
770 		if (display.is_atomic)
771 			igt_assert_eq(drmSetClientCap(display.drm_fd, DRM_CLIENT_CAP_ATOMIC, 0), 0);
772 
773 		get_prop_sanity(&display, false);
774 
775 		if (display.is_atomic)
776 			igt_assert_eq(drmSetClientCap(display.drm_fd, DRM_CLIENT_CAP_ATOMIC, 1), 0);
777 	}
778 
779 	igt_fixture {
780 		igt_display_fini(&display);
781 	}
782 }
783