在启动参数中传入radeon.hard_reset=1这一参数,实际上是给模块参数赋了值,模块参数所在文件及代码为:
drivers/gpu/drm/radeon/radeon_drv.c
int radeon_hard_reset = 0;
MODULE_PARM_DESC(hard_reset, "PCI config reset (1 = force enable, 0 = disable (default))");
module_param_named(hard_reset, radeon_hard_reset, int, 0444);
与radeo_hard_reset这个变量相关的代码共有几处,
分别为:
1. drivers/gpu/drm/radeon/cik.c,int cik_asic_reset(struct radeon_device *rdev, bool hard)函数;
2. drivers/gpu/drm/radeon/evergreen.c,int evergreen_asic_reset(struct radeon_device *rdev, bool hard)函数;
3. drivers/gpu/drm/radeon/r600.c,int r600_asic_reset(struct radeon_device *rdev, bool hard)函数;
4. drivers/gpu/drm/radeon/si.c,int si_asic_reset(struct radeon_device *rdev, bool hard)
实际上几处的处理都是大同小异,这里以drivers/gpu/drm/radeon/r600.c中的r600asic_reset函数为例进行详细分析。源码如下:
int r600_asic_reset(struct radeon_device *rdev, bool hard)
{
u32 reset_mask;
if (hard) {
r600_gpu_pci_config_reset(rdev);
return 0;
}
reset_mask = r600_gpu_check_soft_reset(rdev);
if (reset_mask)
r600_set_bios_scratch_engine_hung(rdev, true);
/* try soft reset */
r600_gpu_soft_reset(rdev, reset_mask);
reset_mask = r600_gpu_check_soft_reset(rdev);
/* try pci config reset */
if (reset_mask && radeon_hard_reset)
r600_gpu_pci_config_reset(rdev);
reset_mask = r600_gpu_check_soft_reset(rdev);
if (!reset_mask)
r600_set_bios_scratch_engine_hung(rdev, false);
return 0;
}
关键的也是radeon_hard_reset影响的代码位于同文件中,其实就在上边,源码如下:
static void r600_gpu_pci_config_reset(struct radeon_device *rdev)
{
struct rv515_mc_save save;
u32 tmp, i;
dev_info(rdev->dev, "GPU pci config reset\n");
/* disable dpm? */
/* Disable CP parsing/prefetching */
if (rdev->family >= CHIP_RV770)
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1) | S_0086D8_CP_PFP_HALT(1));
else
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
/* disable the RLC */
WREG32(RLC_CNTL, 0);
/* Disable DMA */
tmp = RREG32(DMA_RB_CNTL);
tmp &= ~DMA_RB_ENABLE;
WREG32(DMA_RB_CNTL, tmp);
mdelay(50);
/* set mclk/sclk to bypass */
if (rdev->family >= CHIP_RV770)
rv770_set_clk_bypass_mode(rdev);
/* disable BM */
pci_clear_master(rdev->pdev);
/* disable mem access */
rv515_mc_stop(rdev, &save);
if (r600_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
/* BIF reset workaround. Not sure if this is needed on 6xx */
tmp = RREG32(BUS_CNTL);
tmp |= VGA_COHE_SPEC_TIMER_DIS;
WREG32(BUS_CNTL, tmp);
tmp = RREG32(BIF_SCRATCH0);
/* reset */
radeon_pci_config_reset(rdev);
mdelay(1);
/* BIF reset workaround. Not sure if this is needed on 6xx */
tmp = SOFT_RESET_BIF;
WREG32(SRBM_SOFT_RESET, tmp);
mdelay(1);
WREG32(SRBM_SOFT_RESET, 0);
/* wait for asic to come out of reset */
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(CONFIG_MEMSIZE) != 0xffffffff)
break;
udelay(1);
}
}
drivers/gpu/drm/radeon/r600d.h中:
#define R_0086D8_CP_ME_CNTL 0x86D8
#define S_0086D8_CP_PFP_HALT(x) (((x) & 1)<<26)
#define C_0086D8_CP_PFP_HALT(x) ((x) & 0xFBFFFFFF)
#define S_0086D8_CP_ME_HALT(x) (((x) & 1)<<28)
#define C_0086D8_CP_ME_HALT(x) ((x) & 0xEFFFFFFF)