diff options
25 files changed, 733 insertions, 171 deletions
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index ed1d91025928..6dacec4e2090 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> #include "drmP.h" @@ -742,7 +741,6 @@ static int ci_mc_load_microcode(struct radeon_device *rdev) */ static int cik_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; size_t pfp_req_size, me_req_size, ce_req_size, mec_req_size, rlc_req_size, mc_req_size, @@ -752,13 +750,6 @@ static int cik_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_BONAIRE: chip_name = "BONAIRE"; @@ -794,7 +785,7 @@ static int cik_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -806,7 +797,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -817,7 +808,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); - err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->ce_fw->size != ce_req_size) { @@ -828,7 +819,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); - err = request_firmware(&rdev->mec_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mec_fw->size != mec_req_size) { @@ -839,7 +830,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -850,7 +841,7 @@ static int cik_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); - err = request_firmware(&rdev->sdma_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->sdma_fw->size != sdma_req_size) { @@ -863,7 +854,7 @@ static int cik_init_microcode(struct radeon_device *rdev) /* No MC ucode on APUs */ if (!(rdev->flags & RADEON_IS_IGP)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mc_fw->size != mc_req_size) { @@ -875,8 +866,6 @@ static int cik_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -4453,6 +4442,29 @@ void cik_vm_fini(struct radeon_device *rdev) } /** + * cik_vm_decode_fault - print human readable fault info + * + * @rdev: radeon_device pointer + * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value + * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value + * + * Print human readable fault information (CIK). + */ +static void cik_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr, u32 mc_client) +{ + u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; + u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; + u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; + char *block = (char *)&mc_client; + + printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", + protections, vmid, addr, + (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", + block, mc_id); +} + +/** * cik_vm_flush - cik vm flush using the CP * * @rdev: radeon_device pointer @@ -5507,6 +5519,7 @@ int cik_irq_process(struct radeon_device *rdev) u32 ring_index; bool queue_hotplug = false; bool queue_reset = false; + u32 addr, status, mc_client; if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; @@ -5742,11 +5755,15 @@ restart_ih: break; case 146: case 147: + addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); + status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); + mc_client = RREG32(VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT); dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + addr); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + status); + cik_vm_decode_fault(rdev, status, addr, mc_client); /* reset addr and status */ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); break; @@ -6961,7 +6978,7 @@ int cik_uvd_resume(struct radeon_device *rdev) /* programm the VCPU memory controller bits 0-27 */ addr = rdev->uvd.gpu_addr >> 3; - size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 63514b95889a..7e9275eaef80 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -136,6 +136,22 @@ #define VM_INVALIDATE_RESPONSE 0x147c #define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC +#define PROTECTIONS_MASK (0xf << 0) +#define PROTECTIONS_SHIFT 0 + /* bit 0: range + * bit 1: pde0 + * bit 2: valid + * bit 3: read + * bit 4: write + */ +#define MEMORY_CLIENT_ID_MASK (0xff << 12) +#define MEMORY_CLIENT_ID_SHIFT 12 +#define MEMORY_CLIENT_RW_MASK (1 << 24) +#define MEMORY_CLIENT_RW_SHIFT 24 +#define FAULT_VMID_MASK (0xf << 25) +#define FAULT_VMID_SHIFT 25 + +#define VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT 0x14E4 #define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e49059dc9b8f..526e428cb4d0 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -139,6 +139,8 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev); void evergreen_program_aspm(struct radeon_device *rdev); extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev, int ring, u32 cp_int_cntl); +extern void cayman_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr); static const u32 evergreen_golden_registers[] = { @@ -4586,6 +4588,7 @@ int evergreen_irq_process(struct radeon_device *rdev) bool queue_hotplug = false; bool queue_hdmi = false; bool queue_thermal = false; + u32 status, addr; if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; @@ -4872,11 +4875,14 @@ restart_ih: break; case 146: case 147: + addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); + status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + addr); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + status); + cayman_vm_decode_fault(rdev, status, addr); /* reset addr and status */ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); break; diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index b9c6f7675e59..b0d3fb341417 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -177,6 +177,9 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode uint32_t offset; ssize_t err; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (!dig->afmt->enabled) return; @@ -280,6 +283,9 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (enable && dig->afmt->enabled) return; diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index f30127cb30ef..56bd4f3be4fe 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> #include <drm/drmP.h> @@ -684,7 +683,6 @@ int ni_mc_load_microcode(struct radeon_device *rdev) int ni_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; const char *rlc_chip_name; size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size; @@ -694,13 +692,6 @@ int ni_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_BARTS: chip_name = "BARTS"; @@ -753,7 +744,7 @@ int ni_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -765,7 +756,7 @@ int ni_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -776,7 +767,7 @@ int ni_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -789,7 +780,7 @@ int ni_init_microcode(struct radeon_device *rdev) /* no MC ucode on TN */ if (!(rdev->flags & RADEON_IS_IGP)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mc_fw->size != mc_req_size) { @@ -802,7 +793,7 @@ int ni_init_microcode(struct radeon_device *rdev) if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); - err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->smc_fw->size != smc_req_size) { @@ -814,8 +805,6 @@ int ni_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -2461,6 +2450,167 @@ void cayman_vm_fini(struct radeon_device *rdev) { } +/** + * cayman_vm_decode_fault - print human readable fault info + * + * @rdev: radeon_device pointer + * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value + * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value + * + * Print human readable fault information (cayman/TN). + */ +void cayman_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr) +{ + u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; + u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; + u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; + char *block; + + switch (mc_id) { + case 32: + case 16: + case 96: + case 80: + case 160: + case 144: + case 224: + case 208: + block = "CB"; + break; + case 33: + case 17: + case 97: + case 81: + case 161: + case 145: + case 225: + case 209: + block = "CB_FMASK"; + break; + case 34: + case 18: + case 98: + case 82: + case 162: + case 146: + case 226: + case 210: + block = "CB_CMASK"; + break; + case 35: + case 19: + case 99: + case 83: + case 163: + case 147: + case 227: + case 211: + block = "CB_IMMED"; + break; + case 36: + case 20: + case 100: + case 84: + case 164: + case 148: + case 228: + case 212: + block = "DB"; + break; + case 37: + case 21: + case 101: + case 85: + case 165: + case 149: + case 229: + case 213: + block = "DB_HTILE"; + break; + case 38: + case 22: + case 102: + case 86: + case 166: + case 150: + case 230: + case 214: + block = "SX"; + break; + case 39: + case 23: + case 103: + case 87: + case 167: + case 151: + case 231: + case 215: + block = "DB_STEN"; + break; + case 40: + case 24: + case 104: + case 88: + case 232: + case 216: + case 168: + case 152: + block = "TC_TFETCH"; + break; + case 41: + case 25: + case 105: + case 89: + case 233: + case 217: + case 169: + case 153: + block = "TC_VFETCH"; + break; + case 42: + case 26: + case 106: + case 90: + case 234: + case 218: + case 170: + case 154: + block = "VC"; + break; + case 112: + block = "CP"; + break; + case 113: + case 114: + block = "SH"; + break; + case 115: + block = "VGT"; + break; + case 178: + block = "IH"; + break; + case 51: + block = "RLC"; + break; + case 55: + block = "DMA"; + break; + case 56: + block = "HDP"; + break; + default: + block = "unknown"; + break; + } + + printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", + protections, vmid, addr, + (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", + block, mc_id); +} + #define R600_ENTRY_VALID (1 << 0) #define R600_PTE_SYSTEM (1 << 1) #define R600_PTE_SNOOPED (1 << 2) diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index fe24a93542ec..22421bc80c0d 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -133,6 +133,22 @@ #define VM_CONTEXT1_CNTL2 0x1434 #define VM_INVALIDATE_REQUEST 0x1478 #define VM_INVALIDATE_RESPONSE 0x147c +#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC +#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC +#define PROTECTIONS_MASK (0xf << 0) +#define PROTECTIONS_SHIFT 0 + /* bit 0: range + * bit 2: pde0 + * bit 3: valid + * bit 4: read + * bit 5: write + */ +#define MEMORY_CLIENT_ID_MASK (0xff << 12) +#define MEMORY_CLIENT_ID_SHIFT 12 +#define MEMORY_CLIENT_RW_MASK (1 << 24) +#define MEMORY_CLIENT_RW_SHIFT 24 +#define FAULT_VMID_MASK (0x7 << 25) +#define FAULT_VMID_SHIFT 25 #define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518 #define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR 0x151c #define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153C diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index c9affefd79f6..75349cdaa84b 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -39,7 +39,6 @@ #include "atom.h" #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/module.h> #include "r100_reg_safe.h" @@ -989,18 +988,11 @@ void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) /* Load the microcode for the CP */ static int r100_cp_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *fw_name = NULL; int err; DRM_DEBUG_KMS("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || (rdev->family == CHIP_RS200)) { @@ -1042,8 +1034,7 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) fw_name = FIRMWARE_R520; } - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); - platform_device_unregister(pdev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) { printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n", fw_name); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2d3655f7f41e..393880a09412 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -28,7 +28,6 @@ #include <linux/slab.h> #include <linux/seq_file.h> #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/module.h> #include <drm/drmP.h> #include <drm/radeon_drm.h> @@ -2144,7 +2143,6 @@ void r600_cp_stop(struct radeon_device *rdev) int r600_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; const char *rlc_chip_name; const char *smc_chip_name = "RV770"; @@ -2154,13 +2152,6 @@ int r600_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_R600: chip_name = "R600"; @@ -2272,7 +2263,7 @@ int r600_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -2284,7 +2275,7 @@ int r600_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -2295,7 +2286,7 @@ int r600_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -2307,7 +2298,7 @@ int r600_init_microcode(struct radeon_device *rdev) if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name); - err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->smc_fw->size != smc_req_size) { @@ -2319,8 +2310,6 @@ int r600_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -3019,7 +3008,7 @@ void r600_uvd_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) { struct radeon_ring *ring = &rdev->ring[fence->ring]; - uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; + uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); radeon_ring_write(ring, fence->seq); @@ -3145,6 +3134,87 @@ int r600_copy_blit(struct radeon_device *rdev, } /** + * r600_copy_cpdma - copy pages using the CP DMA engine + * + * @rdev: radeon_device pointer + * @src_offset: src GPU address + * @dst_offset: dst GPU address + * @num_gpu_pages: number of GPU pages to xfer + * @fence: radeon fence object + * + * Copy GPU paging using the CP DMA engine (r6xx+). + * Used by the radeon ttm implementation to move pages if + * registered as the asic copy callback. + */ +int r600_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct radeon_fence **fence) +{ + struct radeon_semaphore *sem = NULL; + int ring_index = rdev->asic->copy.blit_ring_index; + struct radeon_ring *ring = &rdev->ring[ring_index]; + u32 size_in_bytes, cur_size_in_bytes, tmp; + int i, num_loops; + int r = 0; + + r = radeon_semaphore_create(rdev, &sem); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + return r; + } + + size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); + num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff); + r = radeon_ring_lock(rdev, ring, num_loops * 6 + 21); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + radeon_semaphore_free(rdev, &sem, NULL); + return r; + } + + if (radeon_fence_need_sync(*fence, ring->idx)) { + radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring, + ring->idx); + radeon_fence_note_sync(*fence, ring->idx); + } else { + radeon_semaphore_free(rdev, &sem, NULL); + } + + for (i = 0; i < num_loops; i++) { + cur_size_in_bytes = size_in_bytes; + if (cur_size_in_bytes > 0x1fffff) + cur_size_in_bytes = 0x1fffff; + size_in_bytes -= cur_size_in_bytes; + tmp = upper_32_bits(src_offset) & 0xff; + if (size_in_bytes == 0) + tmp |= PACKET3_CP_DMA_CP_SYNC; + radeon_ring_write(ring, PACKET3(PACKET3_CP_DMA, 4)); + radeon_ring_write(ring, src_offset & 0xffffffff); + radeon_ring_write(ring, tmp); + radeon_ring_write(ring, dst_offset & 0xffffffff); + radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff); + radeon_ring_write(ring, cur_size_in_bytes); + src_offset += cur_size_in_bytes; + dst_offset += cur_size_in_bytes; + } + radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); + radeon_ring_write(ring, WAIT_CP_DMA_IDLE_bit); + + r = radeon_fence_emit(rdev, fence, ring->idx); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return r; + } + + radeon_ring_unlock_commit(rdev, ring); + radeon_semaphore_free(rdev, &sem, *fence); + + return r; +} + +/** * r600_copy_dma - copy pages using the DMA engine * * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index e73b2a73494a..f48240bb8c56 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -266,6 +266,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod uint32_t offset; ssize_t err; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (!dig->afmt->enabled) return; @@ -448,6 +451,9 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; u32 hdmi = HDMI0_ERROR_ACK; + if (!dig || !dig->afmt) + return; + /* Silent, r600_hdmi_enable will raise WARN for us */ if (enable && dig->afmt->enabled) return; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index f1b3084d8f51..8e3fe815edab 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -602,6 +602,7 @@ #define L2_BUSY (1 << 0) #define WAIT_UNTIL 0x8040 +#define WAIT_CP_DMA_IDLE_bit (1 << 8) #define WAIT_2D_IDLE_bit (1 << 14) #define WAIT_3D_IDLE_bit (1 << 15) #define WAIT_2D_IDLECLEAN_bit (1 << 16) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 9b7025d02cd0..001081757895 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -455,6 +455,7 @@ struct radeon_sa_manager { uint64_t gpu_addr; void *cpu_ptr; uint32_t domain; + uint32_t align; }; struct radeon_sa_bo; @@ -783,6 +784,11 @@ struct radeon_mec { /* number of entries in page table */ #define RADEON_VM_PTE_COUNT (1 << RADEON_VM_BLOCK_SIZE) +/* PTBs (Page Table Blocks) need to be aligned to 32K */ +#define RADEON_VM_PTB_ALIGN_SIZE 32768 +#define RADEON_VM_PTB_ALIGN_MASK (RADEON_VM_PTB_ALIGN_SIZE - 1) +#define RADEON_VM_PTB_ALIGN(a) (((a) + RADEON_VM_PTB_ALIGN_MASK) & ~RADEON_VM_PTB_ALIGN_MASK) + struct radeon_vm { struct list_head list; struct list_head va; @@ -1460,6 +1466,8 @@ struct radeon_uvd { struct radeon_bo *vcpu_bo; void *cpu_addr; uint64_t gpu_addr; + void *saved_bo; + unsigned fw_size; atomic_t handles[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; struct delayed_work idle_work; @@ -2054,7 +2062,6 @@ struct radeon_device { const struct firmware *rlc_fw; /* r6/700 RLC firmware */ const struct firmware *mc_fw; /* NI MC firmware */ const struct firmware *ce_fw; /* SI CE firmware */ - const struct firmware *uvd_fw; /* UVD firmware */ const struct firmware *mec_fw; /* CIK MEC firmware */ const struct firmware *sdma_fw; /* CIK SDMA firmware */ const struct firmware *smc_fw; /* SMC firmware */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 097077499cc6..fea997e247ba 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1026,8 +1026,8 @@ static struct radeon_asic r600_asic = { .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma = &r600_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, - .copy_ring_index = R600_RING_TYPE_DMA_INDEX, + .copy = &r600_copy_cpdma, + .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, }, .surface = { .set_reg = r600_set_surface_reg, @@ -1119,8 +1119,8 @@ static struct radeon_asic rv6xx_asic = { .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma = &r600_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, - .copy_ring_index = R600_RING_TYPE_DMA_INDEX, + .copy = &r600_copy_cpdma, + .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, }, .surface = { .set_reg = r600_set_surface_reg, @@ -1229,8 +1229,8 @@ static struct radeon_asic rs780_asic = { .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX, .dma = &r600_copy_dma, .dma_ring_index = R600_RING_TYPE_DMA_INDEX, - .copy = &r600_copy_dma, - .copy_ring_index = R600_RING_TYPE_DMA_INDEX, + .copy = &r600_copy_cpdma, + .copy_ring_index = RADEON_RING_TYPE_GFX_INDEX, }, .surface = { .set_reg = r600_set_surface_reg, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 45d0693cddd5..b04b5789f4a8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -340,6 +340,9 @@ int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); int r600_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, struct radeon_fence **fence); +int r600_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, struct radeon_fence **fence); int r600_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, struct radeon_fence **fence); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index ddb8f8e04eb5..7ddb0efe2408 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) } else { /* put fence directly behind firmware */ - index = ALIGN(rdev->uvd_fw->size, 8); + index = ALIGN(rdev->uvd.fw_size, 8); rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index; rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 43ec4a401f07..d9d31a383276 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -466,7 +466,8 @@ int radeon_vm_manager_init(struct radeon_device *rdev) size += rdev->vm_manager.max_pfn * 8; size *= 2; r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager, - RADEON_GPU_PAGE_ALIGN(size), + RADEON_VM_PTB_ALIGN(size), + RADEON_VM_PTB_ALIGN_SIZE, RADEON_GEM_DOMAIN_VRAM); if (r) { dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n", @@ -620,10 +621,10 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm) } retry: - pd_size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev)); + pd_size = RADEON_VM_PTB_ALIGN(radeon_vm_directory_size(rdev)); r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->page_directory, pd_size, - RADEON_GPU_PAGE_SIZE, false); + RADEON_VM_PTB_ALIGN_SIZE, false); if (r == -ENOMEM) { r = radeon_vm_evict(rdev, vm); if (r) @@ -952,8 +953,8 @@ static int radeon_vm_update_pdes(struct radeon_device *rdev, retry: r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->page_tables[pt_idx], - RADEON_VM_PTE_COUNT * 8, - RADEON_GPU_PAGE_SIZE, false); + RADEON_VM_PTB_ALIGN(RADEON_VM_PTE_COUNT * 8), + RADEON_VM_PTB_ALIGN_SIZE, false); if (r == -ENOMEM) { r = radeon_vm_evict(rdev, vm); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index bcdefd1dcd43..081886b0642d 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -260,10 +260,6 @@ int radeon_irq_kms_init(struct radeon_device *rdev) { int r = 0; - INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); - INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); - INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); - spin_lock_init(&rdev->irq.lock); r = drm_vblank_init(rdev->ddev, rdev->num_crtc); if (r) { @@ -285,6 +281,11 @@ int radeon_irq_kms_init(struct radeon_device *rdev) rdev->irq.installed = false; return r; } + + INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); + INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); + INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); + DRM_INFO("radeon: irq initialized.\n"); return 0; } @@ -304,8 +305,8 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) rdev->irq.installed = false; if (rdev->msi_enabled) pci_disable_msi(rdev->pdev); + flush_work(&rdev->hotplug_work); } - flush_work(&rdev->hotplug_work); } /** diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 0219d263e2df..2020bf4a3830 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -377,6 +377,7 @@ int radeon_bo_list_validate(struct ww_acquire_ctx *ticket, domain = lobj->alt_domain; goto retry; } + ttm_eu_backoff_reservation(ticket, head); return r; } } diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 91519a5622b4..49c82c480013 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -174,7 +174,7 @@ static inline void * radeon_sa_bo_cpu_addr(struct radeon_sa_bo *sa_bo) extern int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain); + unsigned size, u32 align, u32 domain); extern void radeon_sa_bo_manager_fini(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager); extern int radeon_sa_bo_manager_start(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 5f1c51a776ed..fb5ea6208970 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -224,6 +224,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev) } r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, RADEON_IB_POOL_SIZE*64*1024, + RADEON_GPU_PAGE_SIZE, RADEON_GEM_DOMAIN_GTT); if (r) { return r; diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 0abe5a9431bb..f0bac68254b7 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -49,7 +49,7 @@ static void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager); int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain) + unsigned size, u32 align, u32 domain) { int i, r; @@ -57,13 +57,14 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, sa_manager->bo = NULL; sa_manager->size = size; sa_manager->domain = domain; + sa_manager->align = align; sa_manager->hole = &sa_manager->olist; INIT_LIST_HEAD(&sa_manager->olist); for (i = 0; i < RADEON_NUM_RINGS; ++i) { INIT_LIST_HEAD(&sa_manager->flist[i]); } - r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, + r = radeon_bo_create(rdev, size, align, true, domain, NULL, &sa_manager->bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); @@ -317,7 +318,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, unsigned tries[RADEON_NUM_RINGS]; int i, r; - BUG_ON(align > RADEON_GPU_PAGE_SIZE); + BUG_ON(align > sa_manager->align); BUG_ON(size > sa_manager->size); *sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 41efcec28cd8..414fd145d20e 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -56,20 +56,13 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); int radeon_uvd_init(struct radeon_device *rdev) { - struct platform_device *pdev; + const struct firmware *fw; unsigned long bo_size; const char *fw_name; int i, r; INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); - pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0); - r = IS_ERR(pdev); - if (r) { - dev_err(rdev->dev, "radeon_uvd: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_RV710: case CHIP_RV730: @@ -112,17 +105,14 @@ int radeon_uvd_init(struct radeon_device *rdev) return -EINVAL; } - r = request_firmware(&rdev->uvd_fw, fw_name, &pdev->dev); + r = request_firmware(&fw, fw_name, rdev->dev); if (r) { dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", fw_name); - platform_device_unregister(pdev); return r; } - platform_device_unregister(pdev); - - bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + + bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); @@ -131,16 +121,35 @@ int radeon_uvd_init(struct radeon_device *rdev) return r; } - r = radeon_uvd_resume(rdev); - if (r) + r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); + if (r) { + radeon_bo_unref(&rdev->uvd.vcpu_bo); + dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); return r; + } - memset(rdev->uvd.cpu_addr, 0, bo_size); - memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); + r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, + &rdev->uvd.gpu_addr); + if (r) { + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + radeon_bo_unref(&rdev->uvd.vcpu_bo); + dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); + return r; + } - r = radeon_uvd_suspend(rdev); - if (r) + r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); + if (r) { + dev_err(rdev->dev, "(%d) UVD map failed\n", r); return r; + } + + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + + rdev->uvd.fw_size = fw->size; + memset(rdev->uvd.cpu_addr, 0, bo_size); + memcpy(rdev->uvd.cpu_addr, fw->data, fw->size); + + release_firmware(fw); for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { atomic_set(&rdev->uvd.handles[i], 0); @@ -152,71 +161,47 @@ int radeon_uvd_init(struct radeon_device *rdev) void radeon_uvd_fini(struct radeon_device *rdev) { - radeon_uvd_suspend(rdev); - radeon_bo_unref(&rdev->uvd.vcpu_bo); -} - -int radeon_uvd_suspend(struct radeon_device *rdev) -{ int r; if (rdev->uvd.vcpu_bo == NULL) - return 0; + return; r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); if (!r) { radeon_bo_kunmap(rdev->uvd.vcpu_bo); radeon_bo_unpin(rdev->uvd.vcpu_bo); - rdev->uvd.cpu_addr = NULL; - if (!radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_CPU, NULL)) { - radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); - } radeon_bo_unreserve(rdev->uvd.vcpu_bo); - - if (rdev->uvd.cpu_addr) { - radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); - } else { - rdev->fence_drv[R600_RING_TYPE_UVD_INDEX].cpu_addr = NULL; - } } - return r; + + radeon_bo_unref(&rdev->uvd.vcpu_bo); } -int radeon_uvd_resume(struct radeon_device *rdev) +int radeon_uvd_suspend(struct radeon_device *rdev) { - int r; + unsigned size; if (rdev->uvd.vcpu_bo == NULL) - return -EINVAL; + return 0; - r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); - if (r) { - radeon_bo_unref(&rdev->uvd.vcpu_bo); - dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); - return r; - } + size = radeon_bo_size(rdev->uvd.vcpu_bo); + rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); + memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size); - /* Have been pin in cpu unmap unpin */ - radeon_bo_kunmap(rdev->uvd.vcpu_bo); - radeon_bo_unpin(rdev->uvd.vcpu_bo); + return 0; +} - r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, - &rdev->uvd.gpu_addr); - if (r) { - radeon_bo_unreserve(rdev->uvd.vcpu_bo); - radeon_bo_unref(&rdev->uvd.vcpu_bo); - dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); - return r; - } +int radeon_uvd_resume(struct radeon_device *rdev) +{ + if (rdev->uvd.vcpu_bo == NULL) + return -EINVAL; - r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); - if (r) { - dev_err(rdev->dev, "(%d) UVD map failed\n", r); - return r; + if (rdev->uvd.saved_bo != NULL) { + unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo); + memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size); + kfree(rdev->uvd.saved_bo); + rdev->uvd.saved_bo = NULL; } - radeon_bo_unreserve(rdev->uvd.vcpu_bo); - return 0; } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4a62ad2e5399..30ea14e8854c 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev) /* programm the VCPU memory controller bits 0-27 */ addr = rdev->uvd.gpu_addr >> 3; - size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 234906709067..d3f05076f385 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/module.h> #include <drm/drmP.h> @@ -1541,7 +1540,6 @@ static int si_mc_load_microcode(struct radeon_device *rdev) static int si_init_microcode(struct radeon_device *rdev) { - struct platform_device *pdev; const char *chip_name; const char *rlc_chip_name; size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size; @@ -1551,13 +1549,6 @@ static int si_init_microcode(struct radeon_device *rdev) DRM_DEBUG("\n"); - pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); - err = IS_ERR(pdev); - if (err) { - printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); - return -EINVAL; - } - switch (rdev->family) { case CHIP_TAHITI: chip_name = "TAHITI"; @@ -1615,7 +1606,7 @@ static int si_init_microcode(struct radeon_device *rdev) DRM_INFO("Loading %s Microcode\n", chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); - err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->pfp_fw->size != pfp_req_size) { @@ -1627,7 +1618,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); - err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->me_fw->size != me_req_size) { @@ -1638,7 +1629,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); - err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->ce_fw->size != ce_req_size) { @@ -1649,7 +1640,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); - err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->rlc_fw->size != rlc_req_size) { @@ -1660,7 +1651,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->mc_fw->size != mc_req_size) { @@ -1671,7 +1662,7 @@ static int si_init_microcode(struct radeon_device *rdev) } snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); - err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) goto out; if (rdev->smc_fw->size != smc_req_size) { @@ -1682,8 +1673,6 @@ static int si_init_microcode(struct radeon_device *rdev) } out: - platform_device_unregister(pdev); - if (err) { if (err != -EINVAL) printk(KERN_ERR @@ -4401,6 +4390,270 @@ void si_vm_fini(struct radeon_device *rdev) } /** + * si_vm_decode_fault - print human readable fault info + * + * @rdev: radeon_device pointer + * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value + * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value + * + * Print human readable fault information (SI). + */ +static void si_vm_decode_fault(struct radeon_device *rdev, + u32 status, u32 addr) +{ + u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT; + u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT; + u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT; + char *block; + + if (rdev->family == CHIP_TAHITI) { + switch (mc_id) { + case 160: + case 144: + case 96: + case 80: + case 224: + case 208: + case 32: + case 16: + block = "CB"; + break; + case 161: + case 145: + case 97: + case 81: + case 225: + case 209: + case 33: + case 17: + block = "CB_FMASK"; + break; + case 162: + case 146: + case 98: + case 82: + case 226: + case 210: + case 34: + case 18: + block = "CB_CMASK"; + break; + case 163: + case 147: + case 99: + case 83: + case 227: + case 211: + case 35: + case 19: + block = "CB_IMMED"; + break; + case 164: + case 148: + case 100: + case 84: + case 228: + case 212: + case 36: + case 20: + block = "DB"; + break; + case 165: + case 149: + case 101: + case 85: + case 229: + case 213: + case 37: + case 21: + block = "DB_HTILE"; + break; + case 167: + case 151: + case 103: + case 87: + case 231: + case 215: + case 39: + case 23: + block = "DB_STEN"; + break; + case 72: + case 68: + case 64: + case 8: + case 4: + case 0: + case 136: + case 132: + case 128: + case 200: + case 196: + case 192: + block = "TC"; + break; + case 112: + case 48: + block = "CP"; + break; + case 49: + case 177: + case 50: + case 178: + block = "SH"; + break; + case 53: + case 190: + block = "VGT"; + break; + case 117: + block = "IH"; + break; + case 51: + case 115: + block = "RLC"; + break; + case 119: + case 183: + block = "DMA0"; + break; + case 61: + block = "DMA1"; + break; + case 248: + case 120: + block = "HDP"; + break; + default: + block = "unknown"; + break; + } + } else { + switch (mc_id) { + case 32: + case 16: + case 96: + case 80: + case 160: + case 144: + case 224: + case 208: + block = "CB"; + break; + case 33: + case 17: + case 97: + case 81: + case 161: + case 145: + case 225: + case 209: + block = "CB_FMASK"; + break; + case 34: + case 18: + case 98: + case 82: + case 162: + case 146: + case 226: + case 210: + block = "CB_CMASK"; + break; + case 35: + case 19: + case 99: + case 83: + case 163: + case 147: + case 227: + case 211: + block = "CB_IMMED"; + break; + case 36: + case 20: + case 100: + case 84: + case 164: + case 148: + case 228: + case 212: + block = "DB"; + break; + case 37: + case 21: + case 101: + case 85: + case 165: + case 149: + case 229: + case 213: + block = "DB_HTILE"; + break; + case 39: + case 23: + case 103: + case 87: + case 167: + case 151: + case 231: + case 215: + block = "DB_STEN"; + break; + case 72: + case 68: + case 8: + case 4: + case 136: + case 132: + case 200: + case 196: + block = "TC"; + break; + case 112: + case 48: + block = "CP"; + break; + case 49: + case 177: + case 50: + case 178: + block = "SH"; + break; + case 53: + block = "VGT"; + break; + case 117: + block = "IH"; + break; + case 51: + case 115: + block = "RLC"; + break; + case 119: + case 183: + block = "DMA0"; + break; + case 61: + block = "DMA1"; + break; + case 248: + case 120: + block = "HDP"; + break; + default: + block = "unknown"; + break; + } + } + + printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n", + protections, vmid, addr, + (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read", + block, mc_id); +} + +/** * si_vm_set_page - update the page tables using the CP * * @rdev: radeon_device pointer @@ -5766,6 +6019,7 @@ int si_irq_process(struct radeon_device *rdev) u32 ring_index; bool queue_hotplug = false; bool queue_thermal = false; + u32 status, addr; if (!rdev->ih.enabled || rdev->shutdown) return IRQ_NONE; @@ -6001,11 +6255,14 @@ restart_ih: break; case 146: case 147: + addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); + status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS); dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR)); + addr); dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", - RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS)); + status); + si_vm_decode_fault(rdev, status, addr); /* reset addr and status */ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); break; diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 12a20eb77d0c..2c8da27a929f 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -367,6 +367,20 @@ #define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC #define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC +#define PROTECTIONS_MASK (0xf << 0) +#define PROTECTIONS_SHIFT 0 + /* bit 0: range + * bit 1: pde0 + * bit 2: valid + * bit 3: read + * bit 4: write + */ +#define MEMORY_CLIENT_ID_MASK (0xff << 12) +#define MEMORY_CLIENT_ID_SHIFT 12 +#define MEMORY_CLIENT_RW_MASK (1 << 24) +#define MEMORY_CLIENT_RW_SHIFT 24 +#define FAULT_VMID_MASK (0xf << 25) +#define FAULT_VMID_SHIFT 25 #define VM_INVALIDATE_REQUEST 0x1478 #define VM_INVALIDATE_RESPONSE 0x147c diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 11b6b9924f1b..c0a850319908 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1732,7 +1732,13 @@ int sumo_dpm_init(struct radeon_device *rdev) pi->enable_sclk_ds = true; pi->enable_dynamic_m3_arbiter = false; pi->enable_dynamic_patch_ps = true; - pi->enable_gfx_power_gating = true; + /* Some PALM chips don't seem to properly ungate gfx when UVD is in use; + * for now just disable gfx PG. + */ + if (rdev->family == CHIP_PALM) + pi->enable_gfx_power_gating = false; + else + pi->enable_gfx_power_gating = true; pi->enable_gfx_clock_gating = true; pi->enable_mg_clock_gating = true; pi->enable_auto_thermal_throttling = true; @@ -1845,6 +1851,8 @@ int sumo_dpm_force_performance_level(struct radeon_device *rdev, return 0; if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + if (pi->enable_boost) + sumo_enable_boost(rdev, rps, false); sumo_power_level_enable(rdev, ps->num_levels - 1, true); sumo_set_forced_level(rdev, ps->num_levels - 1); sumo_set_forced_mode_enabled(rdev); @@ -1855,6 +1863,8 @@ int sumo_dpm_force_performance_level(struct radeon_device *rdev, sumo_set_forced_mode_enabled(rdev); sumo_set_forced_mode(rdev, false); } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + if (pi->enable_boost) + sumo_enable_boost(rdev, rps, false); sumo_power_level_enable(rdev, 0, true); sumo_set_forced_level(rdev, 0); sumo_set_forced_mode_enabled(rdev); @@ -1868,6 +1878,8 @@ int sumo_dpm_force_performance_level(struct radeon_device *rdev, for (i = 0; i < ps->num_levels; i++) { sumo_power_level_enable(rdev, i, true); } + if (pi->enable_boost) + sumo_enable_boost(rdev, rps, true); } rdev->pm.dpm.forced_level = level; |