diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_device.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 257 | 
1 files changed, 181 insertions, 76 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 16cb8792b1e..697add2cd4e 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -98,9 +98,20 @@ static const char radeon_family_name[][16] = {  	"BONAIRE",  	"KAVERI",  	"KABINI", +	"HAWAII", +	"MULLINS",  	"LAST",  }; +bool radeon_is_px(struct drm_device *dev) +{ +	struct radeon_device *rdev = dev->dev_private; + +	if (rdev->flags & RADEON_IS_PX) +		return true; +	return false; +} +  /**   * radeon_program_register_sequence - program an array of registers.   * @@ -137,6 +148,11 @@ void radeon_program_register_sequence(struct radeon_device *rdev,  	}  } +void radeon_pci_config_reset(struct radeon_device *rdev) +{ +	pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA); +} +  /**   * radeon_surface_init - Clear GPU surface registers.   * @@ -242,30 +258,25 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)   * Init doorbell driver information (CIK)   * Returns 0 on success, error on failure.   */ -int radeon_doorbell_init(struct radeon_device *rdev) +static int radeon_doorbell_init(struct radeon_device *rdev)  { -	int i; -  	/* doorbell bar mapping */  	rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);  	rdev->doorbell.size = pci_resource_len(rdev->pdev, 2); -	/* limit to 4 MB for now */ -	if (rdev->doorbell.size > (4 * 1024 * 1024)) -		rdev->doorbell.size = 4 * 1024 * 1024; +	rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS); +	if (rdev->doorbell.num_doorbells == 0) +		return -EINVAL; -	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size); +	rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32));  	if (rdev->doorbell.ptr == NULL) {  		return -ENOMEM;  	}  	DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);  	DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size); -	rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE; +	memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used)); -	for (i = 0; i < rdev->doorbell.num_pages; i++) { -		rdev->doorbell.free[i] = true; -	}  	return 0;  } @@ -276,47 +287,45 @@ int radeon_doorbell_init(struct radeon_device *rdev)   *   * Tear down doorbell driver information (CIK)   */ -void radeon_doorbell_fini(struct radeon_device *rdev) +static void radeon_doorbell_fini(struct radeon_device *rdev)  {  	iounmap(rdev->doorbell.ptr);  	rdev->doorbell.ptr = NULL;  }  /** - * radeon_doorbell_get - Allocate a doorbell page + * radeon_doorbell_get - Allocate a doorbell entry   *   * @rdev: radeon_device pointer - * @doorbell: doorbell page number + * @doorbell: doorbell index   * - * Allocate a doorbell page for use by the driver (all asics). + * Allocate a doorbell for use by the driver (all asics).   * Returns 0 on success or -EINVAL on failure.   */  int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)  { -	int i; - -	for (i = 0; i < rdev->doorbell.num_pages; i++) { -		if (rdev->doorbell.free[i]) { -			rdev->doorbell.free[i] = false; -			*doorbell = i; -			return 0; -		} +	unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells); +	if (offset < rdev->doorbell.num_doorbells) { +		__set_bit(offset, rdev->doorbell.used); +		*doorbell = offset; +		return 0; +	} else { +		return -EINVAL;  	} -	return -EINVAL;  }  /** - * radeon_doorbell_free - Free a doorbell page + * radeon_doorbell_free - Free a doorbell entry   *   * @rdev: radeon_device pointer - * @doorbell: doorbell page number + * @doorbell: doorbell index   * - * Free a doorbell page allocated for use by the driver (all asics) + * Free a doorbell allocated for use by the driver (all asics)   */  void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)  { -	if (doorbell < rdev->doorbell.num_pages) -		rdev->doorbell.free[doorbell] = true; +	if (doorbell < rdev->doorbell.num_doorbells) +		__clear_bit(doorbell, rdev->doorbell.used);  }  /* @@ -1043,6 +1052,43 @@ static void radeon_check_arguments(struct radeon_device *rdev)  		radeon_agpmode = 0;  		break;  	} + +	if (!radeon_check_pot_argument(radeon_vm_size)) { +		dev_warn(rdev->dev, "VM size (%d) must be a power of 2\n", +			 radeon_vm_size); +		radeon_vm_size = 4; +	} + +	if (radeon_vm_size < 1) { +		dev_warn(rdev->dev, "VM size (%d) to small, min is 1GB\n", +			 radeon_vm_size); +		radeon_vm_size = 4; +	} + +       /* +        * Max GPUVM size for Cayman, SI and CI are 40 bits. +        */ +	if (radeon_vm_size > 1024) { +		dev_warn(rdev->dev, "VM size (%d) too large, max is 1TB\n", +			 radeon_vm_size); +		radeon_vm_size = 4; +	} + +	/* defines number of bits in page table versus page directory, +	 * a page is 4KB so we have 12 bits offset, minimum 9 bits in the +	 * page table and the remaining bits are in the page directory */ +	if (radeon_vm_block_size < 9) { +		dev_warn(rdev->dev, "VM page table size (%d) too small\n", +			 radeon_vm_block_size); +		radeon_vm_block_size = 9; +	} + +	if (radeon_vm_block_size > 24 || +	    (radeon_vm_size * 1024) < (1ull << radeon_vm_block_size)) { +		dev_warn(rdev->dev, "VM page table size (%d) too large\n", +			 radeon_vm_block_size); +		radeon_vm_block_size = 9; +	}  }  /** @@ -1076,7 +1122,10 @@ static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev)  static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)  {  	struct drm_device *dev = pci_get_drvdata(pdev); -	pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; + +	if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF) +		return; +  	if (state == VGA_SWITCHEROO_ON) {  		unsigned d3_delay = dev->pdev->d3_delay; @@ -1087,7 +1136,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  		if (d3_delay < 20 && radeon_switcheroo_quirk_long_wakeup(pdev))  			dev->pdev->d3_delay = 20; -		radeon_resume_kms(dev); +		radeon_resume_kms(dev, true, true);  		dev->pdev->d3_delay = d3_delay; @@ -1097,7 +1146,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  		printk(KERN_INFO "radeon: switched off\n");  		drm_kms_helper_poll_disable(dev);  		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; -		radeon_suspend_kms(dev, pmm); +		radeon_suspend_kms(dev, true, true);  		dev->switch_power_state = DRM_SWITCH_POWER_OFF;  	}  } @@ -1114,12 +1163,13 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero  static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)  {  	struct drm_device *dev = pci_get_drvdata(pdev); -	bool can_switch; -	spin_lock(&dev->count_lock); -	can_switch = (dev->open_count == 0); -	spin_unlock(&dev->count_lock); -	return can_switch; +	/* +	 * FIXME: open_count is protected by drm_global_mutex but that would lead to +	 * locking inversion with the driver load path. And the access here is +	 * completely racy anyway. So don't bother with locking for now. +	 */ +	return dev->open_count == 0;  }  static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { @@ -1147,6 +1197,7 @@ int radeon_device_init(struct radeon_device *rdev,  {  	int r, i;  	int dma_bits; +	bool runtime = false;  	rdev->shutdown = false;  	rdev->dev = &pdev->dev; @@ -1182,20 +1233,17 @@ int radeon_device_init(struct radeon_device *rdev,  	r = radeon_gem_init(rdev);  	if (r)  		return r; -	/* initialize vm here */ -	mutex_init(&rdev->vm_manager.lock); + +	radeon_check_arguments(rdev);  	/* Adjust VM size here. -	 * Currently set to 4GB ((1 << 20) 4k pages). -	 * Max GPUVM size for cayman and SI is 40 bits. +	 * Max GPUVM size for cayman+ is 40 bits.  	 */ -	rdev->vm_manager.max_pfn = 1 << 20; -	INIT_LIST_HEAD(&rdev->vm_manager.lru_vm); +	rdev->vm_manager.max_pfn = radeon_vm_size << 18;  	/* Set asic functions */  	r = radeon_asic_init(rdev);  	if (r)  		return r; -	radeon_check_arguments(rdev);  	/* all of the newer IGP chips have an internal gart  	 * However some rs4xx report as AGP, so remove that here. @@ -1249,6 +1297,17 @@ int radeon_device_init(struct radeon_device *rdev,  	/* Registers mapping */  	/* TODO: block userspace mapping of io register */  	spin_lock_init(&rdev->mmio_idx_lock); +	spin_lock_init(&rdev->smc_idx_lock); +	spin_lock_init(&rdev->pll_idx_lock); +	spin_lock_init(&rdev->mc_idx_lock); +	spin_lock_init(&rdev->pcie_idx_lock); +	spin_lock_init(&rdev->pciep_idx_lock); +	spin_lock_init(&rdev->pif_idx_lock); +	spin_lock_init(&rdev->cg_idx_lock); +	spin_lock_init(&rdev->uvd_idx_lock); +	spin_lock_init(&rdev->rcu_idx_lock); +	spin_lock_init(&rdev->didt_idx_lock); +	spin_lock_init(&rdev->end_idx_lock);  	if (rdev->family >= CHIP_BONAIRE) {  		rdev->rmmio_base = pci_resource_start(rdev->pdev, 5);  		rdev->rmmio_size = pci_resource_len(rdev->pdev, 5); @@ -1282,7 +1341,12 @@ int radeon_device_init(struct radeon_device *rdev,  	/* this will fail for cards that aren't VGA class devices, just  	 * ignore it */  	vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); -	vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, false); + +	if (rdev->flags & RADEON_IS_PX) +		runtime = true; +	vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); +	if (runtime) +		vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain);  	r = radeon_init(rdev);  	if (r) @@ -1308,14 +1372,24 @@ int radeon_device_init(struct radeon_device *rdev,  		if (r)  			return r;  	} +  	if ((radeon_testing & 1)) { -		radeon_test_moves(rdev); +		if (rdev->accel_working) +			radeon_test_moves(rdev); +		else +			DRM_INFO("radeon: acceleration disabled, skipping move tests\n");  	}  	if ((radeon_testing & 2)) { -		radeon_test_syncing(rdev); +		if (rdev->accel_working) +			radeon_test_syncing(rdev); +		else +			DRM_INFO("radeon: acceleration disabled, skipping sync tests\n");  	}  	if (radeon_benchmarking) { -		radeon_benchmark(rdev, radeon_benchmarking); +		if (rdev->accel_working) +			radeon_benchmark(rdev, radeon_benchmarking); +		else +			DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n");  	}  	return 0;  } @@ -1363,7 +1437,7 @@ void radeon_device_fini(struct radeon_device *rdev)   * Returns 0 for success or an error on failure.   * Called at driver suspend.   */ -int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) +int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)  {  	struct radeon_device *rdev;  	struct drm_crtc *crtc; @@ -1374,9 +1448,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	if (dev == NULL || dev->dev_private == NULL) {  		return -ENODEV;  	} -	if (state.event == PM_EVENT_PRETHAW) { -		return 0; -	} +  	rdev = dev->dev_private;  	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1391,7 +1463,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	/* unpin the front buffers */  	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { -		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); +		struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb);  		struct radeon_bo *robj;  		if (rfb == NULL || rfb->obj == NULL) { @@ -1410,10 +1482,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	/* evict vram memory */  	radeon_bo_evict_vram(rdev); -	mutex_lock(&rdev->ring_lock);  	/* wait for gpu to finish processing current batch */  	for (i = 0; i < RADEON_NUM_RINGS; i++) { -		r = radeon_fence_wait_empty_locked(rdev, i); +		r = radeon_fence_wait_empty(rdev, i);  		if (r) {  			/* delay GPU reset to resume */  			force_completion = true; @@ -1422,11 +1493,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	if (force_completion) {  		radeon_fence_driver_force_completion(rdev);  	} -	mutex_unlock(&rdev->ring_lock);  	radeon_save_bios_scratch_regs(rdev); -	radeon_pm_suspend(rdev);  	radeon_suspend(rdev);  	radeon_hpd_fini(rdev);  	/* evict remaining vram memory */ @@ -1435,14 +1504,17 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)  	radeon_agp_suspend(rdev);  	pci_save_state(dev->pdev); -	if (state.event == PM_EVENT_SUSPEND) { +	if (suspend) {  		/* Shut down the device */  		pci_disable_device(dev->pdev);  		pci_set_power_state(dev->pdev, PCI_D3hot);  	} -	console_lock(); -	radeon_fbdev_set_suspend(rdev, 1); -	console_unlock(); + +	if (fbcon) { +		console_lock(); +		radeon_fbdev_set_suspend(rdev, 1); +		console_unlock(); +	}  	return 0;  } @@ -1455,7 +1527,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)   * Returns 0 for success or an error on failure.   * Called at driver resume.   */ -int radeon_resume_kms(struct drm_device *dev) +int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)  {  	struct drm_connector *connector;  	struct radeon_device *rdev = dev->dev_private; @@ -1464,12 +1536,17 @@ int radeon_resume_kms(struct drm_device *dev)  	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)  		return 0; -	console_lock(); -	pci_set_power_state(dev->pdev, PCI_D0); -	pci_restore_state(dev->pdev); -	if (pci_enable_device(dev->pdev)) { -		console_unlock(); -		return -1; +	if (fbcon) { +		console_lock(); +	} +	if (resume) { +		pci_set_power_state(dev->pdev, PCI_D0); +		pci_restore_state(dev->pdev); +		if (pci_enable_device(dev->pdev)) { +			if (fbcon) +				console_unlock(); +			return -1; +		}  	}  	/* resume AGP if in use */  	radeon_agp_resume(rdev); @@ -1479,11 +1556,19 @@ int radeon_resume_kms(struct drm_device *dev)  	if (r)  		DRM_ERROR("ib ring test failed (%d).\n", r); -	radeon_pm_resume(rdev); -	radeon_restore_bios_scratch_regs(rdev); +	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { +		/* do dpm late init */ +		r = radeon_pm_late_init(rdev); +		if (r) { +			rdev->pm.dpm_enabled = false; +			DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); +		} +	} else { +		/* resume old pm late */ +		radeon_pm_resume(rdev); +	} -	radeon_fbdev_set_suspend(rdev, 0); -	console_unlock(); +	radeon_restore_bios_scratch_regs(rdev);  	/* init dig PHYs, disp eng pll */  	if (rdev->is_atom_bios) { @@ -1500,13 +1585,25 @@ int radeon_resume_kms(struct drm_device *dev)  	/* reset hpd state */  	radeon_hpd_init(rdev);  	/* blat the mode back in */ -	drm_helper_resume_force_mode(dev); -	/* turn on display hw */ -	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); +	if (fbcon) { +		drm_helper_resume_force_mode(dev); +		/* turn on display hw */ +		list_for_each_entry(connector, &dev->mode_config.connector_list, head) { +			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); +		}  	}  	drm_kms_helper_poll_enable(dev); + +	/* set the power state here in case we are a PX system or headless */ +	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) +		radeon_pm_compute_clocks(rdev); + +	if (fbcon) { +		radeon_fbdev_set_suspend(rdev, 0); +		console_unlock(); +	} +  	return 0;  } @@ -1529,6 +1626,14 @@ int radeon_gpu_reset(struct radeon_device *rdev)  	int resched;  	down_write(&rdev->exclusive_lock); + +	if (!rdev->needs_reset) { +		up_write(&rdev->exclusive_lock); +		return 0; +	} + +	rdev->needs_reset = false; +  	radeon_save_bios_scratch_regs(rdev);  	/* block TTM */  	resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);  | 
