• 这里的load本意就是将设备hw初始化.先做admgpu实例化,再amdgpu_device_init对应CHIP初始化.接着做了amdgpu_acpi_init,主要需要理解的是amdgpu_device_ini
  • 值得注意的是,到现在flags还是pci注册时传下来的,没发生变化

实例化adev.

amdgpu_device_init

这里主要有几点:

  1. adev->flags = flags;保存了设备初始化的flags
  2. adev->asic_type = flags & AMD_ASIC_MASK; 用来给不同设备挂载不同asic回调的掩码.最多asic有0xffff
  3. 设备操作的超时时间adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT;100ms TP:使用qemu时间翻倍
  4. 用到最大的GTT内存adev->gmc.gart_size = 512 * 1024 * 1024; 默认512M,这个GTT,会给GPU和CPU同时使用,所以会按照不同
  5. pagesize进行计算页数,在后续mc_init可能重新设置
  6. gpu侧vm相关
adev->num_rings = 0;
    adev->mman.buffer_funcs = NULL;
    adev->mman.buffer_funcs_ring = NULL;
    adev->vm_manager.vm_pte_funcs = NULL;
    adev->vm_manager.vm_pte_num_rings = 0;
    adev->gmc.gmc_funcs = NULL;
  1. fence同步(ringbuffer)和pipe位图
adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS);
   bitmap_zero(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
  1. 对访问显卡上的寄存器操作函数设置默认函数
  2. 各种临界资源的互斥锁初始化
/* mutex initialization are all done here so we
     * can recall function without having locking issues */
    atomic_set(&adev->irq.ih.lock, 0);
    mutex_init(&adev->firmware.mutex);
    mutex_init(&adev->pm.mutex);
    mutex_init(&adev->gfx.gpu_clock_mutex);
    mutex_init(&adev->srbm_mutex);
    mutex_init(&adev->gfx.pipe_reserve_mutex);
    mutex_init(&adev->grbm_idx_mutex);
    mutex_init(&adev->mn_lock);
    mutex_init(&adev->virt.vf_errors.lock);
    hash_init(adev->mn_hash);
    mutex_init(&adev->lock_reset);

    spin_lock_init(&adev->mmio_idx_lock);
    spin_lock_init(&adev->smc_idx_lock);
    spin_lock_init(&adev->pcie_idx_lock);
    spin_lock_init(&adev->uvd_ctx_idx_lock);
    spin_lock_init(&adev->didt_idx_lock);
    spin_lock_init(&adev->gc_cac_idx_lock);
    spin_lock_init(&adev->se_cac_idx_lock);
    spin_lock_init(&adev->audio_endpt_idx_lock);
    spin_lock_init(&adev->mm_stats.lock);

在未初始化前,判断管理参数是不是正确,这里主要判断gttsize,gartsize,jobs,vmsize, smu-prvsize等等
初始化shadow资源链表.和ringbuffer链表
9. 在device的所有ip初始化(hw, sw)最后,调用late时,调用这个延时队列.看看ib_test能不能正常用

INIT_DELAYED_WORK(&adev->late_init_work, amdgpu_device_ip_late_init_func_handler);

映射操作寄存器的mmio, 我们现在应该用的bar2, 后期牛的显卡都用bar5了

/* Registers mapping */
    /* TODO: block userspace mapping of io register */
    if (adev->asic_type >= CHIP_BONAIRE) {
        adev->rmmio_base = pci_resource_start(adev->pdev, 5);
        adev->rmmio_size = pci_resource_len(adev->pdev, 5);
    } else {
        adev->rmmio_base = pci_resource_start(adev->pdev, 2);
        adev->rmmio_size = pci_resource_len(adev->pdev, 2);
    }

    adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size);
    if (adev->rmmio == NULL) {
        return -ENOMEM;
    }
    DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)adev->rmmio_base);
    DRM_INFO("register mmio size: %u\n", (unsigned)adev->rmmio_size);

初始化doorbell,不知道干啥. 后续补上
io端口映射. cardinfo可能会使用io访问ep; DEVICE_COUNT_RESOURCE是17
amdgpu_device_get_pcie_info,获取当前设备的lane和gen-speed
狠角色来了.ip初始化 amdgpu_device_ip_early_init ,后续跟进这部分分析
挂接vgaswitcheroo的操作
amdgpu_get_bios获取vbios
amdgpu_atombios_init初始化atobios的操作函数和相关info,这里会注册一个关于vbios的节点.获取vbiosversion
dev_attr_vbios_version的dev_attr是用宏拼接的? 后续有机会再分析
adev->is_atom_fw vega10以后的card会使用.这个变量的赋值是在get_vbios中赋值的
amdgpu_fence_driver_init 挂接fence的debufs节点
drm_mode_config_init 初始化drm的mode_info
amdgpu_device_ip_init 开始对sw_init和hw_init,后续分析
adev->accel_working 初始化完,标记硬件加速可以用了
amdgpu_ib_pool_init , (Indirect Buffer) ringbuffer的pool初始化,在GTT的
amdgpu_fbdev_init 使用fb_helper初始化fb
amdgpu_pm_sysfs_init电源管理sysfs注册
amdgpu_debugfs_gem_init对amdgpu的GEM管理器注册debugfs
amdgpu_debugfs_regs_init注册card的寄存器debugfs
amdgpu_debugfs_firmware_init 注册firmware的显示.
amdgpu_debugfs_init注册基本card管理节点,有vbios数据打印,evict_gem,amdgpu_test_ib,evict_gtt
amdgpu_testing调试开关.驱动ip初始化完成,如果在bootargs里面加了amdgpu.test=1 就会做test_move. 做基本拷贝工作.amdgpu_test_moves是可以做学习bo_move的切口点,理解内存显存移动的和page管理
amdgpu_benchmarking 调试开关. 驱动层做gpu的bench测试. bootarg写测试选项. 可以改进,弄成bitmap的形式,多项测试
amdgpu_device_ip_late_init ip初始化最后一步.调用延时工作队列,做ib测试