162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1462306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Authors: Dave Airlie 2562306a36Sopenharmony_ci * Alex Deucher 2662306a36Sopenharmony_ci * Jerome Glisse 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/pci.h> 3062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3162306a36Sopenharmony_ci#include <linux/slab.h> 3262306a36Sopenharmony_ci#include <linux/uaccess.h> 3362306a36Sopenharmony_ci#include <linux/vga_switcheroo.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <drm/drm_file.h> 3662306a36Sopenharmony_ci#include <drm/drm_ioctl.h> 3762306a36Sopenharmony_ci#include <drm/radeon_drm.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "radeon.h" 4062306a36Sopenharmony_ci#include "radeon_asic.h" 4162306a36Sopenharmony_ci#include "radeon_drv.h" 4262306a36Sopenharmony_ci#include "radeon_kms.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#if defined(CONFIG_VGA_SWITCHEROO) 4562306a36Sopenharmony_cibool radeon_has_atpx(void); 4662306a36Sopenharmony_ci#else 4762306a36Sopenharmony_cistatic inline bool radeon_has_atpx(void) { return false; } 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/** 5162306a36Sopenharmony_ci * radeon_driver_unload_kms - Main unload function for KMS. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * @dev: drm dev pointer 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * This is the main unload function for KMS (all asics). 5662306a36Sopenharmony_ci * It calls radeon_modeset_fini() to tear down the 5762306a36Sopenharmony_ci * displays, and radeon_device_fini() to tear down 5862306a36Sopenharmony_ci * the rest of the device (CP, writeback, etc.). 5962306a36Sopenharmony_ci * Returns 0 on success. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_civoid radeon_driver_unload_kms(struct drm_device *dev) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (rdev == NULL) 6662306a36Sopenharmony_ci return; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (rdev->rmmio == NULL) 6962306a36Sopenharmony_ci goto done_free; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (radeon_is_px(dev)) { 7262306a36Sopenharmony_ci pm_runtime_get_sync(dev->dev); 7362306a36Sopenharmony_ci pm_runtime_forbid(dev->dev); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci radeon_acpi_fini(rdev); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci radeon_modeset_fini(rdev); 7962306a36Sopenharmony_ci radeon_device_fini(rdev); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (rdev->agp) 8262306a36Sopenharmony_ci arch_phys_wc_del(rdev->agp->agp_mtrr); 8362306a36Sopenharmony_ci kfree(rdev->agp); 8462306a36Sopenharmony_ci rdev->agp = NULL; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cidone_free: 8762306a36Sopenharmony_ci kfree(rdev); 8862306a36Sopenharmony_ci dev->dev_private = NULL; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/** 9262306a36Sopenharmony_ci * radeon_driver_load_kms - Main load function for KMS. 9362306a36Sopenharmony_ci * 9462306a36Sopenharmony_ci * @dev: drm dev pointer 9562306a36Sopenharmony_ci * @flags: device flags 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * This is the main load function for KMS (all asics). 9862306a36Sopenharmony_ci * It calls radeon_device_init() to set up the non-display 9962306a36Sopenharmony_ci * parts of the chip (asic init, CP, writeback, etc.), and 10062306a36Sopenharmony_ci * radeon_modeset_init() to set up the display parts 10162306a36Sopenharmony_ci * (crtcs, encoders, hotplug detect, etc.). 10262306a36Sopenharmony_ci * Returns 0 on success, error on failure. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ciint radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev->dev); 10762306a36Sopenharmony_ci struct radeon_device *rdev; 10862306a36Sopenharmony_ci int r, acpi_status; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL); 11162306a36Sopenharmony_ci if (rdev == NULL) { 11262306a36Sopenharmony_ci return -ENOMEM; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci dev->dev_private = (void *)rdev; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#ifdef __alpha__ 11762306a36Sopenharmony_ci rdev->hose = pdev->sysdata; 11862306a36Sopenharmony_ci#endif 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (pci_find_capability(pdev, PCI_CAP_ID_AGP)) 12162306a36Sopenharmony_ci rdev->agp = radeon_agp_head_init(dev); 12262306a36Sopenharmony_ci if (rdev->agp) { 12362306a36Sopenharmony_ci rdev->agp->agp_mtrr = arch_phys_wc_add( 12462306a36Sopenharmony_ci rdev->agp->agp_info.aper_base, 12562306a36Sopenharmony_ci rdev->agp->agp_info.aper_size * 12662306a36Sopenharmony_ci 1024 * 1024); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* update BUS flag */ 13062306a36Sopenharmony_ci if (pci_find_capability(pdev, PCI_CAP_ID_AGP)) { 13162306a36Sopenharmony_ci flags |= RADEON_IS_AGP; 13262306a36Sopenharmony_ci } else if (pci_is_pcie(pdev)) { 13362306a36Sopenharmony_ci flags |= RADEON_IS_PCIE; 13462306a36Sopenharmony_ci } else { 13562306a36Sopenharmony_ci flags |= RADEON_IS_PCI; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if ((radeon_runtime_pm != 0) && 13962306a36Sopenharmony_ci radeon_has_atpx() && 14062306a36Sopenharmony_ci ((flags & RADEON_IS_IGP) == 0) && 14162306a36Sopenharmony_ci !pci_is_thunderbolt_attached(pdev)) 14262306a36Sopenharmony_ci flags |= RADEON_IS_PX; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* radeon_device_init should report only fatal error 14562306a36Sopenharmony_ci * like memory allocation failure or iomapping failure, 14662306a36Sopenharmony_ci * or memory manager initialization failure, it must 14762306a36Sopenharmony_ci * properly initialize the GPU MC controller and permit 14862306a36Sopenharmony_ci * VRAM allocation 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci r = radeon_device_init(rdev, dev, pdev, flags); 15162306a36Sopenharmony_ci if (r) { 15262306a36Sopenharmony_ci dev_err(dev->dev, "Fatal error during GPU init\n"); 15362306a36Sopenharmony_ci goto out; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Again modeset_init should fail only on fatal error 15762306a36Sopenharmony_ci * otherwise it should provide enough functionalities 15862306a36Sopenharmony_ci * for shadowfb to run 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci r = radeon_modeset_init(rdev); 16162306a36Sopenharmony_ci if (r) 16262306a36Sopenharmony_ci dev_err(dev->dev, "Fatal error during modeset init\n"); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Call ACPI methods: require modeset init 16562306a36Sopenharmony_ci * but failure is not fatal 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci if (!r) { 16862306a36Sopenharmony_ci acpi_status = radeon_acpi_init(rdev); 16962306a36Sopenharmony_ci if (acpi_status) 17062306a36Sopenharmony_ci dev_dbg(dev->dev, "Error during ACPI methods call\n"); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (radeon_is_px(dev)) { 17462306a36Sopenharmony_ci dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); 17562306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev->dev); 17662306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev->dev, 5000); 17762306a36Sopenharmony_ci pm_runtime_set_active(dev->dev); 17862306a36Sopenharmony_ci pm_runtime_allow(dev->dev); 17962306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev->dev); 18062306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciout: 18462306a36Sopenharmony_ci if (r) 18562306a36Sopenharmony_ci radeon_driver_unload_kms(dev); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return r; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/** 19262306a36Sopenharmony_ci * radeon_set_filp_rights - Set filp right. 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * @dev: drm dev pointer 19562306a36Sopenharmony_ci * @owner: drm file 19662306a36Sopenharmony_ci * @applier: drm file 19762306a36Sopenharmony_ci * @value: value 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Sets the filp rights for the device (all asics). 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic void radeon_set_filp_rights(struct drm_device *dev, 20262306a36Sopenharmony_ci struct drm_file **owner, 20362306a36Sopenharmony_ci struct drm_file *applier, 20462306a36Sopenharmony_ci uint32_t *value) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci mutex_lock(&rdev->gem.mutex); 20962306a36Sopenharmony_ci if (*value == 1) { 21062306a36Sopenharmony_ci /* wants rights */ 21162306a36Sopenharmony_ci if (!*owner) 21262306a36Sopenharmony_ci *owner = applier; 21362306a36Sopenharmony_ci } else if (*value == 0) { 21462306a36Sopenharmony_ci /* revokes rights */ 21562306a36Sopenharmony_ci if (*owner == applier) 21662306a36Sopenharmony_ci *owner = NULL; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci *value = *owner == applier ? 1 : 0; 21962306a36Sopenharmony_ci mutex_unlock(&rdev->gem.mutex); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * Userspace get information ioctl 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * radeon_info_ioctl - answer a device specific request. 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * @dev: drm device pointer 22962306a36Sopenharmony_ci * @data: request object 23062306a36Sopenharmony_ci * @filp: drm filp 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * This function is used to pass device specific parameters to the userspace 23362306a36Sopenharmony_ci * drivers. Examples include: pci device id, pipeline parms, tiling params, 23462306a36Sopenharmony_ci * etc. (all asics). 23562306a36Sopenharmony_ci * Returns 0 on success, -EINVAL on failure. 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ciint radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 24062306a36Sopenharmony_ci struct drm_radeon_info *info = data; 24162306a36Sopenharmony_ci struct radeon_mode_info *minfo = &rdev->mode_info; 24262306a36Sopenharmony_ci uint32_t *value, value_tmp, *value_ptr, value_size; 24362306a36Sopenharmony_ci struct ttm_resource_manager *man; 24462306a36Sopenharmony_ci uint64_t value64; 24562306a36Sopenharmony_ci struct drm_crtc *crtc; 24662306a36Sopenharmony_ci int i, found; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci value_ptr = (uint32_t *)((unsigned long)info->value); 24962306a36Sopenharmony_ci value = &value_tmp; 25062306a36Sopenharmony_ci value_size = sizeof(uint32_t); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci switch (info->request) { 25362306a36Sopenharmony_ci case RADEON_INFO_DEVICE_ID: 25462306a36Sopenharmony_ci *value = to_pci_dev(dev->dev)->device; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci case RADEON_INFO_NUM_GB_PIPES: 25762306a36Sopenharmony_ci *value = rdev->num_gb_pipes; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case RADEON_INFO_NUM_Z_PIPES: 26062306a36Sopenharmony_ci *value = rdev->num_z_pipes; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case RADEON_INFO_ACCEL_WORKING: 26362306a36Sopenharmony_ci /* xf86-video-ati 6.13.0 relies on this being false for evergreen */ 26462306a36Sopenharmony_ci if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) 26562306a36Sopenharmony_ci *value = false; 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci *value = rdev->accel_working; 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case RADEON_INFO_CRTC_FROM_ID: 27062306a36Sopenharmony_ci if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { 27162306a36Sopenharmony_ci DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); 27262306a36Sopenharmony_ci return -EFAULT; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci for (i = 0, found = 0; i < rdev->num_crtc; i++) { 27562306a36Sopenharmony_ci crtc = (struct drm_crtc *)minfo->crtcs[i]; 27662306a36Sopenharmony_ci if (crtc && crtc->base.id == *value) { 27762306a36Sopenharmony_ci struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 27862306a36Sopenharmony_ci *value = radeon_crtc->crtc_id; 27962306a36Sopenharmony_ci found = 1; 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci if (!found) { 28462306a36Sopenharmony_ci DRM_DEBUG_KMS("unknown crtc id %d\n", *value); 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case RADEON_INFO_ACCEL_WORKING2: 28962306a36Sopenharmony_ci if (rdev->family == CHIP_HAWAII) { 29062306a36Sopenharmony_ci if (rdev->accel_working) { 29162306a36Sopenharmony_ci if (rdev->new_fw) 29262306a36Sopenharmony_ci *value = 3; 29362306a36Sopenharmony_ci else 29462306a36Sopenharmony_ci *value = 2; 29562306a36Sopenharmony_ci } else { 29662306a36Sopenharmony_ci *value = 0; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci } else { 29962306a36Sopenharmony_ci *value = rdev->accel_working; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci case RADEON_INFO_TILING_CONFIG: 30362306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 30462306a36Sopenharmony_ci *value = rdev->config.cik.tile_config; 30562306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 30662306a36Sopenharmony_ci *value = rdev->config.si.tile_config; 30762306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 30862306a36Sopenharmony_ci *value = rdev->config.cayman.tile_config; 30962306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 31062306a36Sopenharmony_ci *value = rdev->config.evergreen.tile_config; 31162306a36Sopenharmony_ci else if (rdev->family >= CHIP_RV770) 31262306a36Sopenharmony_ci *value = rdev->config.rv770.tile_config; 31362306a36Sopenharmony_ci else if (rdev->family >= CHIP_R600) 31462306a36Sopenharmony_ci *value = rdev->config.r600.tile_config; 31562306a36Sopenharmony_ci else { 31662306a36Sopenharmony_ci DRM_DEBUG_KMS("tiling config is r6xx+ only!\n"); 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci case RADEON_INFO_WANT_HYPERZ: 32162306a36Sopenharmony_ci /* The "value" here is both an input and output parameter. 32262306a36Sopenharmony_ci * If the input value is 1, filp requests hyper-z access. 32362306a36Sopenharmony_ci * If the input value is 0, filp revokes its hyper-z access. 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * When returning, the value is 1 if filp owns hyper-z access, 32662306a36Sopenharmony_ci * 0 otherwise. */ 32762306a36Sopenharmony_ci if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { 32862306a36Sopenharmony_ci DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); 32962306a36Sopenharmony_ci return -EFAULT; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci if (*value >= 2) { 33262306a36Sopenharmony_ci DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", *value); 33362306a36Sopenharmony_ci return -EINVAL; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, value); 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci case RADEON_INFO_WANT_CMASK: 33862306a36Sopenharmony_ci /* The same logic as Hyper-Z. */ 33962306a36Sopenharmony_ci if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { 34062306a36Sopenharmony_ci DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); 34162306a36Sopenharmony_ci return -EFAULT; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci if (*value >= 2) { 34462306a36Sopenharmony_ci DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", *value); 34562306a36Sopenharmony_ci return -EINVAL; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, value); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case RADEON_INFO_CLOCK_CRYSTAL_FREQ: 35062306a36Sopenharmony_ci /* return clock value in KHz */ 35162306a36Sopenharmony_ci if (rdev->asic->get_xclk) 35262306a36Sopenharmony_ci *value = radeon_get_xclk(rdev) * 10; 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci *value = rdev->clock.spll.reference_freq * 10; 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci case RADEON_INFO_NUM_BACKENDS: 35762306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 35862306a36Sopenharmony_ci *value = rdev->config.cik.max_backends_per_se * 35962306a36Sopenharmony_ci rdev->config.cik.max_shader_engines; 36062306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 36162306a36Sopenharmony_ci *value = rdev->config.si.max_backends_per_se * 36262306a36Sopenharmony_ci rdev->config.si.max_shader_engines; 36362306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 36462306a36Sopenharmony_ci *value = rdev->config.cayman.max_backends_per_se * 36562306a36Sopenharmony_ci rdev->config.cayman.max_shader_engines; 36662306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 36762306a36Sopenharmony_ci *value = rdev->config.evergreen.max_backends; 36862306a36Sopenharmony_ci else if (rdev->family >= CHIP_RV770) 36962306a36Sopenharmony_ci *value = rdev->config.rv770.max_backends; 37062306a36Sopenharmony_ci else if (rdev->family >= CHIP_R600) 37162306a36Sopenharmony_ci *value = rdev->config.r600.max_backends; 37262306a36Sopenharmony_ci else { 37362306a36Sopenharmony_ci return -EINVAL; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case RADEON_INFO_NUM_TILE_PIPES: 37762306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 37862306a36Sopenharmony_ci *value = rdev->config.cik.max_tile_pipes; 37962306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 38062306a36Sopenharmony_ci *value = rdev->config.si.max_tile_pipes; 38162306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 38262306a36Sopenharmony_ci *value = rdev->config.cayman.max_tile_pipes; 38362306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 38462306a36Sopenharmony_ci *value = rdev->config.evergreen.max_tile_pipes; 38562306a36Sopenharmony_ci else if (rdev->family >= CHIP_RV770) 38662306a36Sopenharmony_ci *value = rdev->config.rv770.max_tile_pipes; 38762306a36Sopenharmony_ci else if (rdev->family >= CHIP_R600) 38862306a36Sopenharmony_ci *value = rdev->config.r600.max_tile_pipes; 38962306a36Sopenharmony_ci else { 39062306a36Sopenharmony_ci return -EINVAL; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case RADEON_INFO_FUSION_GART_WORKING: 39462306a36Sopenharmony_ci *value = 1; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case RADEON_INFO_BACKEND_MAP: 39762306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 39862306a36Sopenharmony_ci *value = rdev->config.cik.backend_map; 39962306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 40062306a36Sopenharmony_ci *value = rdev->config.si.backend_map; 40162306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 40262306a36Sopenharmony_ci *value = rdev->config.cayman.backend_map; 40362306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 40462306a36Sopenharmony_ci *value = rdev->config.evergreen.backend_map; 40562306a36Sopenharmony_ci else if (rdev->family >= CHIP_RV770) 40662306a36Sopenharmony_ci *value = rdev->config.rv770.backend_map; 40762306a36Sopenharmony_ci else if (rdev->family >= CHIP_R600) 40862306a36Sopenharmony_ci *value = rdev->config.r600.backend_map; 40962306a36Sopenharmony_ci else { 41062306a36Sopenharmony_ci return -EINVAL; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci case RADEON_INFO_VA_START: 41462306a36Sopenharmony_ci /* this is where we report if vm is supported or not */ 41562306a36Sopenharmony_ci if (rdev->family < CHIP_CAYMAN) 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci *value = RADEON_VA_RESERVED_SIZE; 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case RADEON_INFO_IB_VM_MAX_SIZE: 42062306a36Sopenharmony_ci /* this is where we report if vm is supported or not */ 42162306a36Sopenharmony_ci if (rdev->family < CHIP_CAYMAN) 42262306a36Sopenharmony_ci return -EINVAL; 42362306a36Sopenharmony_ci *value = RADEON_IB_VM_MAX_SIZE; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case RADEON_INFO_MAX_PIPES: 42662306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 42762306a36Sopenharmony_ci *value = rdev->config.cik.max_cu_per_sh; 42862306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 42962306a36Sopenharmony_ci *value = rdev->config.si.max_cu_per_sh; 43062306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 43162306a36Sopenharmony_ci *value = rdev->config.cayman.max_pipes_per_simd; 43262306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 43362306a36Sopenharmony_ci *value = rdev->config.evergreen.max_pipes; 43462306a36Sopenharmony_ci else if (rdev->family >= CHIP_RV770) 43562306a36Sopenharmony_ci *value = rdev->config.rv770.max_pipes; 43662306a36Sopenharmony_ci else if (rdev->family >= CHIP_R600) 43762306a36Sopenharmony_ci *value = rdev->config.r600.max_pipes; 43862306a36Sopenharmony_ci else { 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci case RADEON_INFO_TIMESTAMP: 44362306a36Sopenharmony_ci if (rdev->family < CHIP_R600) { 44462306a36Sopenharmony_ci DRM_DEBUG_KMS("timestamp is r6xx+ only!\n"); 44562306a36Sopenharmony_ci return -EINVAL; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci value = (uint32_t *)&value64; 44862306a36Sopenharmony_ci value_size = sizeof(uint64_t); 44962306a36Sopenharmony_ci value64 = radeon_get_gpu_clock_counter(rdev); 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci case RADEON_INFO_MAX_SE: 45262306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 45362306a36Sopenharmony_ci *value = rdev->config.cik.max_shader_engines; 45462306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 45562306a36Sopenharmony_ci *value = rdev->config.si.max_shader_engines; 45662306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 45762306a36Sopenharmony_ci *value = rdev->config.cayman.max_shader_engines; 45862306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 45962306a36Sopenharmony_ci *value = rdev->config.evergreen.num_ses; 46062306a36Sopenharmony_ci else 46162306a36Sopenharmony_ci *value = 1; 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci case RADEON_INFO_MAX_SH_PER_SE: 46462306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 46562306a36Sopenharmony_ci *value = rdev->config.cik.max_sh_per_se; 46662306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 46762306a36Sopenharmony_ci *value = rdev->config.si.max_sh_per_se; 46862306a36Sopenharmony_ci else 46962306a36Sopenharmony_ci return -EINVAL; 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci case RADEON_INFO_FASTFB_WORKING: 47262306a36Sopenharmony_ci *value = rdev->fastfb_working; 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci case RADEON_INFO_RING_WORKING: 47562306a36Sopenharmony_ci if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { 47662306a36Sopenharmony_ci DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); 47762306a36Sopenharmony_ci return -EFAULT; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci switch (*value) { 48062306a36Sopenharmony_ci case RADEON_CS_RING_GFX: 48162306a36Sopenharmony_ci case RADEON_CS_RING_COMPUTE: 48262306a36Sopenharmony_ci *value = rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready; 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case RADEON_CS_RING_DMA: 48562306a36Sopenharmony_ci *value = rdev->ring[R600_RING_TYPE_DMA_INDEX].ready; 48662306a36Sopenharmony_ci *value |= rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready; 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci case RADEON_CS_RING_UVD: 48962306a36Sopenharmony_ci *value = rdev->ring[R600_RING_TYPE_UVD_INDEX].ready; 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case RADEON_CS_RING_VCE: 49262306a36Sopenharmony_ci *value = rdev->ring[TN_RING_TYPE_VCE1_INDEX].ready; 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci default: 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci case RADEON_INFO_SI_TILE_MODE_ARRAY: 49962306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 50062306a36Sopenharmony_ci value = rdev->config.cik.tile_mode_array; 50162306a36Sopenharmony_ci value_size = sizeof(uint32_t)*32; 50262306a36Sopenharmony_ci } else if (rdev->family >= CHIP_TAHITI) { 50362306a36Sopenharmony_ci value = rdev->config.si.tile_mode_array; 50462306a36Sopenharmony_ci value_size = sizeof(uint32_t)*32; 50562306a36Sopenharmony_ci } else { 50662306a36Sopenharmony_ci DRM_DEBUG_KMS("tile mode array is si+ only!\n"); 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci case RADEON_INFO_CIK_MACROTILE_MODE_ARRAY: 51162306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 51262306a36Sopenharmony_ci value = rdev->config.cik.macrotile_mode_array; 51362306a36Sopenharmony_ci value_size = sizeof(uint32_t)*16; 51462306a36Sopenharmony_ci } else { 51562306a36Sopenharmony_ci DRM_DEBUG_KMS("macrotile mode array is cik+ only!\n"); 51662306a36Sopenharmony_ci return -EINVAL; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci case RADEON_INFO_SI_CP_DMA_COMPUTE: 52062306a36Sopenharmony_ci *value = 1; 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci case RADEON_INFO_SI_BACKEND_ENABLED_MASK: 52362306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 52462306a36Sopenharmony_ci *value = rdev->config.cik.backend_enable_mask; 52562306a36Sopenharmony_ci } else if (rdev->family >= CHIP_TAHITI) { 52662306a36Sopenharmony_ci *value = rdev->config.si.backend_enable_mask; 52762306a36Sopenharmony_ci } else { 52862306a36Sopenharmony_ci DRM_DEBUG_KMS("BACKEND_ENABLED_MASK is si+ only!\n"); 52962306a36Sopenharmony_ci return -EINVAL; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case RADEON_INFO_MAX_SCLK: 53362306a36Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && 53462306a36Sopenharmony_ci rdev->pm.dpm_enabled) 53562306a36Sopenharmony_ci *value = rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk * 10; 53662306a36Sopenharmony_ci else 53762306a36Sopenharmony_ci *value = rdev->pm.default_sclk * 10; 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci case RADEON_INFO_VCE_FW_VERSION: 54062306a36Sopenharmony_ci *value = rdev->vce.fw_version; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case RADEON_INFO_VCE_FB_VERSION: 54362306a36Sopenharmony_ci *value = rdev->vce.fb_version; 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci case RADEON_INFO_NUM_BYTES_MOVED: 54662306a36Sopenharmony_ci value = (uint32_t *)&value64; 54762306a36Sopenharmony_ci value_size = sizeof(uint64_t); 54862306a36Sopenharmony_ci value64 = atomic64_read(&rdev->num_bytes_moved); 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case RADEON_INFO_VRAM_USAGE: 55162306a36Sopenharmony_ci value = (uint32_t *)&value64; 55262306a36Sopenharmony_ci value_size = sizeof(uint64_t); 55362306a36Sopenharmony_ci man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM); 55462306a36Sopenharmony_ci value64 = ttm_resource_manager_usage(man); 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci case RADEON_INFO_GTT_USAGE: 55762306a36Sopenharmony_ci value = (uint32_t *)&value64; 55862306a36Sopenharmony_ci value_size = sizeof(uint64_t); 55962306a36Sopenharmony_ci man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_TT); 56062306a36Sopenharmony_ci value64 = ttm_resource_manager_usage(man); 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci case RADEON_INFO_ACTIVE_CU_COUNT: 56362306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) 56462306a36Sopenharmony_ci *value = rdev->config.cik.active_cus; 56562306a36Sopenharmony_ci else if (rdev->family >= CHIP_TAHITI) 56662306a36Sopenharmony_ci *value = rdev->config.si.active_cus; 56762306a36Sopenharmony_ci else if (rdev->family >= CHIP_CAYMAN) 56862306a36Sopenharmony_ci *value = rdev->config.cayman.active_simds; 56962306a36Sopenharmony_ci else if (rdev->family >= CHIP_CEDAR) 57062306a36Sopenharmony_ci *value = rdev->config.evergreen.active_simds; 57162306a36Sopenharmony_ci else if (rdev->family >= CHIP_RV770) 57262306a36Sopenharmony_ci *value = rdev->config.rv770.active_simds; 57362306a36Sopenharmony_ci else if (rdev->family >= CHIP_R600) 57462306a36Sopenharmony_ci *value = rdev->config.r600.active_simds; 57562306a36Sopenharmony_ci else 57662306a36Sopenharmony_ci *value = 1; 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci case RADEON_INFO_CURRENT_GPU_TEMP: 57962306a36Sopenharmony_ci /* get temperature in millidegrees C */ 58062306a36Sopenharmony_ci if (rdev->asic->pm.get_temperature) 58162306a36Sopenharmony_ci *value = radeon_get_temperature(rdev); 58262306a36Sopenharmony_ci else 58362306a36Sopenharmony_ci *value = 0; 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci case RADEON_INFO_CURRENT_GPU_SCLK: 58662306a36Sopenharmony_ci /* get sclk in Mhz */ 58762306a36Sopenharmony_ci if (rdev->pm.dpm_enabled) 58862306a36Sopenharmony_ci *value = radeon_dpm_get_current_sclk(rdev) / 100; 58962306a36Sopenharmony_ci else 59062306a36Sopenharmony_ci *value = rdev->pm.current_sclk / 100; 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci case RADEON_INFO_CURRENT_GPU_MCLK: 59362306a36Sopenharmony_ci /* get mclk in Mhz */ 59462306a36Sopenharmony_ci if (rdev->pm.dpm_enabled) 59562306a36Sopenharmony_ci *value = radeon_dpm_get_current_mclk(rdev) / 100; 59662306a36Sopenharmony_ci else 59762306a36Sopenharmony_ci *value = rdev->pm.current_mclk / 100; 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci case RADEON_INFO_READ_REG: 60062306a36Sopenharmony_ci if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { 60162306a36Sopenharmony_ci DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); 60262306a36Sopenharmony_ci return -EFAULT; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci if (radeon_get_allowed_info_register(rdev, *value, value)) 60562306a36Sopenharmony_ci return -EINVAL; 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci case RADEON_INFO_VA_UNMAP_WORKING: 60862306a36Sopenharmony_ci *value = true; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case RADEON_INFO_GPU_RESET_COUNTER: 61162306a36Sopenharmony_ci *value = atomic_read(&rdev->gpu_reset_counter); 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci default: 61462306a36Sopenharmony_ci DRM_DEBUG_KMS("Invalid request %d\n", info->request); 61562306a36Sopenharmony_ci return -EINVAL; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci if (copy_to_user(value_ptr, (char *)value, value_size)) { 61862306a36Sopenharmony_ci DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__); 61962306a36Sopenharmony_ci return -EFAULT; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/** 62562306a36Sopenharmony_ci * radeon_driver_open_kms - drm callback for open 62662306a36Sopenharmony_ci * 62762306a36Sopenharmony_ci * @dev: drm dev pointer 62862306a36Sopenharmony_ci * @file_priv: drm file 62962306a36Sopenharmony_ci * 63062306a36Sopenharmony_ci * On device open, init vm on cayman+ (all asics). 63162306a36Sopenharmony_ci * Returns 0 on success, error on failure. 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_ciint radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 63662306a36Sopenharmony_ci struct radeon_fpriv *fpriv; 63762306a36Sopenharmony_ci struct radeon_vm *vm; 63862306a36Sopenharmony_ci int r; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci file_priv->driver_priv = NULL; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci r = pm_runtime_get_sync(dev->dev); 64362306a36Sopenharmony_ci if (r < 0) { 64462306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 64562306a36Sopenharmony_ci return r; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* new gpu have virtual address space support */ 64962306a36Sopenharmony_ci if (rdev->family >= CHIP_CAYMAN) { 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); 65262306a36Sopenharmony_ci if (unlikely(!fpriv)) { 65362306a36Sopenharmony_ci r = -ENOMEM; 65462306a36Sopenharmony_ci goto err_suspend; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (rdev->accel_working) { 65862306a36Sopenharmony_ci vm = &fpriv->vm; 65962306a36Sopenharmony_ci r = radeon_vm_init(rdev, vm); 66062306a36Sopenharmony_ci if (r) 66162306a36Sopenharmony_ci goto err_fpriv; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); 66462306a36Sopenharmony_ci if (r) 66562306a36Sopenharmony_ci goto err_vm_fini; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* map the ib pool buffer read only into 66862306a36Sopenharmony_ci * virtual address space */ 66962306a36Sopenharmony_ci vm->ib_bo_va = radeon_vm_bo_add(rdev, vm, 67062306a36Sopenharmony_ci rdev->ring_tmp_bo.bo); 67162306a36Sopenharmony_ci if (!vm->ib_bo_va) { 67262306a36Sopenharmony_ci r = -ENOMEM; 67362306a36Sopenharmony_ci goto err_vm_fini; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, 67762306a36Sopenharmony_ci RADEON_VA_IB_OFFSET, 67862306a36Sopenharmony_ci RADEON_VM_PAGE_READABLE | 67962306a36Sopenharmony_ci RADEON_VM_PAGE_SNOOPED); 68062306a36Sopenharmony_ci if (r) 68162306a36Sopenharmony_ci goto err_vm_fini; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci file_priv->driver_priv = fpriv; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev->dev); 68762306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 68862306a36Sopenharmony_ci return 0; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cierr_vm_fini: 69162306a36Sopenharmony_ci radeon_vm_fini(rdev, vm); 69262306a36Sopenharmony_cierr_fpriv: 69362306a36Sopenharmony_ci kfree(fpriv); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cierr_suspend: 69662306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev->dev); 69762306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 69862306a36Sopenharmony_ci return r; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci/** 70262306a36Sopenharmony_ci * radeon_driver_postclose_kms - drm callback for post close 70362306a36Sopenharmony_ci * 70462306a36Sopenharmony_ci * @dev: drm dev pointer 70562306a36Sopenharmony_ci * @file_priv: drm file 70662306a36Sopenharmony_ci * 70762306a36Sopenharmony_ci * On device close, tear down hyperz and cmask filps on r1xx-r5xx 70862306a36Sopenharmony_ci * (all asics). And tear down vm on cayman+ (all asics). 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_civoid radeon_driver_postclose_kms(struct drm_device *dev, 71162306a36Sopenharmony_ci struct drm_file *file_priv) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci pm_runtime_get_sync(dev->dev); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci mutex_lock(&rdev->gem.mutex); 71862306a36Sopenharmony_ci if (rdev->hyperz_filp == file_priv) 71962306a36Sopenharmony_ci rdev->hyperz_filp = NULL; 72062306a36Sopenharmony_ci if (rdev->cmask_filp == file_priv) 72162306a36Sopenharmony_ci rdev->cmask_filp = NULL; 72262306a36Sopenharmony_ci mutex_unlock(&rdev->gem.mutex); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci radeon_uvd_free_handles(rdev, file_priv); 72562306a36Sopenharmony_ci radeon_vce_free_handles(rdev, file_priv); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* new gpu have virtual address space support */ 72862306a36Sopenharmony_ci if (rdev->family >= CHIP_CAYMAN && file_priv->driver_priv) { 72962306a36Sopenharmony_ci struct radeon_fpriv *fpriv = file_priv->driver_priv; 73062306a36Sopenharmony_ci struct radeon_vm *vm = &fpriv->vm; 73162306a36Sopenharmony_ci int r; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (rdev->accel_working) { 73462306a36Sopenharmony_ci r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); 73562306a36Sopenharmony_ci if (!r) { 73662306a36Sopenharmony_ci if (vm->ib_bo_va) 73762306a36Sopenharmony_ci radeon_vm_bo_rmv(rdev, vm->ib_bo_va); 73862306a36Sopenharmony_ci radeon_bo_unreserve(rdev->ring_tmp_bo.bo); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci radeon_vm_fini(rdev, vm); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci kfree(fpriv); 74462306a36Sopenharmony_ci file_priv->driver_priv = NULL; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev->dev); 74762306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci/* 75162306a36Sopenharmony_ci * VBlank related functions. 75262306a36Sopenharmony_ci */ 75362306a36Sopenharmony_ci/** 75462306a36Sopenharmony_ci * radeon_get_vblank_counter_kms - get frame count 75562306a36Sopenharmony_ci * 75662306a36Sopenharmony_ci * @crtc: crtc to get the frame count from 75762306a36Sopenharmony_ci * 75862306a36Sopenharmony_ci * Gets the frame count on the requested crtc (all asics). 75962306a36Sopenharmony_ci * Returns frame count on success, -EINVAL on failure. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ciu32 radeon_get_vblank_counter_kms(struct drm_crtc *crtc) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 76462306a36Sopenharmony_ci unsigned int pipe = crtc->index; 76562306a36Sopenharmony_ci int vpos, hpos, stat; 76662306a36Sopenharmony_ci u32 count; 76762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (pipe >= rdev->num_crtc) { 77062306a36Sopenharmony_ci DRM_ERROR("Invalid crtc %u\n", pipe); 77162306a36Sopenharmony_ci return -EINVAL; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* The hw increments its frame counter at start of vsync, not at start 77562306a36Sopenharmony_ci * of vblank, as is required by DRM core vblank counter handling. 77662306a36Sopenharmony_ci * Cook the hw count here to make it appear to the caller as if it 77762306a36Sopenharmony_ci * incremented at start of vblank. We measure distance to start of 77862306a36Sopenharmony_ci * vblank in vpos. vpos therefore will be >= 0 between start of vblank 77962306a36Sopenharmony_ci * and start of vsync, so vpos >= 0 means to bump the hw frame counter 78062306a36Sopenharmony_ci * result by 1 to give the proper appearance to caller. 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci if (rdev->mode_info.crtcs[pipe]) { 78362306a36Sopenharmony_ci /* Repeat readout if needed to provide stable result if 78462306a36Sopenharmony_ci * we cross start of vsync during the queries. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci do { 78762306a36Sopenharmony_ci count = radeon_get_vblank_counter(rdev, pipe); 78862306a36Sopenharmony_ci /* Ask radeon_get_crtc_scanoutpos to return vpos as 78962306a36Sopenharmony_ci * distance to start of vblank, instead of regular 79062306a36Sopenharmony_ci * vertical scanout pos. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci stat = radeon_get_crtc_scanoutpos( 79362306a36Sopenharmony_ci dev, pipe, GET_DISTANCE_TO_VBLANKSTART, 79462306a36Sopenharmony_ci &vpos, &hpos, NULL, NULL, 79562306a36Sopenharmony_ci &rdev->mode_info.crtcs[pipe]->base.hwmode); 79662306a36Sopenharmony_ci } while (count != radeon_get_vblank_counter(rdev, pipe)); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != 79962306a36Sopenharmony_ci (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { 80062306a36Sopenharmony_ci DRM_DEBUG_VBL("Query failed! stat %d\n", stat); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci else { 80362306a36Sopenharmony_ci DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n", 80462306a36Sopenharmony_ci pipe, vpos); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* Bump counter if we are at >= leading edge of vblank, 80762306a36Sopenharmony_ci * but before vsync where vpos would turn negative and 80862306a36Sopenharmony_ci * the hw counter really increments. 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_ci if (vpos >= 0) 81162306a36Sopenharmony_ci count++; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci else { 81562306a36Sopenharmony_ci /* Fallback to use value as is. */ 81662306a36Sopenharmony_ci count = radeon_get_vblank_counter(rdev, pipe); 81762306a36Sopenharmony_ci DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return count; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci/** 82462306a36Sopenharmony_ci * radeon_enable_vblank_kms - enable vblank interrupt 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * @crtc: crtc to enable vblank interrupt for 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * Enable the interrupt on the requested crtc (all asics). 82962306a36Sopenharmony_ci * Returns 0 on success, -EINVAL on failure. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ciint radeon_enable_vblank_kms(struct drm_crtc *crtc) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 83462306a36Sopenharmony_ci unsigned int pipe = crtc->index; 83562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 83662306a36Sopenharmony_ci unsigned long irqflags; 83762306a36Sopenharmony_ci int r; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (pipe >= rdev->num_crtc) { 84062306a36Sopenharmony_ci DRM_ERROR("Invalid crtc %d\n", pipe); 84162306a36Sopenharmony_ci return -EINVAL; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci spin_lock_irqsave(&rdev->irq.lock, irqflags); 84562306a36Sopenharmony_ci rdev->irq.crtc_vblank_int[pipe] = true; 84662306a36Sopenharmony_ci r = radeon_irq_set(rdev); 84762306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->irq.lock, irqflags); 84862306a36Sopenharmony_ci return r; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci/** 85262306a36Sopenharmony_ci * radeon_disable_vblank_kms - disable vblank interrupt 85362306a36Sopenharmony_ci * 85462306a36Sopenharmony_ci * @crtc: crtc to disable vblank interrupt for 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * Disable the interrupt on the requested crtc (all asics). 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_civoid radeon_disable_vblank_kms(struct drm_crtc *crtc) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 86162306a36Sopenharmony_ci unsigned int pipe = crtc->index; 86262306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 86362306a36Sopenharmony_ci unsigned long irqflags; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (pipe >= rdev->num_crtc) { 86662306a36Sopenharmony_ci DRM_ERROR("Invalid crtc %d\n", pipe); 86762306a36Sopenharmony_ci return; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci spin_lock_irqsave(&rdev->irq.lock, irqflags); 87162306a36Sopenharmony_ci rdev->irq.crtc_vblank_int[pipe] = false; 87262306a36Sopenharmony_ci radeon_irq_set(rdev); 87362306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->irq.lock, irqflags); 87462306a36Sopenharmony_ci} 875