adreno源码系列(四)注册platform_driver


1. adreno_platform_driver

static struct adreno_device device_3d0;

static const struct of_device_id adreno_match_table[] = {
	{ .compatible = "qcom,kgsl-3d0", .data = &device_3d0 },
	{ },
};

static struct platform_driver adreno_platform_driver = {
    // kgsl probe函数[见第2节]
	.probe = adreno_probe,
	.remove = adreno_remove,
    // device_driver
	.driver = {
		.name = "kgsl-3d",
        // 
		.pm = &adreno_pm_ops,
		.of_match_table = of_match_ptr(adreno_match_table),
	}
};

2. adreno_probe

static int adreno_probe(struct platform_device *pdev)
{
	struct component_match *match = NULL;

	adreno_add_gmu_components(&pdev->dev, &match);

	if (match)
		return component_master_add_with_match(&pdev->dev,
				&adreno_ops, match);
	else
        // 绑定adreno设备[见2.1节]
		return adreno_bind(&pdev->dev);
}

2.1 adreno_bind

static int adreno_bind(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	const struct adreno_gpu_core *gpucore;
	int ret;
	u32 chipid;

    // 判断GPU是否被禁用
	if (adreno_is_gpu_disabled(pdev)) {
		dev_err(&pdev->dev, "adreno: GPU is disabled on this device\n");
		return -ENODEV;
	}
    
    // 识别GPU型号[见2.2节]
	gpucore = adreno_identify_gpu(pdev, &chipid);
	if (IS_ERR(gpucore))
		return PTR_ERR(gpucore);

    // 调用2.5节中adreno_a6xx_gmu_gpudev定义的a6xx_gmu_device_probe
	ret = gpucore->gpudev->probe(pdev, chipid, gpucore);

	if (!ret) {
		struct kgsl_device *device = dev_get_drvdata(dev);

		device->pdev_loaded = true;
	}

	return ret;
}

2.2 adreno_identify_gpu

static const struct adreno_gpu_core *
adreno_identify_gpu(struct platform_device *pdev, u32 *chipid)
{
	const struct adreno_gpu_core *gpucore;

    // 解析dts文件qcom,chipid节点, 获取GPU型号
	if (adreno_get_chipid(pdev, chipid)) {
		dev_crit(&pdev->dev, "Unable to get the GPU chip ID\n");
		return ERR_PTR(-ENODEV);
	}
    
    // 根据GPU型号查找对应的adreno_gpu_core[见2.3节]
	gpucore = _get_gpu_core(pdev, chipid);
	if (!gpucore) {
		dev_crit(&pdev->dev, "Unknown GPU chip ID %8.8x\n", *chipid);
		return ERR_PTR(-ENODEV);
	}

	/*
	 * Identify non-longer supported targets and spins and print a helpful
	 * message
	 */
	if (gpucore->features & ADRENO_DEPRECATED) {
		if (gpucore->compatible)
			dev_err(&pdev->dev,
				"Support for GPU %s has been deprecated\n",
				gpucore->compatible);
		else
			dev_err(&pdev->dev,
				"Support for GPU %x.%d.%x.%d has been deprecated\n",
				gpucore->core, gpucore->major,
				gpucore->minor, gpucore->patchid);
		return ERR_PTR(-ENODEV);
	}

    // 返回adreno_gpu_core
	return gpucore;
}

2.3 _get_gpu_core

static const struct adreno_gpu_core *
_get_gpu_core(struct platform_device *pdev, unsigned int chipid)
{
    // GPU 系列号
	unsigned int core = ADRENO_CHIPID_CORE(chipid);
    // GPU 主版本号
	unsigned int major = ADRENO_CHIPID_MAJOR(chipid);
    // GPU 副版本号
	unsigned int minor = ADRENO_CHIPID_MINOR(chipid);
    // GPU patchid
	unsigned int patchid = ADRENO_CHIPID_PATCH(chipid);
	int i;
	struct device_node *node;

	/*
	 * When "qcom,gpu-models" is defined, use gpu model node to match
	 * on a compatible string, otherwise match using legacy way.
	 */
	node = adreno_get_gpu_model_node(pdev);
	if (!node || !of_find_property(node, "compatible", NULL))
		node = pdev->dev.of_node;

	/* Check to see if any of the entries match on a compatible string */
	for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++) {
		if (adreno_gpulist[i]->compatible &&
			of_device_is_compatible(node,
				adreno_gpulist[i]->compatible))
			return adreno_gpulist[i];
	}

    // 遍历adreno_gpulist并选择匹配的adreno_gpu_core:adreno_gpu_core_a640[见2.4节]
	for (i = 0; i < ARRAY_SIZE(adreno_gpulist); i++) {
		if (core == adreno_gpulist[i]->core &&
		    _rev_match(major, adreno_gpulist[i]->major) &&
		    _rev_match(minor, adreno_gpulist[i]->minor) &&
		    _rev_match(patchid, adreno_gpulist[i]->patchid))
			return adreno_gpulist[i];
	}

	return NULL;
}

2.4 adreno_gpu_core_a640

static const struct adreno_a6xx_core adreno_gpu_core_a640 = {
	.base = {
        // 版本
		DEFINE_ADRENO_REV(ADRENO_REV_A640, 6, 4, 0, ANY_ID),
        // 特性
		.features = ADRENO_RPMH | ADRENO_GPMU |
			ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT |
			ADRENO_IFPC | ADRENO_PREEMPTION,
        // adreno_gpudev:adreno_a6xx_gmu_gpudev[见2.5节]
		.gpudev = &adreno_a6xx_gmu_gpudev,
        // 默认的性能计数器
		.perfcounters = &adreno_a6xx_legacy_perfcounters,
		.gmem_size = SZ_1M, //Verified 1MB
		.bus_width = 32,
		.snapshot_size = 2 * SZ_1M,
	},
	.prim_fifo_threshold = 0x00200000,
	.gmu_major = 2,
	.gmu_minor = 0,
	.sqefw_name = "a630_sqe.fw",
	.gmufw_name = "a640_gmu.bin",
	.zap_name = "a640_zap",
	.hwcg = a640_hwcg_regs,
	.hwcg_count = ARRAY_SIZE(a640_hwcg_regs),
	.vbif = a640_vbif_regs,
	.vbif_count = ARRAY_SIZE(a640_vbif_regs),
	.hang_detect_cycles = 0xcfffff,
	.protected_regs = a630_protected_regs,
	.disable_tseskip = true,
	.highest_bank_bit = 15,
};

2.5 adreno_a6xx_gmu_gpudev

const struct adreno_gpudev adreno_a6xx_gmu_gpudev = {
	.reg_offsets = a6xx_register_offsets,
    // gmu probe函数
	.probe = a6xx_gmu_device_probe,
	.start = a6xx_start,
	.snapshot = a6xx_gmu_snapshot,
	.init = a6xx_init,
	.irq_handler = a6xx_irq_handler,
	.rb_start = a6xx_rb_start,
	.regulator_enable = a6xx_gmu_sptprac_enable,
	.regulator_disable = a6xx_gmu_sptprac_disable,
	.read_throttling_counters = a6xx_read_throttling_counters,
	.microcode_read = a6xx_microcode_read,
	.gpu_keepalive = a6xx_gpu_keepalive,
	.hw_isidle = a6xx_hw_isidle,
	.iommu_fault_block = a6xx_iommu_fault_block,
	.reset = a6xx_gmu_restart,
	.preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit,
	.preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit,
	.preemption_init = a6xx_preemption_init,
	.preemption_schedule = a6xx_preemption_schedule,
	.set_marker = a6xx_set_marker,
	.preemption_context_init = a6xx_preemption_context_init,
	.sptprac_is_on = a6xx_gmu_sptprac_is_on,
	.ccu_invalidate = a6xx_ccu_invalidate,
#ifdef CONFIG_QCOM_KGSL_CORESIGHT
	.coresight = {&a6xx_coresight, &a6xx_coresight_cx},
#endif
	.read_alwayson = a6xx_read_alwayson,
	.power_ops = &a6xx_gmu_power_ops,
};

2.6 a6xx_gmu_device_probe

int a6xx_gmu_device_probe(struct platform_device *pdev,
	u32 chipid, const struct adreno_gpu_core *gpucore)
{
	struct adreno_device *adreno_dev;
	struct kgsl_device *device;
	struct a6xx_device *a6xx_dev;
	int ret;

    // 创建a6xx_device
	a6xx_dev = devm_kzalloc(&pdev->dev, sizeof(*a6xx_dev),
			GFP_KERNEL);
	if (!a6xx_dev)
		return -ENOMEM;

    // 取a6xx_device的成员adreno_device
	adreno_dev = &a6xx_dev->adreno_dev;

    // gmu probe[见第3节]
	ret = a6xx_probe_common(pdev, adreno_dev, chipid, gpucore);
	if (ret)
		return ret;

    // 取adreno_device的成员kgsl_device
	device = KGSL_DEVICE(adreno_dev);

	INIT_WORK(&device->idle_check_ws, gmu_idle_check);

	timer_setup(&device->idle_timer, gmu_idle_timer, 0);

	adreno_dev->irq_mask = A6XX_INT_MASK;

	return 0;
}

3. a6xx_probe_common

int a6xx_probe_common(struct platform_device *pdev,
	struct	adreno_device *adreno_dev, u32 chipid,
	const struct adreno_gpu_core *gpucore)
{
	const struct adreno_gpudev *gpudev = gpucore->gpudev;

    // 初始化adreno_device
	adreno_dev->gpucore = gpucore;
	adreno_dev->chipid = chipid;

	adreno_reg_offset_init(gpudev->reg_offsets);

	adreno_dev->hwcg_enabled = true;

	adreno_dev->preempt.preempt_level = 1;
	adreno_dev->preempt.skipsaverestore = true;
	adreno_dev->preempt.usesgmem = true;

	/* Set the GPU busy counter for frequency scaling */
	adreno_dev->perfctr_pwr_lo = A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L;

	/* Set the counter for IFPC */
	if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC))
		adreno_dev->perfctr_ifpc_lo =
			A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L;

    // adreno_device probe[见第4节]
	return adreno_device_probe(pdev, adreno_dev);
}

4. adreno_device_probe

int adreno_device_probe(struct platform_device *pdev,
		struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct device *dev = &pdev->dev;
	unsigned int priv = 0;
	int status;
	u32 size;

	place_marker("M - DRIVER GPU Init");

	/* Initialize the adreno device structure */
    // 初始化adreno_device[见第5节]
	adreno_setup_device(adreno_dev);

	dev_set_drvdata(dev, device);

	device->pdev = pdev;

	adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);

	status = adreno_read_speed_bin(pdev);
	if (status < 0)
		return status;

	device->speed_bin = status;

    // 获取GPU寄存器物理地址和大小和GPU频率[见第6节]
	status = adreno_of_get_power(adreno_dev, pdev);
	if (status)
		return status;

	status = kgsl_bus_init(device, pdev);
	if (status)
		goto err;

	/*
	 * Bind the GMU components (if applicable) before doing the KGSL
	 * platform probe
	 */
	if (of_find_matching_node(dev->of_node, adreno_gmu_match)) {
		status = component_bind_all(dev, NULL);
		if (status) {
			kgsl_bus_close(device);
			return status;
		}
	}

	/*
	 * The SMMU APIs use unsigned long for virtual addresses which means
	 * that we cannot use 64 bit virtual addresses on a 32 bit kernel even
	 * though the hardware and the rest of the KGSL driver supports it.
	 */
	if (adreno_support_64bit(adreno_dev))
		kgsl_mmu_set_feature(device, KGSL_MMU_64BIT);

	/*
	 * Set the SMMU aperture on A6XX targets to use per-process pagetables.
	 */
	if (adreno_is_a6xx(adreno_dev))
		kgsl_mmu_set_feature(device, KGSL_MMU_SMMU_APERTURE);

	if (ADRENO_FEATURE(adreno_dev, ADRENO_IOCOHERENT))
		kgsl_mmu_set_feature(device, KGSL_MMU_IO_COHERENT);

	device->pwrctrl.bus_width = adreno_dev->gpucore->bus_width;

	device->mmu.secured = (IS_ENABLED(CONFIG_QCOM_SECURE_BUFFER) &&
		ADRENO_FEATURE(adreno_dev, ADRENO_CONTENT_PROTECTION));

	/* Probe the LLCC - this could return -EPROBE_DEFER */
	status = adreno_probe_llcc(adreno_dev, pdev);
	if (status)
		goto err;

	/*
	 * IF the GPU HTW slice was successsful set the MMU feature so the
	 * domain can set the appropriate attributes
	 */
	if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice))
		kgsl_mmu_set_feature(device, KGSL_MMU_LLCC_ENABLE);

    // [见第7节]
	status = kgsl_device_platform_probe(device);
	if (status)
		goto err;

	/* Probe for the optional CX_DBGC block */
	adreno_cx_dbgc_probe(device);

	/* Probe for the optional CX_MISC block */
	adreno_cx_misc_probe(device);

	adreno_isense_probe(device);

	/* Allocate the memstore for storing timestamps and other useful info */

	if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV))
		priv |= KGSL_MEMDESC_PRIVILEGED;

    // 分配kgsl_device全局共享的内存: 见"adreno源码系列之Gpu内存申请"
	device->memstore = kgsl_allocate_global(device,
		KGSL_MEMSTORE_SIZE, 0, 0, priv, "memstore");

	status = PTR_ERR_OR_ZERO(device->memstore);
	if (status) {
		kgsl_device_platform_remove(device);
		goto err;
	}

	/* Initialize the snapshot engine */
	size = adreno_dev->gpucore->snapshot_size;

	/*
	 * Use a default size if one wasn't specified, but print a warning so
	 * the developer knows to fix it
	 */

	if (WARN(!size, "The snapshot size was not specified in the gpucore\n"))
		size = SZ_1M;

	kgsl_device_snapshot_probe(device, size);

	adreno_debugfs_init(adreno_dev);
	adreno_profile_init(adreno_dev);

	adreno_sysfs_init(adreno_dev);

	kgsl_pwrscale_init(device, pdev, CONFIG_QCOM_ADRENO_DEFAULT_GOVERNOR);

	/* Initialize coresight for the target */
	adreno_coresight_init(adreno_dev);

#ifdef CONFIG_INPUT
	if (!device->pwrctrl.input_disable) {
		adreno_input_handler.private = device;
		/*
		 * It isn't fatal if we cannot register the input handler.  Sad,
		 * perhaps, but not fatal
		 */
		if (input_register_handler(&adreno_input_handler)) {
			adreno_input_handler.private = NULL;
			dev_err(device->dev,
				     "Unable to register the input handler\n");
		}
	}
#endif

	place_marker("M - DRIVER GPU Ready");

	return 0;
err:
	device->pdev = NULL;

	if (of_find_matching_node(dev->of_node, adreno_gmu_match))
		component_unbind_all(dev, NULL);

	kgsl_bus_close(device);

	return status;
}

5. adreno_setup_device

static void adreno_setup_device(struct adreno_device *adreno_dev)
{
	u32 i;

    // 初始化kgsl_device名称
	adreno_dev->dev.name = "kgsl-3d0";
    // 初始化kgsl_device的函数表[见5.1节]
	adreno_dev->dev.ftbl = &adreno_functable;

	init_completion(&adreno_dev->dev.hwaccess_gate);
	init_completion(&adreno_dev->dev.halt_gate);

	idr_init(&adreno_dev->dev.context_idr);

	mutex_init(&adreno_dev->dev.mutex);
	INIT_LIST_HEAD(&adreno_dev->dev.globals);

	/* Set the fault tolerance policy to replay, skip, throttle */
	adreno_dev->ft_policy = BIT(KGSL_FT_REPLAY) |
		BIT(KGSL_FT_SKIPCMD) | BIT(KGSL_FT_THROTTLE);

	/* Enable command timeouts by default */
	adreno_dev->long_ib_detect = true;

	INIT_WORK(&adreno_dev->input_work, adreno_input_work);

	INIT_LIST_HEAD(&adreno_dev->active_list);
	spin_lock_init(&adreno_dev->active_list_lock);

    // 初始化adreno_ringbuffer
	for (i = 0; i < ARRAY_SIZE(adreno_dev->ringbuffers); i++) {
		struct adreno_ringbuffer *rb = &adreno_dev->ringbuffers[i];

		INIT_LIST_HEAD(&rb->events.group);
	}

	/*
	 * Some GPUs needs UCHE GMEM base address to be minimum 0x100000
	 * and 1MB aligned. Configure UCHE GMEM base based on GMEM size
	 * and align it one 1MB. This needs to be done based on GMEM size
	 * because setting it to minimum value 0x100000 will result in RB
	 * and UCHE GMEM range overlap for GPUs with GMEM size >1MB.
	 */
	if (!adreno_is_a650_family(adreno_dev))
		adreno_dev->uche_gmem_base =
			ALIGN(adreno_dev->gpucore->gmem_size, SZ_1M);

}

5.1 adreno_functable

static const struct kgsl_functable adreno_functable = {
	/* Mandatory functions */
    // 读寄存器
	.regread = adreno_regread,
    // 写寄存器
	.regwrite = adreno_regwrite,
	.idle = adreno_idle,
	.suspend_context = adreno_suspend_context,
    // 打开/dev/kgsl-3d0
	.first_open = adreno_first_open,
    // 启动adreno
	.start = adreno_start,
	.stop = adreno_stop,
	.last_close = adreno_last_close,
	.getproperty = adreno_getproperty,
	.getproperty_compat = adreno_getproperty_compat,
	.waittimestamp = adreno_waittimestamp,
	.readtimestamp = adreno_readtimestamp,
	.queue_cmds = adreno_queue_cmds,
    // adreno ioctl列表
	.ioctl = adreno_ioctl,
	.compat_ioctl = adreno_compat_ioctl,
	.power_stats = adreno_power_stats,
	.gpuid = adreno_gpuid,
	.snapshot = adreno_snapshot,
    // adreno中断处理函数
	.irq_handler = adreno_irq_handler,
	.drain = adreno_drain,
	.device_private_create = adreno_device_private_create,
	.device_private_destroy = adreno_device_private_destroy,
	/* Optional functions */
    // 创建adreno_context
	.drawctxt_create = adreno_drawctxt_create,
	.drawctxt_detach = adreno_drawctxt_detach,
	.drawctxt_destroy = adreno_drawctxt_destroy,
	.drawctxt_dump = adreno_drawctxt_dump,
	.setproperty = adreno_setproperty,
	.setproperty_compat = adreno_setproperty_compat,
	.drawctxt_sched = adreno_drawctxt_sched,
	.resume = adreno_dispatcher_start,
	.regulator_enable = adreno_regulator_enable,
	.prepare_for_power_off = adreno_prepare_for_power_off,
	.regulator_disable = adreno_regulator_disable,
	.pwrlevel_change_settings = adreno_pwrlevel_change_settings,
	.regulator_disable_poll = adreno_regulator_disable_poll,
	.clk_set_options = adreno_clk_set_options,
	.gpu_model = adreno_gpu_model,
	.query_property_list = adreno_query_property_list,
	.is_hwcg_on = adreno_is_hwcg_on,
	.gpu_clock_set = adreno_gpu_clock_set,
	.gpu_bus_set = adreno_gpu_bus_set,
	.deassert_gbif_halt = adreno_deassert_gbif_halt,
};

6. adreno_of_get_power

static int adreno_of_get_power(struct adreno_device *adreno_dev,
		struct platform_device *pdev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct resource *res;
	int ret;

	/* Get starting physical address of device registers */
    // 获取GPU的kgsl_3d0_reg_memory寄存器起始物理地址和大小:dts中配置的0x2c00000和256k(0x40000)
	res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM,
		"kgsl_3d0_reg_memory");

	if (res == NULL) {
		dev_err(device->dev,
			     "platform_get_resource_byname failed\n");
		return -EINVAL;
	}
	if (res->start == 0 || resource_size(res) == 0) {
		dev_err(device->dev, "dev %d invalid register region\n",
			     device->id);
		return -EINVAL;
	}

    // kgsl_device保存kgsl_3d0_reg_memory寄存器的起始物理地址和大小
	device->reg_phys = res->start;
	device->reg_len = resource_size(res);

    // 解析dts中的qcom,gpu-pwrlevels节点获取GPU频率配置
	ret = adreno_of_get_pwrlevels(adreno_dev, pdev->dev.of_node);
	if (ret)
		return ret;

	l3_pwrlevel_probe(device, pdev->dev.of_node);

	device->pwrctrl.interval_timeout = CONFIG_QCOM_KGSL_IDLE_TIMEOUT;

	device->pwrctrl.minbw_timeout = 10;

	/* Set default bus control to true on all targets */
	device->pwrctrl.bus_control = true;

	device->pwrctrl.input_disable =
		of_property_read_bool(pdev->dev.of_node,
			"qcom,disable-wake-on-touch");

	return 0;
}

7. kgsl_device_platform_probe

int kgsl_device_platform_probe(struct kgsl_device *device)
{
	struct platform_device *pdev = device->pdev;
	int status = -EINVAL;

    // 创建kgsl_device对应的device结构体[见7.1节]
	status = _register_device(device);
	if (status)
		return status;

	/* Can return -EPROBE_DEFER */
    // 初始化kgsl_pwrctrl:见"adreno源码系列之kgsl_pwrctrl"
	status = kgsl_pwrctrl_init(device);
	if (status)
		goto error;

    // 申请访问GPU寄存器内存
	if (!devm_request_mem_region(&pdev->dev, device->reg_phys,
				device->reg_len, device->name)) {
		dev_err(device->dev, "request_mem_region failed\n");
		status = -ENODEV;
		goto error_pwrctrl_close;
	}

    // 将GPU寄存器物理内存映射到内核虚拟地址空间, 并返回内核虚拟地址空间起始地址
	device->reg_virt = devm_ioremap(&pdev->dev, device->reg_phys,
					device->reg_len);

	if (device->reg_virt == NULL) {
		dev_err(device->dev, "ioremap failed\n");
		status = -ENODEV;
		goto error_pwrctrl_close;
	}

    // 注册kgsl中断处理函数kgsl_irq_handler: 见"adreno源码系列之kgsl_irq_handler"
	status = kgsl_request_irq(pdev, "kgsl_3d0_irq",
		kgsl_irq_handler, device);
	if (status < 0)
		goto error_pwrctrl_close;

	device->pwrctrl.interrupt_num = status;
	disable_irq(device->pwrctrl.interrupt_num);

	rwlock_init(&device->context_lock);
	spin_lock_init(&device->submit_lock);

	idr_init(&device->timelines);
	spin_lock_init(&device->timelines_lock);

#if defined(OPLUS_FEATURE_SCHED_ASSIST) && defined(CONFIG_OPLUS_FEATURE_SCHED_ASSIST)
	if (sysctl_sched_assist_enabled)
		device->events_wq = alloc_workqueue("kgsl-events",
			WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI | WQ_UX, 0);
	else
		device->events_wq = alloc_workqueue("kgsl-events",
			WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0);
#else
    // 分配一个名为kgsl-events的工作队列
	device->events_wq = alloc_workqueue("kgsl-events",
		WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS | WQ_HIGHPRI, 0);
#endif

	if (!device->events_wq) {
		dev_err(device->dev, "Failed to allocate events workqueue\n");
		status = -ENOMEM;
		goto error_pwrctrl_close;
	}

	/* This can return -EPROBE_DEFER */
    // kgsl_mmu: 见"adreno源码系列之kgsl_mmu"
	status = kgsl_mmu_probe(device);
	if (status != 0)
		goto error_pwrctrl_close;

    // 创建并初始化/sys/kernel/debug/kgsl/kgsl-3d0
	kgsl_device_debugfs_init(device);

	dma_set_coherent_mask(&pdev->dev, KGSL_DMA_BIT_MASK);

	/* Set up the GPU events for the device */
	kgsl_device_events_probe(device);

	/* Initialize common sysfs entries */
	kgsl_pwrctrl_init_sysfs(device);

	return 0;

error_pwrctrl_close:
	if (device->events_wq) {
		destroy_workqueue(device->events_wq);
		device->events_wq = NULL;
	}

	kgsl_pwrctrl_close(device);
error:
	_unregister_device(device);
	return status;
}

7.1 _register_device

static int _register_device(struct kgsl_device *device)
{
	static u64 dma_mask = DMA_BIT_MASK(64);
	static struct device_dma_parameters dma_parms;
	int minor, ret;
	dev_t dev;

	/* Find a minor for the device */
	mutex_lock(&kgsl_driver.devlock);
	for (minor = 0; minor < ARRAY_SIZE(kgsl_driver.devp); minor++) {
		if (kgsl_driver.devp[minor] == NULL) {
			kgsl_driver.devp[minor] = device;
			break;
		}
	}
	mutex_unlock(&kgsl_driver.devlock);

	if (minor == ARRAY_SIZE(kgsl_driver.devp)) {
		pr_err("kgsl: minor devices exhausted\n");
		return -ENODEV;
	}

	/* Create the device */
	dev = MKDEV(MAJOR(kgsl_driver.major), minor);
    // 创建device
	device->dev = device_create(kgsl_driver.class,
				    &device->pdev->dev,
				    dev, device,
				    device->name);

	if (IS_ERR(device->dev)) {
		mutex_lock(&kgsl_driver.devlock);
		kgsl_driver.devp[minor] = NULL;
		mutex_unlock(&kgsl_driver.devlock);
		ret = PTR_ERR(device->dev);
		pr_err("kgsl: device_create(%s): %d\n", device->name, ret);
		return ret;
	}

	device->dev->dma_mask = &dma_mask;
	device->dev->dma_parms = &dma_parms;

	dma_set_max_seg_size(device->dev, DMA_BIT_MASK(32));

    // 初始化device的dma_map_ops为NULL
	set_dma_ops(device->dev, NULL);

    // 初始化/sys/kernel/gpu
	if (kobject_init_and_add(&device->gpu_sysfs_kobj, &kgsl_gpu_sysfs_ktype,
		kernel_kobj, "gpu"))
		dev_err(device->dev, "Unable to add sysfs for gpu\n");

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值