Merge "soc: qcom: Implement early domain handoff driver"
This commit is contained in:
commit
f76f39c28b
5 changed files with 490 additions and 0 deletions
|
@ -0,0 +1,29 @@
|
||||||
|
Early domain core driver.
|
||||||
|
|
||||||
|
Early domain in bootloader run multimedia services like display,
|
||||||
|
camera, audio by reserving cpu(s) and some memory in parallel with
|
||||||
|
kernel.
|
||||||
|
|
||||||
|
These services may need to stop when they decide. Early domain
|
||||||
|
driver in kernel communicates with early services through a shared
|
||||||
|
memory block. This block is reserved during kernel boot.
|
||||||
|
|
||||||
|
Early services running in bootloader update their status in the
|
||||||
|
shared memory block. Multimedia drivers in kernel can make use of
|
||||||
|
apis provided by early domain core driver to get the status of early
|
||||||
|
services and free reserved memory resource to system
|
||||||
|
when the early services end.
|
||||||
|
|
||||||
|
Required properties
|
||||||
|
- compatible : should be "qcom,early_domain"
|
||||||
|
- status : should be "disabled" by default.
|
||||||
|
status should be made "ok" only
|
||||||
|
if earlydomain is active by
|
||||||
|
bootloaders.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
early_domain: early_domain {
|
||||||
|
compatible = "qcom,early_domain";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
|
@ -392,6 +392,9 @@ config QCOM_SCM_QCPE
|
||||||
bool "Para-Virtualized Secure Channel Manager (SCM) support over QCPE"
|
bool "Para-Virtualized Secure Channel Manager (SCM) support over QCPE"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config QCOM_EARLY_DOMAIN
|
||||||
|
bool "Support for handoff of early domain services running in bootloader"
|
||||||
|
|
||||||
menuconfig QCOM_SCM_XPU
|
menuconfig QCOM_SCM_XPU
|
||||||
bool "Qualcomm XPU configuration driver"
|
bool "Qualcomm XPU configuration driver"
|
||||||
depends on QCOM_SCM
|
depends on QCOM_SCM
|
||||||
|
|
|
@ -71,6 +71,7 @@ obj-$(CONFIG_QCOM_MEMORY_DUMP_V2) += memory_dump_v2.o
|
||||||
obj-$(CONFIG_QCOM_MINIDUMP) += msm_minidump.o
|
obj-$(CONFIG_QCOM_MINIDUMP) += msm_minidump.o
|
||||||
obj-$(CONFIG_QCOM_DCC) += dcc.o
|
obj-$(CONFIG_QCOM_DCC) += dcc.o
|
||||||
obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o
|
obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o
|
||||||
|
obj-$(CONFIG_QCOM_EARLY_DOMAIN) += early_dom.o
|
||||||
obj-$(CONFIG_QCOM_COMMON_LOG) += common_log.o
|
obj-$(CONFIG_QCOM_COMMON_LOG) += common_log.o
|
||||||
obj-$(CONFIG_QCOM_IRQ_HELPER) += irq-helper.o
|
obj-$(CONFIG_QCOM_IRQ_HELPER) += irq-helper.o
|
||||||
obj-$(CONFIG_TRACER_PKT) += tracer_pkt.o
|
obj-$(CONFIG_TRACER_PKT) += tracer_pkt.o
|
||||||
|
|
359
drivers/soc/qcom/early_dom.c
Normal file
359
drivers/soc/qcom/early_dom.c
Normal file
|
@ -0,0 +1,359 @@
|
||||||
|
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/memblock.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <soc/qcom/early_domain.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <asm/barrier.h>
|
||||||
|
|
||||||
|
static struct early_domain_core *ed_core_data;
|
||||||
|
static bool early_domain_enabled;
|
||||||
|
|
||||||
|
bool get_early_service_status(enum service_id sid)
|
||||||
|
{
|
||||||
|
struct early_domain_core *domain;
|
||||||
|
unsigned long *status;
|
||||||
|
|
||||||
|
if (!early_domain_enabled)
|
||||||
|
return false;
|
||||||
|
domain = ed_core_data;
|
||||||
|
status = &domain->pdata->early_domain_status;
|
||||||
|
cpu_relax();
|
||||||
|
return test_bit(sid, status);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(get_early_service_status);
|
||||||
|
|
||||||
|
static void active_early_services(void)
|
||||||
|
{
|
||||||
|
enum service_id core;
|
||||||
|
int i;
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
core = EARLY_DOMAIN_CORE;
|
||||||
|
i = (int)core;
|
||||||
|
while (i < NUM_SERVICES) {
|
||||||
|
active = get_early_service_status((enum service_id)i);
|
||||||
|
if (active)
|
||||||
|
pr_info("Early service_id:%d active\n", i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void request_early_service_shutdown(enum service_id sid)
|
||||||
|
{
|
||||||
|
struct early_domain_core *domain = ed_core_data;
|
||||||
|
unsigned long *request;
|
||||||
|
|
||||||
|
request = &domain->pdata->early_domain_request;
|
||||||
|
set_bit(sid, request);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(request_early_service_shutdown);
|
||||||
|
|
||||||
|
void *get_service_shared_mem_start(enum service_id sid)
|
||||||
|
{
|
||||||
|
void *service_shared_mem_start;
|
||||||
|
void *early_domain_shm_start;
|
||||||
|
|
||||||
|
if (!early_domain_enabled || sid < EARLY_DISPLAY || sid > NUM_SERVICES)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
early_domain_shm_start = ed_core_data->pdata;
|
||||||
|
service_shared_mem_start = early_domain_shm_start +
|
||||||
|
sizeof(struct early_domain_header) +
|
||||||
|
(SERVICE_SHARED_MEM_SIZE * (sid - 1));
|
||||||
|
return service_shared_mem_start;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(get_service_shared_mem_start);
|
||||||
|
|
||||||
|
static void free_reserved_lk_mem(phys_addr_t paddr, size_t size)
|
||||||
|
{
|
||||||
|
unsigned long pfn_start, pfn_end, pfn_idx;
|
||||||
|
|
||||||
|
memblock_free(paddr, size);
|
||||||
|
pfn_start = paddr >> PAGE_SHIFT;
|
||||||
|
pfn_end = (paddr + size) >> PAGE_SHIFT;
|
||||||
|
for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++)
|
||||||
|
free_reserved_page(pfn_to_page(pfn_idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void early_domain_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct early_domain_core *core_data;
|
||||||
|
struct device *cpu_device;
|
||||||
|
unsigned long *status;
|
||||||
|
int cpu;
|
||||||
|
int delay;
|
||||||
|
int max_delay;
|
||||||
|
|
||||||
|
core_data = ed_core_data;
|
||||||
|
status = &core_data->pdata->early_domain_status;
|
||||||
|
delay = 40;
|
||||||
|
max_delay = 1000;
|
||||||
|
|
||||||
|
/* Poll on status which will be updated by early-domain running in LK */
|
||||||
|
while (*status) {
|
||||||
|
cpu_relax();
|
||||||
|
msleep(delay);
|
||||||
|
delay = (delay > max_delay ? max_delay : delay + 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* An instruction barrier to ensure that execution pipline is flushed
|
||||||
|
* and instrutions ahead are not executed out of order, leading to
|
||||||
|
* an unwanted situation where we free resources with a non-zero status.
|
||||||
|
*/
|
||||||
|
|
||||||
|
isb();
|
||||||
|
|
||||||
|
/* Once the status is zero, hot add reserved cpu cores and
|
||||||
|
* free reserved memory
|
||||||
|
*/
|
||||||
|
unregister_cpu_notifier(&core_data->ed_notifier);
|
||||||
|
|
||||||
|
/* Take attempts to hot add the cpu(s) reserved for early domain
|
||||||
|
* with delays
|
||||||
|
*/
|
||||||
|
delay = 20;
|
||||||
|
max_delay = 200;
|
||||||
|
while (!cpumask_empty(&core_data->cpumask)) {
|
||||||
|
for_each_cpu(cpu, &core_data->cpumask) {
|
||||||
|
cpu_device = get_cpu_device(cpu);
|
||||||
|
if (!cpu_device) {
|
||||||
|
pr_err("cpu:%d absent in cpu_possible_mask\n"
|
||||||
|
, cpu);
|
||||||
|
cpumask_clear_cpu(cpu, &core_data->cpumask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!device_online(cpu_device))
|
||||||
|
cpumask_clear_cpu(cpu, &core_data->cpumask);
|
||||||
|
}
|
||||||
|
msleep(delay);
|
||||||
|
delay = (delay > max_delay ? max_delay : delay + 20);
|
||||||
|
}
|
||||||
|
free_reserved_lk_mem(core_data->lk_pool_paddr, core_data->lk_pool_size);
|
||||||
|
free_reserved_lk_mem(core_data->early_domain_shm,
|
||||||
|
core_data->early_domain_shm_size);
|
||||||
|
|
||||||
|
/* Remove qos and wake locks */
|
||||||
|
|
||||||
|
pm_qos_remove_request(&core_data->ed_qos_request);
|
||||||
|
__pm_relax(&core_data->ed_wake_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int early_domain_cpu_notifier(struct notifier_block *self,
|
||||||
|
unsigned long action, void *hcpu)
|
||||||
|
{
|
||||||
|
struct early_domain_core *core_data = container_of(self,
|
||||||
|
struct early_domain_core, ed_notifier);
|
||||||
|
unsigned int notifier;
|
||||||
|
unsigned int cpu;
|
||||||
|
|
||||||
|
notifier = NOTIFY_BAD;
|
||||||
|
cpu = (long)hcpu;
|
||||||
|
switch (action & ~CPU_TASKS_FROZEN) {
|
||||||
|
case CPU_UP_PREPARE:
|
||||||
|
if (cpumask_test_cpu(cpu, &core_data->cpumask))
|
||||||
|
pr_err("Early domain services are running on cpu%d\n"
|
||||||
|
, cpu);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
notifier = NOTIFY_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return notifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_early_domain_data(struct early_domain_core *core_data)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
unsigned long cpumask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cpumask_clear(&core_data->cpumask);
|
||||||
|
cpumask = (unsigned long)core_data->pdata->cpumask;
|
||||||
|
for_each_set_bit(cpu, &cpumask, sizeof(cpumask_t))
|
||||||
|
cpumask_set_cpu(cpu, &core_data->cpumask);
|
||||||
|
|
||||||
|
memset(&core_data->ed_qos_request, 0,
|
||||||
|
sizeof(core_data->ed_qos_request));
|
||||||
|
core_data->ed_qos_request.type = PM_QOS_REQ_AFFINE_CORES;
|
||||||
|
core_data->ed_qos_request.cpus_affine = core_data->cpumask;
|
||||||
|
pm_qos_add_request(&core_data->ed_qos_request,
|
||||||
|
PM_QOS_CPU_DMA_LATENCY, PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE);
|
||||||
|
wakeup_source_init(&core_data->ed_wake_lock, "early_domain");
|
||||||
|
__pm_stay_awake(&core_data->ed_wake_lock);
|
||||||
|
core_data->ed_notifier = (struct notifier_block) {
|
||||||
|
.notifier_call = early_domain_cpu_notifier,
|
||||||
|
};
|
||||||
|
ret = register_cpu_notifier(&core_data->ed_notifier);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&core_data->pdev->dev, "Could not register cpu notifier\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
INIT_WORK(&core_data->early_domain_work, early_domain_work);
|
||||||
|
if (!schedule_work(&core_data->early_domain_work)) {
|
||||||
|
dev_err(&core_data->pdev->dev, "Could not schedule work for handoff\n");
|
||||||
|
unregister_cpu_notifier(&core_data->ed_notifier);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It is expected that probe is being called before the initialization of
|
||||||
|
* multimedia drivers like display/camera/audio, so they get correct status
|
||||||
|
* of any active early service.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int early_domain_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct early_domain_core *core_data;
|
||||||
|
struct resource res_shm, res_lk;
|
||||||
|
struct device_node *parent, *node;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
parent = of_find_node_by_path("/reserved-memory");
|
||||||
|
if (!parent) {
|
||||||
|
dev_err(&pdev->dev, "Could not find reserved-memory node\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* early_domain_shm reserved memory node will be added by bootloader
|
||||||
|
* dynamically if earlydomain was enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
node = of_find_node_by_name(parent, "early_domain_shm");
|
||||||
|
if (!node) {
|
||||||
|
dev_err(&pdev->dev, "Could not find early_domain_shm\n");
|
||||||
|
of_node_put(parent);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
ret = of_address_to_resource(node, 0, &res_shm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "No memory address assigned to the region\n");
|
||||||
|
of_node_put(node);
|
||||||
|
of_node_put(parent);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
of_node_put(node);
|
||||||
|
/* lk_pool reserved memory node will be added by bootloader
|
||||||
|
* dynamically if earlydomain was enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
node = of_find_node_by_name(parent, "lk_pool");
|
||||||
|
if (!node) {
|
||||||
|
dev_err(&pdev->dev, "Could not find lk_pool\n");
|
||||||
|
of_node_put(parent);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
of_node_put(parent);
|
||||||
|
ret = of_address_to_resource(node, 0, &res_lk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "No memory address assigned to lk_pool\n");
|
||||||
|
of_node_put(node);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
of_node_put(node);
|
||||||
|
core_data = kzalloc(sizeof(*core_data), GFP_KERNEL);
|
||||||
|
if (!core_data)
|
||||||
|
return -ENOMEM;
|
||||||
|
ed_core_data = core_data;
|
||||||
|
core_data->pdata = (struct early_domain_header *)
|
||||||
|
ioremap_nocache(res_shm.start, resource_size(&res_shm));
|
||||||
|
if (!core_data->pdata) {
|
||||||
|
dev_err(&pdev->dev, "%s cannot map reserved early domain space\n"
|
||||||
|
, __func__);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
core_data->early_domain_shm = (dma_addr_t)res_shm.start;
|
||||||
|
core_data->early_domain_shm_size = res_shm.end - res_shm.start;
|
||||||
|
core_data->lk_pool_paddr = (dma_addr_t)res_lk.start;
|
||||||
|
core_data->lk_pool_size = res_lk.end - res_lk.start;
|
||||||
|
ret = memcmp(core_data->pdata->magic, EARLY_DOMAIN_MAGIC,
|
||||||
|
MAGIC_SIZE);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Early domain reserved page has been corrupted\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
core_data->pdev = pdev;
|
||||||
|
ret = init_early_domain_data(core_data);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
platform_set_drvdata(pdev, core_data);
|
||||||
|
early_domain_enabled = true;
|
||||||
|
active_early_services();
|
||||||
|
return ret;
|
||||||
|
err:
|
||||||
|
if (pm_qos_request_active(&core_data->ed_qos_request))
|
||||||
|
pm_qos_remove_request(&core_data->ed_qos_request);
|
||||||
|
if (core_data->ed_wake_lock.active)
|
||||||
|
wakeup_source_trash(&core_data->ed_wake_lock);
|
||||||
|
kfree(core_data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int early_domain_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct early_domain_core *core_data;
|
||||||
|
|
||||||
|
core_data = platform_get_drvdata(pdev);
|
||||||
|
pm_qos_remove_request(&core_data->ed_qos_request);
|
||||||
|
__pm_relax(&core_data->ed_wake_lock);
|
||||||
|
unregister_cpu_notifier(&core_data->ed_notifier);
|
||||||
|
kfree(core_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id early_domain_table[] = {
|
||||||
|
{ .compatible = "qcom,early_domain" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver early_domain_driver = {
|
||||||
|
.probe = early_domain_probe,
|
||||||
|
.remove = early_domain_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "early_domain",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = early_domain_table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init earlydom_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&early_domain_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_initcall(earlydom_init);
|
||||||
|
|
||||||
|
static void __exit earlydom_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&early_domain_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_exit(earlydom_exit);
|
||||||
|
MODULE_DESCRIPTION("QCOM EARLYDOMAIN DRIVER");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_DEVICE_TABLE(of, early_domain_table);
|
98
include/soc/qcom/early_domain.h
Normal file
98
include/soc/qcom/early_domain.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Early domain services invoked in bootloaders run in parallel after
|
||||||
|
* kernel takes over. One page in memory is reserved to pass information
|
||||||
|
* between bootloader and kernel. This page has a header to capture status,
|
||||||
|
* request and cpumask described in structure early_domain_header. Early
|
||||||
|
* domain core driver in kernel reads this header to decide the status of
|
||||||
|
* services and takes necessary action. The rest of the page is intended to
|
||||||
|
* pass service specific information. Offset for service specific area are
|
||||||
|
* defined in macros, and its the service specific driver's responsiblity
|
||||||
|
* to operate in their defined areas to pass service specific information.
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *****************************************
|
||||||
|
* * Header *
|
||||||
|
* * *
|
||||||
|
* *****************************************
|
||||||
|
* * *
|
||||||
|
* * Early display *
|
||||||
|
* * *
|
||||||
|
* * *
|
||||||
|
* *****************************************
|
||||||
|
* * *
|
||||||
|
* * Early camera *
|
||||||
|
* * *
|
||||||
|
* * *
|
||||||
|
* *****************************************
|
||||||
|
* * *
|
||||||
|
* * Early audio *
|
||||||
|
* * *
|
||||||
|
* * *
|
||||||
|
* *****************************************
|
||||||
|
* *
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum service_id {
|
||||||
|
EARLY_DOMAIN_CORE = 0,
|
||||||
|
EARLY_DISPLAY,
|
||||||
|
EARLY_CAMERA,
|
||||||
|
EARLY_AUDIO,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_QCOM_EARLY_DOMAIN
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/cpumask.h>
|
||||||
|
#include <linux/pm_qos.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
|
||||||
|
#define EARLY_DOMAIN_MAGIC "ERLYDOM"
|
||||||
|
#define MAGIC_SIZE 8
|
||||||
|
#define NUM_SERVICES 3
|
||||||
|
#define SERVICE_SHARED_MEM_SIZE ((PAGE_SIZE)/(NUM_SERVICES))
|
||||||
|
|
||||||
|
struct early_domain_header {
|
||||||
|
char magic[MAGIC_SIZE];
|
||||||
|
unsigned long cpumask;
|
||||||
|
unsigned long early_domain_status;
|
||||||
|
unsigned long early_domain_request;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct early_domain_core {
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct early_domain_header *pdata;
|
||||||
|
struct work_struct early_domain_work;
|
||||||
|
phys_addr_t lk_pool_paddr;
|
||||||
|
size_t lk_pool_size;
|
||||||
|
phys_addr_t early_domain_shm;
|
||||||
|
size_t early_domain_shm_size;
|
||||||
|
cpumask_t cpumask;
|
||||||
|
struct notifier_block ed_notifier;
|
||||||
|
struct pm_qos_request ed_qos_request;
|
||||||
|
struct wakeup_source ed_wake_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
void request_early_service_shutdown(enum service_id);
|
||||||
|
bool get_early_service_status(enum service_id sid);
|
||||||
|
void *get_service_shared_mem_start(enum service_id sid);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void request_early_service_shutdown(enum service_id sid) {}
|
||||||
|
static inline bool get_early_service_status(enum service_id sid)
|
||||||
|
{ return false; }
|
||||||
|
static inline void *get_service_shared_mem_start(enum service_id sid)
|
||||||
|
{ return NULL; }
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue