adreno源码系列打开kgsl
Posted bubbleben
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了adreno源码系列打开kgsl相关的知识,希望对你有一定的参考价值。
// 接"adreno源码系列(二)kgsl driver"中第3.3节
static int kgsl_open_device(struct kgsl_device *device)
int result = 0;
mutex_lock(&device->mutex);
// kgsl_device->open_count记录/dev/kgsl-3d0被open的次数
if (device->open_count == 0)
// 如果是第一次打开, 则调用adreno_functable中定义的adreno_first_open[见第1节]
result = device->ftbl->first_open(device);
if (result)
goto out;
// /dev/kgsl-3d0每被打开一次, 增加1个对应的fd
device->open_count++;
out:
mutex_unlock(&device->mutex);
return result;
1. adreno_first_open
static int adreno_first_open(struct kgsl_device *device)
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
// adreno_a6xx_gmu_gpudev中定义adreno_power_ops为a6xx_gmu_power_ops[见第2节]
const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev);
// 调用a6xx_gmu_power_ops定义的a6xx_gmu_first_open[见第3节]
return ops->first_open(adreno_dev);
2. a6xx_gmu_power_ops
const struct adreno_power_ops a6xx_gmu_power_ops =
// 第一次打开
.first_open = a6xx_gmu_first_open,
.last_close = a6xx_gmu_last_close,
.active_count_get = a6xx_gmu_active_count_get,
.active_count_put = a6xx_gmu_active_count_put,
.pm_suspend = a6xx_gmu_pm_suspend,
.pm_resume = a6xx_gmu_pm_resume,
.touch_wakeup = a6xx_gmu_touch_wakeup,
.gpu_clock_set = a6xx_gmu_clock_set,
.gpu_bus_set = a6xx_gmu_bus_set,
;
3. a6xx_gmu_first_open
static int a6xx_gmu_first_open(struct adreno_device *adreno_dev)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
int ret;
/*
* Do the one time settings that need to happen when we
* attempt to boot the gpu the very first time
*/
// a6xx第一次启动[见3.1节]
ret = a6xx_first_boot(adreno_dev);
if (ret)
return ret;
/*
* A client that does a first_open but never closes the device
* may prevent us from going back to SLUMBER. So trigger the idle
* check by incrementing the active count and immediately releasing it.
*/
atomic_inc(&device->active_cnt);
a6xx_gmu_active_count_put(adreno_dev);
return 0;
3.1 a6xx_first_boot
static int a6xx_first_boot(struct adreno_device *adreno_dev)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
int ret;
unsigned long priv = 0;
if (test_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags))
return a6xx_boot(adreno_dev);
place_marker("M - DRIVER ADRENO Init");
// 初始化adreno_dispatcher[见第4节]
ret = adreno_dispatcher_init(adreno_dev);
if (ret)
return ret;
// 初始化adreno_ringbuffer[见第5节]
ret = adreno_ringbuffer_init(adreno_dev);
if (ret)
return ret;
ret = a6xx_microcode_read(adreno_dev);
if (ret)
return ret;
// 初始化a6xx[见第6节]
ret = a6xx_init(adreno_dev);
if (ret)
return ret;
// 初始化a6xx gmu: 见"adreno源码系列之GMU"
ret = a6xx_gmu_init(adreno_dev);
if (ret)
return ret;
trace_kgsl_pwr_request_state(device, KGSL_STATE_ACTIVE);
// gmu第一次启动: 见"adreno源码系列之GMU"
ret = a6xx_gmu_first_boot(adreno_dev);
if (ret)
return ret;
// a6xx gpu启动[见第7节]
ret = a6xx_gpu_boot(adreno_dev);
if (ret)
return ret;
adreno_get_bus_counters(adreno_dev);
adreno_dev->cooperative_reset = ADRENO_FEATURE(adreno_dev,
ADRENO_COOP_RESET);
if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV))
priv |= KGSL_MEMDESC_PRIVILEGED;
// 分配adreno_device全局共享的大小为4k名为alwayson的内存
adreno_dev->profile_buffer = kgsl_allocate_global(device, PAGE_SIZE, 0,
0, priv, "alwayson");
// profile_index初始化为0
adreno_dev->profile_index = 0;
if (!IS_ERR(adreno_dev->profile_buffer))
set_bit(ADRENO_DEVICE_DRAWOBJ_PROFILE, &adreno_dev->priv);
set_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags);
set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags);
device->pwrctrl.last_stat_updated = ktime_get();
device->state = KGSL_STATE_ACTIVE;
trace_kgsl_pwr_set_state(device, KGSL_STATE_ACTIVE);
place_marker("M - DRIVER ADRENO Ready");
return 0;
4. adreno_dispatcher_init
/* Use a kmem cache to speed up allocations for dispatcher jobs */
static struct kmem_cache *jobs_cache;
/**
* adreno_dispatcher_init() - Initialize the dispatcher
* @adreno_dev: pointer to the adreno device structure
*
* Initialize the dispatcher
*/
// 见"adreno源码系列之adreno_dispatcher"
int adreno_dispatcher_init(struct adreno_device *adreno_dev)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
int ret, i;
if (test_bit(ADRENO_DISPATCHER_INIT, &dispatcher->priv))
return 0;
// 初始化adreno_dispatcher
memset(dispatcher, 0, sizeof(*dispatcher));
ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher,
&device->dev->kobj, "dispatch");
if (ret)
return ret;
WARN_ON(sysfs_create_files(&device->dev->kobj, _preempt_attr_list));
mutex_init(&dispatcher->mutex);
// 设置timer_list
timer_setup(&dispatcher->timer, adreno_dispatcher_timer, 0);
timer_setup(&dispatcher->fault_timer, adreno_dispatcher_fault_timer, 0);
// 初始化kthread_work为adreno_dispatcher_work
kthread_init_work(&dispatcher->work, adreno_dispatcher_work);
init_completion(&dispatcher->idle_gate);
complete_all(&dispatcher->idle_gate);
// 创建adreno_dispatch_job
jobs_cache = KMEM_CACHE(adreno_dispatch_job, 0);
for (i = 0; i < ARRAY_SIZE(dispatcher->jobs); i++)
init_llist_head(&dispatcher->jobs[i]);
init_llist_head(&dispatcher->requeue[i]);
// 设置adreno_dispatcher的标志位:ADRENO_DISPATCHER_INIT
set_bit(ADRENO_DISPATCHER_INIT, &dispatcher->priv);
return 0;
5. adreno_ringbuffer_init
// 见"adreno源码系列之adreno_ringbuffer"
int adreno_ringbuffer_init(struct adreno_device *adreno_dev)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
int i;
int status = -ENOMEM;
if (!adreno_is_a3xx(adreno_dev))
unsigned int priv =
KGSL_MEMDESC_RANDOM | KGSL_MEMDESC_PRIVILEGED;
if (IS_ERR_OR_NULL(device->scratch))
// 分配kgsl_device全局共享的大小为4k名为scratch的内存
device->scratch = kgsl_allocate_global(device,
PAGE_SIZE, 0, 0, priv, "scratch");
if (IS_ERR(device->scratch))
return PTR_ERR(device->scratch);
// 支持抢占则adreno_ringbuffer个数为4, 否则只有1个adreno_ringbuffer
if (ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION))
adreno_dev->num_ringbuffers =
ARRAY_SIZE(adreno_dev->ringbuffers);
else
adreno_dev->num_ringbuffers = 1;
for (i = 0; i < adreno_dev->num_ringbuffers; i++)
// 初始化每个adreno_ringbuffer
status = _adreno_ringbuffer_init(adreno_dev, i);
if (status)
adreno_ringbuffer_close(adreno_dev);
return status;
// 初始化当前adreno_ringbuffer
adreno_dev->cur_rb = &(adreno_dev->ringbuffers[0]);
if (ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION))
const struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct adreno_preemption *preempt = &adreno_dev->preempt;
int ret;
timer_setup(&preempt->timer, adreno_preemption_timer, 0);
ret = gpudev->preemption_init(adreno_dev);
WARN(ret, "adreno GPU preemption is disabled\\n");
return 0;
6. a6xx_init
int a6xx_init(struct adreno_device *adreno_dev)
const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev);
adreno_dev->highest_bank_bit = a6xx_core->highest_bank_bit;
/* If the memory type is DDR 4, override the existing configuration */
if (of_fdt_get_ddrtype() == 0x7)
if (adreno_is_a642(adreno_dev) ||
adreno_is_a642l(adreno_dev))
adreno_dev->highest_bank_bit = 14;
else if ((adreno_is_a650(adreno_dev) ||
adreno_is_a660(adreno_dev)))
adreno_dev->highest_bank_bit = 15;
a6xx_crashdump_init(adreno_dev);
if (IS_ERR_OR_NULL(adreno_dev->pwrup_reglist))
// 分配adreno_device全局共享的大小为4k名为powerup_register_list的内存
adreno_dev->pwrup_reglist =
kgsl_allocate_global(KGSL_DEVICE(adreno_dev),
PAGE_SIZE, 0, 0, KGSL_MEMDESC_PRIVILEGED,
"powerup_register_list");
if (IS_ERR(adreno_dev->pwrup_reglist))
return PTR_ERR(adreno_dev->pwrup_reglist);
find_ddr_qos_device(adreno_dev);
// 获取CP初始化指令, 保存到adreno_device->cp_init_cmds
return a6xx_get_cp_init_cmds(adreno_dev);
7. a6xx_gpu_boot
static int a6xx_gpu_boot(struct adreno_device *adreno_dev)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
int ret;
/* Clear any GPU faults that might have been left over */
adreno_clear_gpu_fault(adreno_dev);
adreno_set_active_ctxs_null(adreno_dev);
adreno_ringbuffer_set_global(adreno_dev, 0);
// kgsl mmu启动
ret = kgsl_mmu_start(device);
if (ret)
goto err;
ret = a6xx_gmu_oob_set(device, oob_gpu);
if (ret)
goto oob_clear;
ret = a6xx_gmu_hfi_start_msg(adreno_dev);
if (ret)
goto oob_clear;
adreno_clear_dcvs_counters(adreno_dev);
/* Restore performance counter registers with saved values */
adreno_perfcounter_restore(adreno_dev);
// a6xx gpu start:见"adreno源码系列(六)启动kgsl"
a6xx_start(adreno_dev);
/* Re-initialize the coresight registers if applicable */
adreno_coresight_start(adreno_dev);
// 启动性能计数器:见"adreno源码系列(六)启动kgsl"
adreno_perfcounter_start(adreno_dev);
/* Clear FSR here in case it is set from a previous pagefault */
kgsl_mmu_clear_fsr(&device->mmu);
a6xx_enable_gpu_irq(adreno_dev);
// 启动adreno_ringbuffer:见"adreno源码系列(六)启动kgsl"
ret = a6xx_rb_start(adreno_dev);
if (ret)
a6xx_disable_gpu_irq(adreno_dev);
goto oob_clear;
/* Start the dispatcher */
// 启动adreno_dispatcher:见"adreno源码系列(六)启动kgsl"
adreno_dispatcher_start(device);
device->reset_counter++;
a6xx_gmu_oob_clear(device, oob_gpu);
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
gmu_core_dev_oob_clear(device, oob_boot_slumber);
return 0;
oob_clear:
a6xx_gmu_oob_clear(device, oob_gpu);
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
gmu_core_dev_oob_clear(device, oob_boot_slumber);
err:
a6xx_gmu_power_off(adreno_dev);
return ret;
以上是关于adreno源码系列打开kgsl的主要内容,如果未能解决你的问题,请参考以下文章