summaryrefslogtreecommitdiffstats
path: root/drivers/thermal
AgeCommit message (Expand)Author
2016-12-13Merge tag 'pm-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafa...Linus Torvalds
2016-12-13Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/l...Linus Torvalds
2016-12-12Merge branch 'x86-idle-for-linus' of git://git.kernel.org/pub/scm/linux/kerne...Linus Torvalds
2016-12-12Merge powerclamp driver updates (that depend on cpuidle material) for v4.10.Rafael J. Wysocki
2016-12-09x86: Remove empty idle.h headerThomas Gleixner
2016-11-30Merge branches 'thermal-core', 'thermal-intel', 'thermal-soc-fixes' and 'ther...Zhang Rui
2016-11-30thermal/x86 pkg temp: Convert to hotplug state machineSebastian Andrzej Siewior
2016-11-30thermal/x86_pkg_temp: Sanitize package managementThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Move work into package structThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Move work scheduled flag into package structThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Sanitize lockingThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Cleanup code some moreThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Cleanup namespaceThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Get rid of ref countingThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Sanitize callback (de)initializationThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Replace open coded cpu searchThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Remove redundant package searchThomas Gleixner
2016-11-30thermal/x86_pkg_temp: Cleanup thermal interrupt handlingThomas Gleixner
2016-11-30thermal: hwmon: Properly report critical temperature in sysfsKrzysztof Kozlowski
2016-11-29thermal/intel_powerclamp: stop sched tick in forced idleJacob Pan
2016-11-29thermal/intel_powerclamp: Convert to CPU hotplug stateSebastian Andrzej Siewior
2016-11-29thermal/intel_powerclamp: Convert the kthread to kthread worker APIPetr Mladek
2016-11-29thermal/intel_powerclamp: Remove duplicated code that starts the kthreadPetr Mladek
2016-11-26Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/netDavid S. Miller
2016-11-23devfreq_cooling: pass a pointer to devfreq in the power model callbacksJavi Merino
2016-11-23thermal: rockchip: improve the warning logShawn Lin
2016-11-23thermal: db8500: Fix module autoloadJavier Martinez Canillas
2016-11-23thermal: tango: Fix module autoloadJavier Martinez Canillas
2016-11-23thermal: max77620: Fix module autoloadJavier Martinez Canillas
2016-11-23thermal: qcom-spmi: Treat reg property as a single cellStephen Boyd
2016-11-23thermal: hisilicon: fix for dependencyLeo Yan
2016-11-23thermal: ti-soc-thermal: add missing clk_put()Luis Henriques
2016-11-23thermal: core: move slop and offset helpers to thermal_helpers.cEduardo Valentin
2016-11-23thermal: sysfs: use kcalloc() instead of kzalloc()Eduardo Valentin
2016-11-23thermal: core: use kzalloc(sizeof(*ptr),...)Eduardo Valentin
2016-11-23thermal: core: improve kerneldoc entry of thermal_cooling_device_unregisterEduardo Valentin
2016-11-23thermal: core: remove style warnings and checksEduardo Valentin
2016-11-23thermal: core: remove void function return statementsEduardo Valentin
2016-11-23thermal: core: standardize line breaking alignmentEduardo Valentin
2016-11-23thermal: core: small style fix when checking for __find_governor()Eduardo Valentin
2016-11-23thermal: core: remove FSF address in the GPL noticeEduardo Valentin
2016-11-23thermal: sysfs: remove symbols of emul_temp when config is disabledEduardo Valentin
2016-11-23thermal: core: add a comment describing the device management sectionEduardo Valentin
2016-11-23thermal: core: add a comment describing the power actor sectionEduardo Valentin
2016-11-23thermal: core: add a comment describing the main update loopEduardo Valentin
2016-11-23thermal: core: move notify to the zone update sectionEduardo Valentin
2016-11-23thermal: core: add inline to print_bind_err_msg()Eduardo Valentin
2016-11-23thermal: core: move __bind() to where it is usedEduardo Valentin
2016-11-23thermal: core: fix couple of style issues on __bind() helperEduardo Valentin
2016-11-23thermal: core: move bind_tz() to where it is usedEduardo Valentin
a id='n385' href='#n385'>385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright © 2017 Keith Packard <keithp@keithp.com>
 */
#include <linux/file.h>
#include <linux/uaccess.h>

#include <drm/drm_auth.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_lease.h>
#include <drm/drm_print.h>

#include "drm_crtc_internal.h"
#include "drm_internal.h"
#include "drm_legacy.h"

#define drm_for_each_lessee(lessee, lessor) \
	list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)

static uint64_t drm_lease_idr_object;

/**
 * drm_lease_owner - return ancestor owner drm_master
 * @master: drm_master somewhere within tree of lessees and lessors
 *
 * RETURN:
 *
 * drm_master at the top of the tree (i.e, with lessor NULL
 */
struct drm_master *drm_lease_owner(struct drm_master *master)
{
	while (master->lessor != NULL)
		master = master->lessor;
	return master;
}

/**
 * _drm_find_lessee - find lessee by id (idr_mutex held)
 * @master: drm_master of lessor
 * @lessee_id: id
 *
 * RETURN:
 *
 * drm_master of the lessee if valid, NULL otherwise
 */

static struct drm_master*
_drm_find_lessee(struct drm_master *master, int lessee_id)
{
	lockdep_assert_held(&master->dev->mode_config.idr_mutex);
	return idr_find(&drm_lease_owner(master)->lessee_idr, lessee_id);
}

/**
 * _drm_lease_held_master - check to see if an object is leased (or owned) by master (idr_mutex held)
 * @master: the master to check the lease status of
 * @id: the id to check
 *
 * Checks if the specified master holds a lease on the object. Return
 * value:
 *
 *	true		'master' holds a lease on (or owns) the object
 *	false		'master' does not hold a lease.
 */
static int _drm_lease_held_master(struct drm_master *master, int id)
{
	lockdep_assert_held(&master->dev->mode_config.idr_mutex);
	if (master->lessor)
		return idr_find(&master->leases, id) != NULL;
	return true;
}

/**
 * _drm_has_leased - check to see if an object has been leased (idr_mutex held)
 * @master: the master to check the lease status of
 * @id: the id to check
 *
 * Checks if any lessee of 'master' holds a lease on 'id'. Return
 * value:
 *
 *	true		Some lessee holds a lease on the object.
 *	false		No lessee has a lease on the object.
 */
static bool _drm_has_leased(struct drm_master *master, int id)
{
	struct drm_master *lessee;

	lockdep_assert_held(&master->dev->mode_config.idr_mutex);
	drm_for_each_lessee(lessee, master)
		if (_drm_lease_held_master(lessee, id))
			return true;
	return false;
}

/**
 * _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
 * @file_priv: the master drm_file
 * @id: the object id
 *
 * Checks if the specified master holds a lease on the object. Return
 * value:
 *
 *	true		'master' holds a lease on (or owns) the object
 *	false		'master' does not hold a lease.
 */
bool _drm_lease_held(struct drm_file *file_priv, int id)
{
	if (!file_priv || !file_priv->master)
		return true;

	return _drm_lease_held_master(file_priv->master, id);
}

/**
 * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
 * @file_priv: the master drm_file
 * @id: the object id
 *
 * Checks if the specified master holds a lease on the object. Return
 * value:
 *
 *	true		'master' holds a lease on (or owns) the object
 *	false		'master' does not hold a lease.
 */
bool drm_lease_held(struct drm_file *file_priv, int id)
{
	struct drm_master *master;
	bool ret;

	if (!file_priv || !file_priv->master || !file_priv->master->lessor)
		return true;

	master = file_priv->master;
	mutex_lock(&master->dev->mode_config.idr_mutex);
	ret = _drm_lease_held_master(master, id);
	mutex_unlock(&master->dev->mode_config.idr_mutex);
	return ret;
}

/**
 * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
 * @file_priv: requestor file
 * @crtcs_in: bitmask of crtcs to check
 *
 * Reconstructs a crtc mask based on the crtcs which are visible
 * through the specified file.
 */
uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
{
	struct drm_master *master;
	struct drm_device *dev;
	struct drm_crtc *crtc;
	int count_in, count_out;
	uint32_t crtcs_out = 0;

	if (!file_priv || !file_priv->master || !file_priv->master->lessor)
		return crtcs_in;

	master = file_priv->master;
	dev = master->dev;

	count_in = count_out = 0;
	mutex_lock(&master->dev->mode_config.idr_mutex);
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		if (_drm_lease_held_master(master, crtc->base.id)) {
			uint32_t mask_in = 1ul << count_in;

			if ((crtcs_in & mask_in) != 0) {
				uint32_t mask_out = 1ul << count_out;

				crtcs_out |= mask_out;
			}
			count_out++;
		}
		count_in++;
	}
	mutex_unlock(&master->dev->mode_config.idr_mutex);
	return crtcs_out;
}

/*
 * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
 * @lessor: lease holder (or owner) of objects
 * @leases: objects to lease to the new drm_master
 *
 * Uses drm_master_create to allocate a new drm_master, then checks to
 * make sure all of the desired objects can be leased, atomically
 * leasing them to the new drmmaster.
 *
 * 	ERR_PTR(-EACCES)	some other master holds the title to any object
 * 	ERR_PTR(-ENOENT)	some object is not a valid DRM object for this device
 * 	ERR_PTR(-EBUSY)		some other lessee holds title to this object
 *	ERR_PTR(-EEXIST)	same object specified more than once in the provided list
 *	ERR_PTR(-ENOMEM)	allocation failed
 */
static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr *leases)
{
	struct drm_device *dev = lessor->dev;
	int error;
	struct drm_master *lessee;
	int object;
	int id;
	void *entry;

	DRM_DEBUG_LEASE("lessor %d\n", lessor->lessee_id);

	lessee = drm_master_create(lessor->dev);
	if (!lessee) {
		DRM_DEBUG_LEASE("drm_master_create failed\n");
		return ERR_PTR(-ENOMEM);
	}

	mutex_lock(&dev->mode_config.idr_mutex);

	idr_for_each_entry(leases, entry, object) {
		error = 0;
		if (!idr_find(&dev->mode_config.object_idr, object))
			error = -ENOENT;
		else if (_drm_has_leased(lessor, object))
			error = -EBUSY;

		if (error != 0) {
			DRM_DEBUG_LEASE("object %d failed %d\n", object, error);
			goto out_lessee;
		}
	}

	/* Insert the new lessee into the tree */
	id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL);
	if (id < 0) {
		error = id;
		goto out_lessee;
	}

	lessee->lessee_id = id;
	lessee->lessor =