linux内核radeon gpu源码解析3 —— Radeon初始化

葛智敏
2023-12-01

解析DRM代码,以从底层介绍显卡驱动的初始化过程,显卡类型是AMD的radeon r600以后的系列显卡。基本的过程就是驱动载入,硬件初始化,设置硬件独立的模块(如内存管理器),设置显示(分辨率等)。 代码如下:

drivers/gpu/drm/radeon/radeon_drv.c

module_init(radeon_init);
module_exit(radeon_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");
static int __init radeon_init(void)
{
	if (vgacon_text_force() && radeon_modeset == -1) {
		DRM_INFO("VGACON disable radeon kernel modesetting.\n");
		radeon_modeset = 0;
	}
	/* set to modesetting by default if not nomodeset */
	if (radeon_modeset == -1)
		radeon_modeset = 1;

	if (radeon_modeset == 1) {
		DRM_INFO("radeon kernel modesetting enabled.\n");
		driver = &kms_driver;
		pdriver = &radeon_kms_pci_driver;
		driver->driver_features |= DRIVER_MODESET;
		driver->num_ioctls = radeon_max_kms_ioctl;
		radeon_register_atpx_handler();

	} else {
		DRM_ERROR("No UMS support in radeon module!\n");
		return -EINVAL;
	}

	return pci_register_driver(pdriver);
}

static void __exit radeon_exit(void)
{
	pci_unregister_driver(pdriver);
	radeon_unregister_atpx_handler();
}

重点说一下这行代码:driver->driver_features |= DRIVER_MODESET;。driver指针指向了&kms_driver,这一句的意思是给kms_driver.driver_features添加上DRIVER_MODESET标志位,以告知DRM Coce当前驱动支持modesetting操作。

radeon_init函数中调用pci_register_driver(pdriver)注册pdriver,pdriver实际指向了radeon_kms_pci_driver,初始化内容如下: 

static struct drm_driver *driver;
static struct pci_driver *pdriver;
static struct pci_driver radeon_kms_pci_driver = {
	.name = DRIVER_NAME,
	.id_table = pciidlist,
	.probe = radeon_pci_probe,
	.remove = radeon_pci_remove,
	.shutdown = radeon_pci_shutdown,
	.driver.pm = &radeon_pm_ops,
};

驱动和设备匹配之后调用radeon_pci_probe,源码如下:

static int radeon_pci_probe(struct pci_dev *pdev,
			    const struct pci_device_id *ent)
{
	unsigned long flags = 0;
	int ret;

	if (!ent)
		return -ENODEV; /* Avoid NULL-ptr deref in drm_get_pci_dev */

	flags = ent->driver_data;

	if (!radeon_si_support) {
		switch (flags & RADEON_FAMILY_MASK) {
		case CHIP_TAHITI:
		case CHIP_PITCAIRN:
		case CHIP_VERDE:
		case CHIP_OLAND:
		case CHIP_HAINAN:
			dev_info(&pdev->dev,
				 "SI support disabled by module param\n");
			return -ENODEV;
		}
	}
	if (!radeon_cik_support) {
		switch (flags & RADEON_FAMILY_MASK) {
		case CHIP_KAVERI:
		case CHIP_BONAIRE:
		case CHIP_HAWAII:
		case CHIP_KABINI:
		case CHIP_MULLINS:
			dev_info(&pdev->dev,
				 "CIK support disabled by module param\n");
			return -ENODEV;
		}
	}

	if (vga_switcheroo_client_probe_defer(pdev))
		return -EPROBE_DEFER;

	/* Get rid of things like offb */
	ret = radeon_kick_out_firmware_fb(pdev);
	if (ret)
		return ret;

	return drm_get_pci_dev(pdev, ent, &kms_driver);
}

radeon_si_support和radeon_cik_support由启动参数得来,在/etc/default/grub文件中的GRUB_CMDLINE_LINUX_DEFAULT=一行可以添加诸如"modprobe.blacklist=radeon radeon.si_support=1 radeon.cik_support=1"的语句,其中的si_support和cik_support实际上就是设置了这里的radeon_si_support和radeon_cik_support。两个模块参数的初始化代码如下:

int radeon_si_support = 1;
MODULE_PARM_DESC(si_support, "SI support (1 = enabled (default), 0 = disabled)");
module_param_named(si_support, radeon_si_support, int, 0444);

int radeon_cik_support = 1;
MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled)");
module_param_named(cik_support, radeon_cik_support, int, 0444);

radeon_pci_probe函数最后调用drm_get_pci_dev(pdev, ent, &kms_driver),kms_driver的初始化内容如下:

static struct drm_driver kms_driver = {
	.driver_features =
	    DRIVER_USE_AGP |
	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
	    DRIVER_PRIME | DRIVER_RENDER,
	.load = radeon_driver_load_kms,
	.open = radeon_driver_open_kms,
	.postclose = radeon_driver_postclose_kms,
	.lastclose = radeon_driver_lastclose_kms,
	.unload = radeon_driver_unload_kms,
	.get_vblank_counter = radeon_get_vblank_counter_kms,
	.enable_vblank = radeon_enable_vblank_kms,
	.disable_vblank = radeon_disable_vblank_kms,
	.get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
	.get_scanout_position = radeon_get_crtc_scanout_position,
	.irq_preinstall = radeon_driver_irq_preinstall_kms,
	.irq_postinstall = radeon_driver_irq_postinstall_kms,
	.irq_uninstall = radeon_driver_irq_uninstall_kms,
	.irq_handler = radeon_driver_irq_handler_kms,
	.ioctls = radeon_ioctls_kms,
	.gem_free_object_unlocked = radeon_gem_object_free,
	.gem_open_object = radeon_gem_object_open,
	.gem_close_object = radeon_gem_object_close,
	.dumb_create = radeon_mode_dumb_create,
	.dumb_map_offset = radeon_mode_dumb_mmap,
	.fops = &radeon_driver_kms_fops,

	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_export = radeon_gem_prime_export,
	.gem_prime_import = drm_gem_prime_import,
	.gem_prime_pin = radeon_gem_prime_pin,
	.gem_prime_unpin = radeon_gem_prime_unpin,
	.gem_prime_res_obj = radeon_gem_prime_res_obj,
	.gem_prime_get_sg_table = radeon_gem_prime_get_sg_table,
	.gem_prime_import_sg_table = radeon_gem_prime_import_sg_table,
	.gem_prime_vmap = radeon_gem_prime_vmap,
	.gem_prime_vunmap = radeon_gem_prime_vunmap,

	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = KMS_DRIVER_MAJOR,
	.minor = KMS_DRIVER_MINOR,
	.patchlevel = KMS_DRIVER_PATCHLEVEL,
};

drm_get_pci_dev函数代码如下:

drivers/gpu/drm/drm_pci.c

/**
 * drm_get_pci_dev - Register a PCI device with the DRM subsystem
 * @pdev: PCI device
 * @ent: entry from the PCI ID table that matches @pdev
 * @driver: DRM device driver
 *
 * Attempt to gets inter module "drm" information. If we are first
 * then register the character device and inter module information.
 * Try and register, if we fail to register, backout previous work.
 *
 * NOTE: This function is deprecated, please use drm_dev_alloc() and
 * drm_dev_register() instead and remove your &drm_driver.load callback.
 *
 * Return: 0 on success or a negative error code on failure.
 */
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
		    struct drm_driver *driver)
{
	struct drm_device *dev;
	int ret;

	DRM_DEBUG("\n");

	dev = drm_dev_alloc(driver, &pdev->dev);
	if (IS_ERR(dev))
		return PTR_ERR(dev);

	ret = pci_enable_device(pdev);
	if (ret)
		goto err_free;

	dev->pdev = pdev;
#ifdef __alpha__
	dev->hose = pdev->sysdata;
#endif

	if (drm_core_check_feature(dev, DRIVER_MODESET))
		pci_set_drvdata(pdev, dev);

	drm_pci_agp_init(dev);

	ret = drm_dev_register(dev, ent->driver_data);
	if (ret)
		goto err_agp;

	/* No locking needed since shadow-attach is single-threaded since it may
	 * only be called from the per-driver module init hook. */
	if (drm_core_check_feature(dev, DRIVER_LEGACY))
		list_add_tail(&dev->legacy_dev_list, &driver->legacy_dev_list);

	return 0;

err_agp:
	drm_pci_agp_destroy(dev);
	pci_disable_device(pdev);
err_free:
	drm_dev_put(dev);
	return ret;
}
EXPORT_SYMBOL(drm_get_pci_dev);

这是一个比较关键的函数,重点讲一下。不过这一篇的内容比较多了,留在下一篇详细说明吧。

 类似资料: