brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · bcd03e8 Raw
147 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * cpuidle driver for haltpoll governor.4 *5 * Copyright 2019 Red Hat, Inc. and/or its affiliates.6 *7 * This work is licensed under the terms of the GNU GPL, version 2.  See8 * the COPYING file in the top-level directory.9 *10 * Authors: Marcelo Tosatti <mtosatti@redhat.com>11 */12 13#include <linux/init.h>14#include <linux/cpu.h>15#include <linux/cpuidle.h>16#include <linux/module.h>17#include <linux/sched/idle.h>18#include <linux/kvm_para.h>19#include <linux/cpuidle_haltpoll.h>20 21static bool force __read_mostly;22module_param(force, bool, 0444);23MODULE_PARM_DESC(force, "Load unconditionally");24 25static struct cpuidle_device __percpu *haltpoll_cpuidle_devices;26static enum cpuhp_state haltpoll_hp_state;27 28static __cpuidle int default_enter_idle(struct cpuidle_device *dev,29					struct cpuidle_driver *drv, int index)30{31	if (current_clr_polling_and_test())32		return index;33 34	arch_cpu_idle();35	return index;36}37 38static struct cpuidle_driver haltpoll_driver = {39	.name = "haltpoll",40	.governor = "haltpoll",41	.states = {42		{ /* entry 0 is for polling */ },43		{44			.enter			= default_enter_idle,45			.exit_latency		= 1,46			.target_residency	= 1,47			.power_usage		= -1,48			.name			= "haltpoll idle",49			.desc			= "default architecture idle",50		},51	},52	.safe_state_index = 0,53	.state_count = 2,54};55 56static int haltpoll_cpu_online(unsigned int cpu)57{58	struct cpuidle_device *dev;59 60	dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);61	if (!dev->registered) {62		dev->cpu = cpu;63		if (cpuidle_register_device(dev)) {64			pr_notice("cpuidle_register_device %d failed!\n", cpu);65			return -EIO;66		}67		arch_haltpoll_enable(cpu);68	}69 70	return 0;71}72 73static int haltpoll_cpu_offline(unsigned int cpu)74{75	struct cpuidle_device *dev;76 77	dev = per_cpu_ptr(haltpoll_cpuidle_devices, cpu);78	if (dev->registered) {79		arch_haltpoll_disable(cpu);80		cpuidle_unregister_device(dev);81	}82 83	return 0;84}85 86static void haltpoll_uninit(void)87{88	if (haltpoll_hp_state)89		cpuhp_remove_state(haltpoll_hp_state);90	cpuidle_unregister_driver(&haltpoll_driver);91 92	free_percpu(haltpoll_cpuidle_devices);93	haltpoll_cpuidle_devices = NULL;94}95 96static bool haltpoll_want(void)97{98	return kvm_para_has_hint(KVM_HINTS_REALTIME) || force;99}100 101static int __init haltpoll_init(void)102{103	int ret;104	struct cpuidle_driver *drv = &haltpoll_driver;105 106	/* Do not load haltpoll if idle= is passed */107	if (boot_option_idle_override != IDLE_NO_OVERRIDE)108		return -ENODEV;109 110	if (!kvm_para_available() || !haltpoll_want())111		return -ENODEV;112 113	cpuidle_poll_state_init(drv);114 115	ret = cpuidle_register_driver(drv);116	if (ret < 0)117		return ret;118 119	haltpoll_cpuidle_devices = alloc_percpu(struct cpuidle_device);120	if (haltpoll_cpuidle_devices == NULL) {121		cpuidle_unregister_driver(drv);122		return -ENOMEM;123	}124 125	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpuidle/haltpoll:online",126				haltpoll_cpu_online, haltpoll_cpu_offline);127	if (ret < 0) {128		haltpoll_uninit();129	} else {130		haltpoll_hp_state = ret;131		ret = 0;132	}133 134	return ret;135}136 137static void __exit haltpoll_exit(void)138{139	haltpoll_uninit();140}141 142module_init(haltpoll_init);143module_exit(haltpoll_exit);144MODULE_DESCRIPTION("cpuidle driver for haltpoll governor");145MODULE_LICENSE("GPL");146MODULE_AUTHOR("Marcelo Tosatti <mtosatti@redhat.com>");147