.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright © 2017 Keith Packard <keithp@keithp.com> |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License as published by |
---|
6 | | - * the Free Software Foundation, either version 2 of the License, or |
---|
7 | | - * (at your option) any later version. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope that it will be useful, but |
---|
10 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | | - * General Public License for more details. |
---|
13 | 4 | */ |
---|
| 5 | +#include <linux/file.h> |
---|
| 6 | +#include <linux/uaccess.h> |
---|
14 | 7 | |
---|
15 | | -#include <drm/drmP.h> |
---|
16 | | -#include "drm_internal.h" |
---|
17 | | -#include "drm_legacy.h" |
---|
18 | | -#include "drm_crtc_internal.h" |
---|
19 | | -#include <drm/drm_lease.h> |
---|
20 | 8 | #include <drm/drm_auth.h> |
---|
21 | 9 | #include <drm/drm_crtc_helper.h> |
---|
| 10 | +#include <drm/drm_drv.h> |
---|
| 11 | +#include <drm/drm_file.h> |
---|
| 12 | +#include <drm/drm_lease.h> |
---|
| 13 | +#include <drm/drm_print.h> |
---|
| 14 | + |
---|
| 15 | +#include "drm_crtc_internal.h" |
---|
| 16 | +#include "drm_internal.h" |
---|
| 17 | +#include "drm_legacy.h" |
---|
22 | 18 | |
---|
23 | 19 | #define drm_for_each_lessee(lessee, lessor) \ |
---|
24 | 20 | list_for_each_entry((lessee), &(lessor)->lessees, lessee_list) |
---|
.. | .. |
---|
39 | 35 | master = master->lessor; |
---|
40 | 36 | return master; |
---|
41 | 37 | } |
---|
42 | | -EXPORT_SYMBOL(drm_lease_owner); |
---|
43 | 38 | |
---|
44 | 39 | /** |
---|
45 | 40 | * _drm_find_lessee - find lessee by id (idr_mutex held) |
---|
.. | .. |
---|
112 | 107 | */ |
---|
113 | 108 | bool _drm_lease_held(struct drm_file *file_priv, int id) |
---|
114 | 109 | { |
---|
115 | | - if (file_priv == NULL || file_priv->master == NULL) |
---|
| 110 | + if (!file_priv || !file_priv->master) |
---|
116 | 111 | return true; |
---|
117 | 112 | |
---|
118 | 113 | return _drm_lease_held_master(file_priv->master, id); |
---|
119 | 114 | } |
---|
120 | | -EXPORT_SYMBOL(_drm_lease_held); |
---|
121 | 115 | |
---|
122 | 116 | /** |
---|
123 | 117 | * drm_lease_held - check drm_mode_object lease status (idr_mutex not held) |
---|
.. | .. |
---|
135 | 129 | struct drm_master *master; |
---|
136 | 130 | bool ret; |
---|
137 | 131 | |
---|
138 | | - if (file_priv == NULL || file_priv->master == NULL) |
---|
| 132 | + if (!file_priv || !file_priv->master || !file_priv->master->lessor) |
---|
139 | 133 | return true; |
---|
140 | 134 | |
---|
141 | 135 | master = file_priv->master; |
---|
.. | .. |
---|
144 | 138 | mutex_unlock(&master->dev->mode_config.idr_mutex); |
---|
145 | 139 | return ret; |
---|
146 | 140 | } |
---|
147 | | -EXPORT_SYMBOL(drm_lease_held); |
---|
148 | 141 | |
---|
149 | 142 | /** |
---|
150 | 143 | * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held) |
---|
.. | .. |
---|
162 | 155 | int count_in, count_out; |
---|
163 | 156 | uint32_t crtcs_out = 0; |
---|
164 | 157 | |
---|
165 | | - if (file_priv == NULL || file_priv->master == NULL) |
---|
| 158 | + if (!file_priv || !file_priv->master || !file_priv->master->lessor) |
---|
166 | 159 | return crtcs_in; |
---|
167 | 160 | |
---|
168 | 161 | master = file_priv->master; |
---|
.. | .. |
---|
173 | 166 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
---|
174 | 167 | if (_drm_lease_held_master(master, crtc->base.id)) { |
---|
175 | 168 | uint32_t mask_in = 1ul << count_in; |
---|
| 169 | + |
---|
176 | 170 | if ((crtcs_in & mask_in) != 0) { |
---|
177 | 171 | uint32_t mask_out = 1ul << count_out; |
---|
| 172 | + |
---|
178 | 173 | crtcs_out |= mask_out; |
---|
179 | 174 | } |
---|
180 | 175 | count_out++; |
---|
.. | .. |
---|
184 | 179 | mutex_unlock(&master->dev->mode_config.idr_mutex); |
---|
185 | 180 | return crtcs_out; |
---|
186 | 181 | } |
---|
187 | | -EXPORT_SYMBOL(drm_lease_filter_crtcs); |
---|
188 | 182 | |
---|
189 | 183 | /* |
---|
190 | 184 | * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held) |
---|
.. | .. |
---|
195 | 189 | * make sure all of the desired objects can be leased, atomically |
---|
196 | 190 | * leasing them to the new drmmaster. |
---|
197 | 191 | * |
---|
198 | | - * ERR_PTR(-EACCESS) some other master holds the title to any object |
---|
| 192 | + * ERR_PTR(-EACCES) some other master holds the title to any object |
---|
199 | 193 | * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device |
---|
200 | 194 | * ERR_PTR(-EBUSY) some other lessee holds title to this object |
---|
201 | 195 | * ERR_PTR(-EEXIST) same object specified more than once in the provided list |
---|
.. | .. |
---|
222 | 216 | |
---|
223 | 217 | idr_for_each_entry(leases, entry, object) { |
---|
224 | 218 | error = 0; |
---|
225 | | - if (!idr_find(&dev->mode_config.crtc_idr, object)) |
---|
| 219 | + if (!idr_find(&dev->mode_config.object_idr, object)) |
---|
226 | 220 | error = -ENOENT; |
---|
227 | | - else if (!_drm_lease_held_master(lessor, object)) |
---|
228 | | - error = -EACCES; |
---|
229 | 221 | else if (_drm_has_leased(lessor, object)) |
---|
230 | 222 | error = -EBUSY; |
---|
231 | 223 | |
---|
.. | .. |
---|
357 | 349 | } |
---|
358 | 350 | |
---|
359 | 351 | static int validate_lease(struct drm_device *dev, |
---|
360 | | - struct drm_file *lessor_priv, |
---|
361 | 352 | int object_count, |
---|
362 | | - struct drm_mode_object **objects) |
---|
| 353 | + struct drm_mode_object **objects, |
---|
| 354 | + bool universal_planes) |
---|
363 | 355 | { |
---|
364 | 356 | int o; |
---|
365 | 357 | int has_crtc = -1; |
---|
.. | .. |
---|
376 | 368 | if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1) |
---|
377 | 369 | has_connector = o; |
---|
378 | 370 | |
---|
379 | | - if (lessor_priv->universal_planes) { |
---|
| 371 | + if (universal_planes) { |
---|
380 | 372 | if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1) |
---|
381 | 373 | has_plane = o; |
---|
382 | 374 | } |
---|
383 | 375 | } |
---|
384 | 376 | if (has_crtc == -1 || has_connector == -1) |
---|
385 | 377 | return -EINVAL; |
---|
386 | | - if (lessor_priv->universal_planes && has_plane == -1) |
---|
| 378 | + if (universal_planes && has_plane == -1) |
---|
387 | 379 | return -EINVAL; |
---|
388 | 380 | return 0; |
---|
389 | 381 | } |
---|
.. | .. |
---|
397 | 389 | struct drm_mode_object **objects; |
---|
398 | 390 | u32 o; |
---|
399 | 391 | int ret; |
---|
| 392 | + bool universal_planes = READ_ONCE(lessor_priv->universal_planes); |
---|
| 393 | + |
---|
400 | 394 | objects = kcalloc(object_count, sizeof(struct drm_mode_object *), |
---|
401 | 395 | GFP_KERNEL); |
---|
402 | 396 | if (!objects) |
---|
.. | .. |
---|
405 | 399 | /* step one - get references to all the mode objects |
---|
406 | 400 | and check for validity. */ |
---|
407 | 401 | for (o = 0; o < object_count; o++) { |
---|
408 | | - if ((int) object_ids[o] < 0) { |
---|
409 | | - ret = -EINVAL; |
---|
410 | | - goto out_free_objects; |
---|
411 | | - } |
---|
412 | | - |
---|
413 | 402 | objects[o] = drm_mode_object_find(dev, lessor_priv, |
---|
414 | 403 | object_ids[o], |
---|
415 | 404 | DRM_MODE_OBJECT_ANY); |
---|
.. | .. |
---|
419 | 408 | } |
---|
420 | 409 | |
---|
421 | 410 | if (!drm_mode_object_lease_required(objects[o]->type)) { |
---|
| 411 | + DRM_DEBUG_KMS("invalid object for lease\n"); |
---|
422 | 412 | ret = -EINVAL; |
---|
423 | 413 | goto out_free_objects; |
---|
424 | 414 | } |
---|
425 | 415 | } |
---|
426 | 416 | |
---|
427 | | - ret = validate_lease(dev, lessor_priv, object_count, objects); |
---|
428 | | - if (ret) |
---|
| 417 | + ret = validate_lease(dev, object_count, objects, universal_planes); |
---|
| 418 | + if (ret) { |
---|
| 419 | + DRM_DEBUG_LEASE("lease validation failed\n"); |
---|
429 | 420 | goto out_free_objects; |
---|
| 421 | + } |
---|
430 | 422 | |
---|
431 | 423 | /* add their IDs to the lease request - taking into account |
---|
432 | 424 | universal planes */ |
---|
433 | 425 | for (o = 0; o < object_count; o++) { |
---|
434 | 426 | struct drm_mode_object *obj = objects[o]; |
---|
435 | 427 | u32 object_id = objects[o]->id; |
---|
| 428 | + |
---|
436 | 429 | DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id); |
---|
437 | 430 | |
---|
438 | 431 | /* |
---|
439 | 432 | * We're using an IDR to hold the set of leased |
---|
440 | 433 | * objects, but we don't need to point at the object's |
---|
441 | | - * data structure from the lease as the main crtc_idr |
---|
| 434 | + * data structure from the lease as the main object_idr |
---|
442 | 435 | * will be used to actually find that. Instead, all we |
---|
443 | 436 | * really want is a 'leased/not-leased' result, for |
---|
444 | 437 | * which any non-NULL pointer will work fine. |
---|
.. | .. |
---|
449 | 442 | object_id, ret); |
---|
450 | 443 | goto out_free_objects; |
---|
451 | 444 | } |
---|
452 | | - if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) { |
---|
| 445 | + if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) { |
---|
453 | 446 | struct drm_crtc *crtc = obj_to_crtc(obj); |
---|
| 447 | + |
---|
454 | 448 | ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL); |
---|
455 | 449 | if (ret < 0) { |
---|
456 | 450 | DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n", |
---|
.. | .. |
---|
506 | 500 | |
---|
507 | 501 | /* Can't lease without MODESET */ |
---|
508 | 502 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
---|
509 | | - return -EINVAL; |
---|
| 503 | + return -EOPNOTSUPP; |
---|
510 | 504 | |
---|
511 | 505 | /* Do not allow sub-leases */ |
---|
512 | | - if (lessor->lessor) |
---|
| 506 | + if (lessor->lessor) { |
---|
| 507 | + DRM_DEBUG_LEASE("recursive leasing not allowed\n"); |
---|
513 | 508 | return -EINVAL; |
---|
| 509 | + } |
---|
514 | 510 | |
---|
515 | 511 | /* need some objects */ |
---|
516 | | - if (cl->object_count == 0) |
---|
| 512 | + if (cl->object_count == 0) { |
---|
| 513 | + DRM_DEBUG_LEASE("no objects in lease\n"); |
---|
517 | 514 | return -EINVAL; |
---|
| 515 | + } |
---|
518 | 516 | |
---|
519 | | - if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) |
---|
| 517 | + if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) { |
---|
| 518 | + DRM_DEBUG_LEASE("invalid flags\n"); |
---|
520 | 519 | return -EINVAL; |
---|
| 520 | + } |
---|
521 | 521 | |
---|
522 | 522 | object_count = cl->object_count; |
---|
523 | 523 | |
---|
.. | .. |
---|
533 | 533 | object_count, object_ids); |
---|
534 | 534 | kfree(object_ids); |
---|
535 | 535 | if (ret) { |
---|
| 536 | + DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret); |
---|
536 | 537 | idr_destroy(&leases); |
---|
537 | 538 | return ret; |
---|
538 | 539 | } |
---|
.. | .. |
---|
617 | 618 | |
---|
618 | 619 | /* Can't lease without MODESET */ |
---|
619 | 620 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
---|
620 | | - return -EINVAL; |
---|
| 621 | + return -EOPNOTSUPP; |
---|
621 | 622 | |
---|
622 | 623 | DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id); |
---|
623 | 624 | |
---|
.. | .. |
---|
673 | 674 | |
---|
674 | 675 | /* Can't lease without MODESET */ |
---|
675 | 676 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
---|
676 | | - return -EINVAL; |
---|
| 677 | + return -EOPNOTSUPP; |
---|
677 | 678 | |
---|
678 | 679 | DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id); |
---|
679 | 680 | |
---|
.. | .. |
---|
681 | 682 | |
---|
682 | 683 | if (lessee->lessor == NULL) |
---|
683 | 684 | /* owner can use all objects */ |
---|
684 | | - object_idr = &lessee->dev->mode_config.crtc_idr; |
---|
| 685 | + object_idr = &lessee->dev->mode_config.object_idr; |
---|
685 | 686 | else |
---|
686 | 687 | /* lessee can only use allowed object */ |
---|
687 | 688 | object_idr = &lessee->leases; |
---|
.. | .. |
---|
728 | 729 | |
---|
729 | 730 | /* Can't lease without MODESET */ |
---|
730 | 731 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
---|
731 | | - return -EINVAL; |
---|
| 732 | + return -EOPNOTSUPP; |
---|
732 | 733 | |
---|
733 | 734 | mutex_lock(&dev->mode_config.idr_mutex); |
---|
734 | 735 | |
---|