int tegra_auto_hotplug_init(struct mutex *cpu_lock) { int err; cpu_clk = clk_get_sys(NULL, "cpu"); cpu_g_clk = clk_get_sys(NULL, "cpu_g"); cpu_lp_clk = clk_get_sys(NULL, "cpu_lp"); if (IS_ERR(cpu_clk) || IS_ERR(cpu_g_clk) || IS_ERR(cpu_lp_clk)) return -ENOENT; /* * Not bound to the issuer CPU (=> high-priority), has rescue worker * task, single-threaded, freezable. */ cpuquiet_wq = alloc_workqueue( "cpuquiet", WQ_UNBOUND | WQ_RESCUER | WQ_FREEZABLE, 1); if (!cpuquiet_wq) return -ENOMEM; INIT_DELAYED_WORK(&cpuquiet_work, tegra_cpuquiet_work_func); INIT_WORK(&minmax_work, min_max_constraints_workfunc); idle_top_freq = clk_get_max_rate(cpu_lp_clk) / 1000; idle_bottom_freq = clk_get_min_rate(cpu_g_clk) / 1000; up_delay = msecs_to_jiffies(UP_DELAY_MS); down_delay = msecs_to_jiffies(DOWN_DELAY_MS); cpumask_clear(&cr_online_requests); tegra3_cpu_lock = cpu_lock; cpq_state = INITIAL_STATE; enable = cpq_state == TEGRA_CPQ_DISABLED ? false : true; pr_info("Tegra cpuquiet initialized: %s\n", (cpq_state == TEGRA_CPQ_DISABLED) ? "disabled" : "enabled"); if (pm_qos_add_notifier(PM_QOS_MIN_ONLINE_CPUS, &min_cpus_notifier)) pr_err("%s: Failed to register min cpus PM QoS notifier\n", __func__); if (pm_qos_add_notifier(PM_QOS_MAX_ONLINE_CPUS, &max_cpus_notifier)) pr_err("%s: Failed to register max cpus PM QoS notifier\n", __func__); err = cpuquiet_register_driver(&tegra_cpuquiet_driver); if (err) { destroy_workqueue(cpuquiet_wq); return err; } err = tegra_auto_sysfs(); if (err) { cpuquiet_unregister_driver(&tegra_cpuquiet_driver); destroy_workqueue(cpuquiet_wq); } return err; }
void tegra_auto_hotplug_exit(void) { destroy_workqueue(cpuquiet_wq); cpuquiet_unregister_driver(&tegra_cpuquiet_driver); kobject_put(tegra_auto_sysfs_kobject); }
int tegra_auto_hotplug_init(struct mutex *cpu_lock) { int err; cpu_clk = clk_get_sys(NULL, "cpu"); cpu_g_clk = clk_get_sys(NULL, "cpu_g"); cpu_lp_clk = clk_get_sys(NULL, "cpu_lp"); if (IS_ERR(cpu_clk) || IS_ERR(cpu_g_clk) || IS_ERR(cpu_lp_clk)) return -ENOENT; idle_top_freq = tegra_lpmode_freq_max(); pr_info(CPUQUIET_TAG "%s: idle_top_freq = %d\n", __func__, idle_top_freq); /* * Not bound to the issuer CPU (=> high-priority), has rescue worker * task, single-threaded, freezable. */ cpuquiet_wq = alloc_workqueue( "cpuquiet", WQ_UNBOUND | WQ_RESCUER | WQ_FREEZABLE, 1); if (!cpuquiet_wq) return -ENOMEM; INIT_DELAYED_WORK(&cpuquiet_work, tegra_cpuquiet_work_func); INIT_WORK(&minmax_work, min_max_constraints_workfunc); INIT_WORK(&cpu_core_state_work, cpu_core_state_workfunc); tegra3_cpu_lock = cpu_lock; cpq_state = INITIAL_STATE; enable = cpq_state == TEGRA_CPQ_DISABLED ? false : true; pr_info(CPUQUIET_TAG "%s: initialized: %s\n", __func__, (cpq_state == TEGRA_CPQ_DISABLED) ? "disabled" : "enabled"); if (pm_qos_add_notifier(PM_QOS_MIN_ONLINE_CPUS, &min_cpus_notifier)) pr_err(CPUQUIET_TAG "%s: Failed to register min cpus PM QoS notifier\n", __func__); if (pm_qos_add_notifier(PM_QOS_MAX_ONLINE_CPUS, &max_cpus_notifier)) pr_err(CPUQUIET_TAG "%s: Failed to register max cpus PM QoS notifier\n", __func__); err = cpuquiet_register_driver(&tegra_cpuquiet_driver); if (err) { destroy_workqueue(cpuquiet_wq); return err; } err = tegra_auto_sysfs(); if (err) goto error; // sysfs interface for misc cpusallowed err = misc_register(&cpusallowed_device); if (err) { pr_err(CPUQUIET_TAG "%s: misc_register(%s) fail\n", __func__, cpusallowed_device.name); goto error; } if (sysfs_create_group(&cpusallowed_device.this_device->kobj, &cpusallowed_group) < 0) { pr_err(CPUQUIET_TAG "%s: Failed to create sysfs group for device (%s)!\n", __func__, cpusallowed_device.name); goto error; } return err; error: cpuquiet_unregister_driver(&tegra_cpuquiet_driver); destroy_workqueue(cpuquiet_wq); return err; }