diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
97 files changed, 6102 insertions, 2796 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index dbcbfe80aac0..d01b87991422 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -60,7 +60,7 @@ radeon-y := radeon_drv.o # add UMS driver radeon-$(CONFIG_DRM_RADEON_UMS)+= radeon_cp.o radeon_state.o radeon_mem.o \ - radeon_irq.o r300_cmdbuf.o r600_cp.o r600_blit.o + radeon_irq.o r300_cmdbuf.o r600_cp.o r600_blit.o drm_buffer.o # add KMS driver radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ @@ -72,15 +72,15 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit_shaders.o \ - radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o dce3_1_afmt.o \ + radeon_pm.o atombios_dp.o r600_hdmi.o dce3_1_afmt.o \ evergreen.o evergreen_cs.o evergreen_blit_shaders.o \ evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \ atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ - si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \ + si_blit_shaders.o radeon_prime.o cik.o cik_blit_shaders.o \ r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \ rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \ trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \ - ci_dpm.o dce6_afmt.o radeon_vm.o + ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o # add async DMA block radeon-y += \ diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 15da7ef344a4..ec1593a6a561 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1217,7 +1217,7 @@ free: return ret; } -int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) +int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t * params) { int r; @@ -1238,6 +1238,15 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) return r; } +int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) +{ + int r; + mutex_lock(&ctx->scratch_mutex); + r = atom_execute_table_scratch_unlocked(ctx, index, params); + mutex_unlock(&ctx->scratch_mutex); + return r; +} + static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; static void atom_index_iio(struct atom_context *ctx, int base) diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index feba6b8d36b3..6d014ddb6b78 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -125,6 +125,7 @@ struct card_info { struct atom_context { struct card_info *card; struct mutex mutex; + struct mutex scratch_mutex; void *bios; uint32_t cmd_table, data_table; uint16_t *iio; @@ -145,6 +146,7 @@ extern int atom_debug; struct atom_context *atom_parse(struct card_info *, void *); int atom_execute_table(struct atom_context *, int, uint32_t *); +int atom_execute_table_scratch_unlocked(struct atom_context *, int, uint32_t *); int atom_asic_init(struct atom_context *); void atom_destroy(struct atom_context *); bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index b1e11f8434e2..11ba9d21b89b 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -100,6 +100,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, memset(&args, 0, sizeof(args)); mutex_lock(&chan->mutex); + mutex_lock(&rdev->mode_info.atom_context->scratch_mutex); base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); @@ -113,7 +114,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, if (ASIC_IS_DCE4(rdev)) args.v2.ucHPD_ID = chan->rec.hpd; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table_scratch_unlocked(rdev->mode_info.atom_context, index, (uint32_t *)&args); *ack = args.v1.ucReplyStatus; @@ -147,6 +148,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, r = recv_bytes; done: + mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex); mutex_unlock(&chan->mutex); return r; @@ -232,8 +234,8 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector) /***** general DP utility functions *****/ -#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200 -#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5 +#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3 +#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3 static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE], int lane_count, @@ -405,16 +407,13 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) u8 msg[DP_DPCD_SIZE]; int ret; - char dpcd_hex_dump[DP_DPCD_SIZE * 3]; - ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, DP_DPCD_SIZE); if (ret > 0) { memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); - hex_dump_to_buffer(dig_connector->dpcd, sizeof(dig_connector->dpcd), - 32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false); - DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); + DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd), + dig_connector->dpcd); radeon_dp_probe_oui(radeon_connector); diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 7d68203a3737..b8cd7975f797 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -291,29 +291,6 @@ static void radeon_atom_backlight_exit(struct radeon_encoder *encoder) bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, struct drm_display_mode *mode); - -static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: - return true; - default: - return false; - } -} - static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -331,12 +308,10 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; - /* get the native mode for LVDS */ - if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) + /* get the native mode for scaling */ + if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { radeon_panel_mode_fixup(encoder, adjusted_mode); - - /* get the native mode for TV */ - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { + } else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; if (tv_dac) { if (tv_dac->tv_std == TV_STD_NTSC || @@ -346,6 +321,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, else radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); } + } else if (radeon_encoder->rmx_type != RMX_OFF) { + radeon_panel_mode_fixup(encoder, adjusted_mode); } if (ASIC_IS_DCE3(rdev) && @@ -716,7 +693,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if (radeon_connector->use_digital && (radeon_connector->audio == RADEON_AUDIO_ENABLE)) return ATOM_ENCODER_MODE_HDMI; - else if (drm_detect_hdmi_monitor(radeon_connector->edid) && + else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && (radeon_connector->audio == RADEON_AUDIO_AUTO)) return ATOM_ENCODER_MODE_HDMI; else if (radeon_connector->use_digital) @@ -735,7 +712,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if (radeon_audio != 0) { if (radeon_connector->audio == RADEON_AUDIO_ENABLE) return ATOM_ENCODER_MODE_HDMI; - else if (drm_detect_hdmi_monitor(radeon_connector->edid) && + else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && (radeon_connector->audio == RADEON_AUDIO_AUTO)) return ATOM_ENCODER_MODE_HDMI; else @@ -755,7 +732,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) } else if (radeon_audio != 0) { if (radeon_connector->audio == RADEON_AUDIO_ENABLE) return ATOM_ENCODER_MODE_HDMI; - else if (drm_detect_hdmi_monitor(radeon_connector->edid) && + else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && (radeon_connector->audio == RADEON_AUDIO_AUTO)) return ATOM_ENCODER_MODE_HDMI; else diff --git a/drivers/gpu/drm/radeon/atombios_i2c.c b/drivers/gpu/drm/radeon/atombios_i2c.c index 9c570fb15b8c..4157780585a0 100644 --- a/drivers/gpu/drm/radeon/atombios_i2c.c +++ b/drivers/gpu/drm/radeon/atombios_i2c.c @@ -48,6 +48,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, memset(&args, 0, sizeof(args)); mutex_lock(&chan->mutex); + mutex_lock(&rdev->mode_info.atom_context->scratch_mutex); base = (unsigned char *)rdev->mode_info.atom_context->scratch; @@ -82,7 +83,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, args.ucSlaveAddr = slave_addr << 1; args.ucLineNumber = chan->rec.i2c_id; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table_scratch_unlocked(rdev->mode_info.atom_context, index, (uint32_t *)&args); /* error */ if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { @@ -95,6 +96,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, radeon_atom_copy_swap(buf, base, num, false); done: + mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex); mutex_unlock(&chan->mutex); return r; diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index f81d7ca134db..0b2929de9f41 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -24,6 +24,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "btcd.h" #include "r600_dpm.h" #include "cypress_dpm.h" @@ -2099,7 +2100,6 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev, bool disable_mclk_switching; u32 mclk, sclk; u16 vddc, vddci; - u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; if ((rdev->pm.dpm.new_active_crtc_count > 1) || btc_dpm_vblank_too_short(rdev)) @@ -2141,39 +2141,6 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev, ps->low.vddci = max_limits->vddci; } - /* limit clocks to max supported clocks based on voltage dependency tables */ - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, - &max_sclk_vddc); - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, - &max_mclk_vddci); - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, - &max_mclk_vddc); - - if (max_sclk_vddc) { - if (ps->low.sclk > max_sclk_vddc) - ps->low.sclk = max_sclk_vddc; - if (ps->medium.sclk > max_sclk_vddc) - ps->medium.sclk = max_sclk_vddc; - if (ps->high.sclk > max_sclk_vddc) - ps->high.sclk = max_sclk_vddc; - } - if (max_mclk_vddci) { - if (ps->low.mclk > max_mclk_vddci) - ps->low.mclk = max_mclk_vddci; - if (ps->medium.mclk > max_mclk_vddci) - ps->medium.mclk = max_mclk_vddci; - if (ps->high.mclk > max_mclk_vddci) - ps->high.mclk = max_mclk_vddci; - } - if (max_mclk_vddc) { - if (ps->low.mclk > max_mclk_vddc) - ps->low.mclk = max_mclk_vddc; - if (ps->medium.mclk > max_mclk_vddc) - ps->medium.mclk = max_mclk_vddc; - if (ps->high.mclk > max_mclk_vddc) - ps->high.mclk = max_mclk_vddc; - } - /* XXX validate the min clocks required for display */ if (disable_mclk_switching) { diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index 584090ac3eb9..11a55e9dad7f 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -24,6 +24,7 @@ #include <linux/firmware.h> #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "radeon_ucode.h" #include "cikd.h" #include "r600_dpm.h" @@ -162,8 +163,6 @@ static const struct ci_pt_config_reg didt_config_ci[] = }; extern u8 rv770_get_memory_module_index(struct radeon_device *rdev); -extern void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, - u32 *max_clock); extern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev, u32 arb_freq_src, u32 arb_freq_dest); extern u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock); @@ -748,7 +747,6 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_clock_and_voltage_limits *max_limits; bool disable_mclk_switching; u32 sclk, mclk; - u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; int i; if (rps->vce_active) { @@ -784,29 +782,6 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev, } } - /* limit clocks to max supported clocks based on voltage dependency tables */ - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, - &max_sclk_vddc); - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, - &max_mclk_vddci); - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, - &max_mclk_vddc); - - for (i = 0; i < ps->performance_level_count; i++) { - if (max_sclk_vddc) { - if (ps->performance_levels[i].sclk > max_sclk_vddc) - ps->performance_levels[i].sclk = max_sclk_vddc; - } - if (max_mclk_vddci) { - if (ps->performance_levels[i].mclk > max_mclk_vddci) - ps->performance_levels[i].mclk = max_mclk_vddci; - } - if (max_mclk_vddc) { - if (ps->performance_levels[i].mclk > max_mclk_vddc) - ps->performance_levels[i].mclk = max_mclk_vddc; - } - } - /* XXX validate the min clocks required for display */ if (disable_mclk_switching) { @@ -869,6 +844,9 @@ static int ci_set_thermal_temperature_range(struct radeon_device *rdev, WREG32_SMC(CG_THERMAL_CTRL, tmp); #endif + rdev->pm.dpm.thermal.min_temp = low_temp; + rdev->pm.dpm.thermal.max_temp = high_temp; + return 0; } @@ -940,7 +918,18 @@ static void ci_get_leakage_voltages(struct radeon_device *rdev) pi->vddc_leakage.count = 0; pi->vddci_leakage.count = 0; - if (radeon_atom_get_leakage_id_from_vbios(rdev, &leakage_id) == 0) { + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { + for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) { + virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; + if (radeon_atom_get_voltage_evv(rdev, virtual_voltage_id, &vddc) != 0) + continue; + if (vddc != 0 && vddc != virtual_voltage_id) { + pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc; + pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id; + pi->vddc_leakage.count++; + } + } + } else if (radeon_atom_get_leakage_id_from_vbios(rdev, &leakage_id) == 0) { for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) { virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i; if (radeon_atom_get_leakage_vddc_based_on_leakage_params(rdev, &vddc, &vddci, @@ -5279,9 +5268,13 @@ int ci_dpm_init(struct radeon_device *rdev) void ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { + struct ci_power_info *pi = ci_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; u32 sclk = ci_get_average_sclk_freq(rdev); u32 mclk = ci_get_average_mclk_freq(rdev); + seq_printf(m, "uvd %sabled\n", pi->uvd_enabled ? "en" : "dis"); + seq_printf(m, "vce %sabled\n", rps->vce_active ? "en" : "dis"); seq_printf(m, "power level avg sclk: %u mclk: %u\n", sclk, mclk); } diff --git a/drivers/gpu/drm/radeon/ci_smc.c b/drivers/gpu/drm/radeon/ci_smc.c index 8debc9d47362..b630edc2fd0c 100644 --- a/drivers/gpu/drm/radeon/ci_smc.c +++ b/drivers/gpu/drm/radeon/ci_smc.c @@ -213,24 +213,37 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) if (!rdev->smc_fw) return -EINVAL; - switch (rdev->family) { - case CHIP_BONAIRE: - ucode_start_address = BONAIRE_SMC_UCODE_START; - ucode_size = BONAIRE_SMC_UCODE_SIZE; - break; - case CHIP_HAWAII: - ucode_start_address = HAWAII_SMC_UCODE_START; - ucode_size = HAWAII_SMC_UCODE_SIZE; - break; - default: - DRM_ERROR("unknown asic in smc ucode loader\n"); - BUG(); + if (rdev->new_fw) { + const struct smc_firmware_header_v1_0 *hdr = + (const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data; + + radeon_ucode_print_smc_hdr(&hdr->header); + + ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); + ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); + src = (const u8 *) + (rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + } else { + switch (rdev->family) { + case CHIP_BONAIRE: + ucode_start_address = BONAIRE_SMC_UCODE_START; + ucode_size = BONAIRE_SMC_UCODE_SIZE; + break; + case CHIP_HAWAII: + ucode_start_address = HAWAII_SMC_UCODE_START; + ucode_size = HAWAII_SMC_UCODE_SIZE; + break; + default: + DRM_ERROR("unknown asic in smc ucode loader\n"); + BUG(); + } + + src = (const u8 *)rdev->smc_fw->data; } if (ucode_size & 3) return -EINVAL; - src = (const u8 *)rdev->smc_fw->data; spin_lock_irqsave(&rdev->smc_idx_lock, flags); WREG32(SMC_IND_INDEX_0, ucode_start_address); WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index c0ea66192fe0..89c01fa6dd8e 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -42,6 +42,16 @@ MODULE_FIRMWARE("radeon/BONAIRE_mc2.bin"); MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin"); MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin"); MODULE_FIRMWARE("radeon/BONAIRE_smc.bin"); + +MODULE_FIRMWARE("radeon/bonaire_pfp.bin"); +MODULE_FIRMWARE("radeon/bonaire_me.bin"); +MODULE_FIRMWARE("radeon/bonaire_ce.bin"); +MODULE_FIRMWARE("radeon/bonaire_mec.bin"); +MODULE_FIRMWARE("radeon/bonaire_mc.bin"); +MODULE_FIRMWARE("radeon/bonaire_rlc.bin"); +MODULE_FIRMWARE("radeon/bonaire_sdma.bin"); +MODULE_FIRMWARE("radeon/bonaire_smc.bin"); + MODULE_FIRMWARE("radeon/HAWAII_pfp.bin"); MODULE_FIRMWARE("radeon/HAWAII_me.bin"); MODULE_FIRMWARE("radeon/HAWAII_ce.bin"); @@ -51,18 +61,45 @@ MODULE_FIRMWARE("radeon/HAWAII_mc2.bin"); MODULE_FIRMWARE("radeon/HAWAII_rlc.bin"); MODULE_FIRMWARE("radeon/HAWAII_sdma.bin"); MODULE_FIRMWARE("radeon/HAWAII_smc.bin"); + +MODULE_FIRMWARE("radeon/hawaii_pfp.bin"); +MODULE_FIRMWARE("radeon/hawaii_me.bin"); +MODULE_FIRMWARE("radeon/hawaii_ce.bin"); +MODULE_FIRMWARE("radeon/hawaii_mec.bin"); +MODULE_FIRMWARE("radeon/hawaii_mc.bin"); +MODULE_FIRMWARE("radeon/hawaii_rlc.bin"); +MODULE_FIRMWARE("radeon/hawaii_sdma.bin"); +MODULE_FIRMWARE("radeon/hawaii_smc.bin"); + MODULE_FIRMWARE("radeon/KAVERI_pfp.bin"); MODULE_FIRMWARE("radeon/KAVERI_me.bin"); MODULE_FIRMWARE("radeon/KAVERI_ce.bin"); MODULE_FIRMWARE("radeon/KAVERI_mec.bin"); MODULE_FIRMWARE("radeon/KAVERI_rlc.bin"); MODULE_FIRMWARE("radeon/KAVERI_sdma.bin"); + +MODULE_FIRMWARE("radeon/kaveri_pfp.bin"); +MODULE_FIRMWARE("radeon/kaveri_me.bin"); +MODULE_FIRMWARE("radeon/kaveri_ce.bin"); +MODULE_FIRMWARE("radeon/kaveri_mec.bin"); +MODULE_FIRMWARE("radeon/kaveri_mec2.bin"); +MODULE_FIRMWARE("radeon/kaveri_rlc.bin"); +MODULE_FIRMWARE("radeon/kaveri_sdma.bin"); + MODULE_FIRMWARE("radeon/KABINI_pfp.bin"); MODULE_FIRMWARE("radeon/KABINI_me.bin"); MODULE_FIRMWARE("radeon/KABINI_ce.bin"); MODULE_FIRMWARE("radeon/KABINI_mec.bin"); MODULE_FIRMWARE("radeon/KABINI_rlc.bin"); MODULE_FIRMWARE("radeon/KABINI_sdma.bin"); + +MODULE_FIRMWARE("radeon/kabini_pfp.bin"); +MODULE_FIRMWARE("radeon/kabini_me.bin"); +MODULE_FIRMWARE("radeon/kabini_ce.bin"); +MODULE_FIRMWARE("radeon/kabini_mec.bin"); +MODULE_FIRMWARE("radeon/kabini_rlc.bin"); +MODULE_FIRMWARE("radeon/kabini_sdma.bin"); + MODULE_FIRMWARE("radeon/MULLINS_pfp.bin"); MODULE_FIRMWARE("radeon/MULLINS_me.bin"); MODULE_FIRMWARE("radeon/MULLINS_ce.bin"); @@ -70,6 +107,13 @@ MODULE_FIRMWARE("radeon/MULLINS_mec.bin"); MODULE_FIRMWARE("radeon/MULLINS_rlc.bin"); MODULE_FIRMWARE("radeon/MULLINS_sdma.bin"); +MODULE_FIRMWARE("radeon/mullins_pfp.bin"); +MODULE_FIRMWARE("radeon/mullins_me.bin"); +MODULE_FIRMWARE("radeon/mullins_ce.bin"); +MODULE_FIRMWARE("radeon/mullins_mec.bin"); +MODULE_FIRMWARE("radeon/mullins_rlc.bin"); +MODULE_FIRMWARE("radeon/mullins_sdma.bin"); + extern int r600_ih_ring_alloc(struct radeon_device *rdev); extern void r600_ih_ring_fini(struct radeon_device *rdev); extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); @@ -1760,27 +1804,44 @@ static void cik_srbm_select(struct radeon_device *rdev, */ int ci_mc_load_microcode(struct radeon_device *rdev) { - const __be32 *fw_data; + const __be32 *fw_data = NULL; + const __le32 *new_fw_data = NULL; u32 running, blackout = 0; - u32 *io_mc_regs; + u32 *io_mc_regs = NULL; + const __le32 *new_io_mc_regs = NULL; int i, regs_size, ucode_size; if (!rdev->mc_fw) return -EINVAL; - ucode_size = rdev->mc_fw->size / 4; + if (rdev->new_fw) { + const struct mc_firmware_header_v1_0 *hdr = + (const struct mc_firmware_header_v1_0 *)rdev->mc_fw->data; - switch (rdev->family) { - case CHIP_BONAIRE: - io_mc_regs = (u32 *)&bonaire_io_mc_regs; - regs_size = BONAIRE_IO_MC_REGS_SIZE; - break; - case CHIP_HAWAII: - io_mc_regs = (u32 *)&hawaii_io_mc_regs; - regs_size = HAWAII_IO_MC_REGS_SIZE; - break; - default: - return -EINVAL; + radeon_ucode_print_mc_hdr(&hdr->header); + + regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); + new_io_mc_regs = (const __le32 *) + (rdev->mc_fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); + ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + new_fw_data = (const __le32 *) + (rdev->mc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + } else { + ucode_size = rdev->mc_fw->size / 4; + + switch (rdev->family) { + case CHIP_BONAIRE: + io_mc_regs = (u32 *)&bonaire_io_mc_regs; + regs_size = BONAIRE_IO_MC_REGS_SIZE; + break; + case CHIP_HAWAII: + io_mc_regs = (u32 *)&hawaii_io_mc_regs; + regs_size = HAWAII_IO_MC_REGS_SIZE; + break; + default: + return -EINVAL; + } + fw_data = (const __be32 *)rdev->mc_fw->data; } running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; @@ -1797,13 +1858,21 @@ int ci_mc_load_microcode(struct radeon_device *rdev) /* load mc io regs */ for (i = 0; i < regs_size; i++) { - WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); - WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); + if (rdev->new_fw) { + WREG32(MC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(new_io_mc_regs++)); + WREG32(MC_SEQ_IO_DEBUG_DATA, le32_to_cpup(new_io_mc_regs++)); + } else { + WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); + WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); + } } /* load the MC ucode */ - fw_data = (const __be32 *)rdev->mc_fw->data; - for (i = 0; i < ucode_size; i++) - WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); + for (i = 0; i < ucode_size; i++) { + if (rdev->new_fw) + WREG32(MC_SEQ_SUP_PGM, le32_to_cpup(new_fw_data++)); + else + WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); + } /* put the engine back into the active state */ WREG32(MC_SEQ_SUP_CNTL, 0x00000008); @@ -1841,17 +1910,21 @@ int ci_mc_load_microcode(struct radeon_device *rdev) static int cik_init_microcode(struct radeon_device *rdev) { const char *chip_name; + const char *new_chip_name; size_t pfp_req_size, me_req_size, ce_req_size, mec_req_size, rlc_req_size, mc_req_size = 0, sdma_req_size, smc_req_size = 0, mc2_req_size = 0; char fw_name[30]; + int new_fw = 0; int err; + int num_fw; DRM_DEBUG("\n"); switch (rdev->family) { case CHIP_BONAIRE: chip_name = "BONAIRE"; + new_chip_name = "bonaire"; pfp_req_size = CIK_PFP_UCODE_SIZE * 4; me_req_size = CIK_ME_UCODE_SIZE * 4; ce_req_size = CIK_CE_UCODE_SIZE * 4; @@ -1861,9 +1934,11 @@ static int cik_init_microcode(struct radeon_device *rdev) mc2_req_size = BONAIRE_MC2_UCODE_SIZE * 4; sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; smc_req_size = ALIGN(BONAIRE_SMC_UCODE_SIZE, 4); + num_fw = 8; break; case CHIP_HAWAII: chip_name = "HAWAII"; + new_chip_name = "hawaii"; pfp_req_size = CIK_PFP_UCODE_SIZE * 4; me_req_size = CIK_ME_UCODE_SIZE * 4; ce_req_size = CIK_CE_UCODE_SIZE * 4; @@ -1873,142 +1948,285 @@ static int cik_init_microcode(struct radeon_device *rdev) mc2_req_size = HAWAII_MC2_UCODE_SIZE * 4; sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; smc_req_size = ALIGN(HAWAII_SMC_UCODE_SIZE, 4); + num_fw = 8; break; case CHIP_KAVERI: chip_name = "KAVERI"; + new_chip_name = "kaveri"; pfp_req_size = CIK_PFP_UCODE_SIZE * 4; me_req_size = CIK_ME_UCODE_SIZE * 4; ce_req_size = CIK_CE_UCODE_SIZE * 4; mec_req_size = CIK_MEC_UCODE_SIZE * 4; rlc_req_size = KV_RLC_UCODE_SIZE * 4; sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; + num_fw = 7; break; case CHIP_KABINI: chip_name = "KABINI"; + new_chip_name = "kabini"; pfp_req_size = CIK_PFP_UCODE_SIZE * 4; me_req_size = CIK_ME_UCODE_SIZE * 4; ce_req_size = CIK_CE_UCODE_SIZE * 4; mec_req_size = CIK_MEC_UCODE_SIZE * 4; rlc_req_size = KB_RLC_UCODE_SIZE * 4; sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; + num_fw = 6; break; case CHIP_MULLINS: chip_name = "MULLINS"; + new_chip_name = "mullins"; pfp_req_size = CIK_PFP_UCODE_SIZE * 4; me_req_size = CIK_ME_UCODE_SIZE * 4; ce_req_size = CIK_CE_UCODE_SIZE * 4; mec_req_size = CIK_MEC_UCODE_SIZE * 4; rlc_req_size = ML_RLC_UCODE_SIZE * 4; sdma_req_size = CIK_SDMA_UCODE_SIZE * 4; + num_fw = 6; break; default: BUG(); } - DRM_INFO("Loading %s Microcode\n", chip_name); + DRM_INFO("Loading %s Microcode\n", new_chip_name); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name); err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->pfp_fw->size != pfp_req_size) { - printk(KERN_ERR - "cik_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->pfp_fw->size, fw_name); - err = -EINVAL; - goto out; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->pfp_fw->size != pfp_req_size) { + printk(KERN_ERR + "cik_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->pfp_fw->size, fw_name); + err = -EINVAL; + goto out; + } + } else { + err = radeon_ucode_validate(rdev->pfp_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", new_chip_name); err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->me_fw->size != me_req_size) { - printk(KERN_ERR - "cik_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->me_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->me_fw->size != me_req_size) { + printk(KERN_ERR + "cik_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->me_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->me_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", new_chip_name); err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->ce_fw->size != ce_req_size) { - printk(KERN_ERR - "cik_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->ce_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->ce_fw->size != ce_req_size) { + printk(KERN_ERR + "cik_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->ce_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->ce_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", new_chip_name); err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->mec_fw->size != mec_req_size) { - printk(KERN_ERR - "cik_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->mec_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); + err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->mec_fw->size != mec_req_size) { + printk(KERN_ERR + "cik_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->mec_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->mec_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + if (rdev->family == CHIP_KAVERI) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec2.bin", new_chip_name); + err = request_firmware(&rdev->mec2_fw, fw_name, rdev->dev); + if (err) { + goto out; + } else { + err = radeon_ucode_validate(rdev->mec2_fw); + if (err) { + goto out; + } else { + new_fw++; + } + } + } + + snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", new_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->rlc_fw->size != rlc_req_size) { - printk(KERN_ERR - "cik_rlc: Bogus length %zu in firmware \"%s\"\n", - rdev->rlc_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->rlc_fw->size != rlc_req_size) { + printk(KERN_ERR + "cik_rlc: Bogus length %zu in firmware \"%s\"\n", + rdev->rlc_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->rlc_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", new_chip_name); err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->sdma_fw->size != sdma_req_size) { - printk(KERN_ERR - "cik_sdma: Bogus length %zu in firmware \"%s\"\n", - rdev->sdma_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); + err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->sdma_fw->size != sdma_req_size) { + printk(KERN_ERR + "cik_sdma: Bogus length %zu in firmware \"%s\"\n", + rdev->sdma_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->sdma_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } /* No SMC, MC ucode on APUs */ if (!(rdev->flags & RADEON_IS_IGP)) { - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name); err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) { - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); - if (err) + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); + if (err) + goto out; + } + if ((rdev->mc_fw->size != mc_req_size) && + (rdev->mc_fw->size != mc2_req_size)){ + printk(KERN_ERR + "cik_mc: Bogus length %zu in firmware \"%s\"\n", + rdev->mc_fw->size, fw_name); + err = -EINVAL; + } + DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size); + } else { + err = radeon_ucode_validate(rdev->mc_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); goto out; + } else { + new_fw++; + } } - if ((rdev->mc_fw->size != mc_req_size) && - (rdev->mc_fw->size != mc2_req_size)){ - printk(KERN_ERR - "cik_mc: Bogus length %zu in firmware \"%s\"\n", - rdev->mc_fw->size, fw_name); - err = -EINVAL; - } - DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name); err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) { - printk(KERN_ERR - "smc: error loading firmware \"%s\"\n", - fw_name); - release_firmware(rdev->smc_fw); - rdev->smc_fw = NULL; - err = 0; - } else if (rdev->smc_fw->size != smc_req_size) { - printk(KERN_ERR - "cik_smc: Bogus length %zu in firmware \"%s\"\n", - rdev->smc_fw->size, fw_name); - err = -EINVAL; + snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); + if (err) { + printk(KERN_ERR + "smc: error loading firmware \"%s\"\n", + fw_name); + release_firmware(rdev->smc_fw); + rdev->smc_fw = NULL; + err = 0; + } else if (rdev->smc_fw->size != smc_req_size) { + printk(KERN_ERR + "cik_smc: Bogus length %zu in firmware \"%s\"\n", + rdev->smc_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->smc_fw); + if (err) { + printk(KERN_ERR + "cik_fw: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } } + if (new_fw == 0) { + rdev->new_fw = false; + } else if (new_fw < num_fw) { + printk(KERN_ERR "ci_fw: mixing new and old firmware!\n"); + err = -EINVAL; + } else { + rdev->new_fw = true; + } + out: if (err) { if (err != -EINVAL) @@ -2021,8 +2239,14 @@ out: rdev->me_fw = NULL; release_firmware(rdev->ce_fw); rdev->ce_fw = NULL; + release_firmware(rdev->mec_fw); + rdev->mec_fw = NULL; + release_firmware(rdev->mec2_fw); + rdev->mec2_fw = NULL; release_firmware(rdev->rlc_fw); rdev->rlc_fw = NULL; + release_firmware(rdev->sdma_fw); + rdev->sdma_fw = NULL; release_firmware(rdev->mc_fw); rdev->mc_fw = NULL; release_firmware(rdev->smc_fw); @@ -3259,7 +3483,7 @@ static void cik_gpu_init(struct radeon_device *rdev) u32 mc_shared_chmap, mc_arb_ramcfg; u32 hdp_host_path_cntl; u32 tmp; - int i, j, k; + int i, j; switch (rdev->family) { case CHIP_BONAIRE: @@ -3320,6 +3544,7 @@ static void cik_gpu_init(struct radeon_device *rdev) (rdev->pdev->device == 0x130B) || (rdev->pdev->device == 0x130E) || (rdev->pdev->device == 0x1315) || + (rdev->pdev->device == 0x1318) || (rdev->pdev->device == 0x131B)) { rdev->config.cik.max_cu_per_sh = 4; rdev->config.cik.max_backends_per_se = 1; @@ -3448,12 +3673,11 @@ static void cik_gpu_init(struct radeon_device *rdev) rdev->config.cik.max_sh_per_se, rdev->config.cik.max_backends_per_se); + rdev->config.cik.active_cus = 0; for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { - for (k = 0; k < rdev->config.cik.max_cu_per_sh; k++) { - rdev->config.cik.active_cus += - hweight32(cik_get_cu_active_bitmap(rdev, i, j)); - } + rdev->config.cik.active_cus += + hweight32(cik_get_cu_active_bitmap(rdev, i, j)); } } @@ -3577,7 +3801,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1)); radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); @@ -3666,8 +3890,6 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | DATA_SEL(1) | INT_SEL(2)); radeon_ring_write(ring, fence->seq); radeon_ring_write(ring, 0); - /* HDP flush */ - cik_hdp_flush_cp_ring_emit(rdev, fence->ring); } /** @@ -3696,10 +3918,19 @@ void cik_fence_compute_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, upper_32_bits(addr)); radeon_ring_write(ring, fence->seq); radeon_ring_write(ring, 0); - /* HDP flush */ - cik_hdp_flush_cp_ring_emit(rdev, fence->ring); } +/** + * cik_semaphore_ring_emit - emit a semaphore on the CP ring + * + * @rdev: radeon_device pointer + * @ring: radeon ring buffer object + * @semaphore: radeon semaphore object + * @emit_wait: Is this a sempahore wait? + * + * Emits a semaphore signal/wait packet to the CP ring and prevents the PFP + * from running ahead of semaphore waits. + */ bool cik_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring, struct radeon_semaphore *semaphore, @@ -3712,6 +3943,12 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, lower_32_bits(addr)); radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel); + if (emit_wait && ring->idx == RADEON_RING_TYPE_GFX_INDEX) { + /* Prevent the PFP from running ahead of the semaphore wait */ + radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); + radeon_ring_write(ring, 0x0); + } + return true; } @@ -3722,18 +3959,19 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev, * @src_offset: src GPU address * @dst_offset: dst GPU address * @num_gpu_pages: number of GPU pages to xfer - * @fence: radeon fence object + * @resv: reservation object to sync to * * Copy GPU paging using the CP DMA engine (CIK+). * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ -int cik_copy_cpdma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; 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, control; @@ -3743,7 +3981,7 @@ int cik_copy_cpdma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); @@ -3752,10 +3990,10 @@ int cik_copy_cpdma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); for (i = 0; i < num_loops; i++) { @@ -3777,17 +4015,17 @@ int cik_copy_cpdma(struct radeon_device *rdev, dst_offset += cur_size_in_bytes; } - r = radeon_fence_emit(rdev, fence, ring->idx); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } /* @@ -3883,7 +4121,7 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2); ib.ptr[2] = 0xDEADBEEF; ib.length_dw = 3; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_scratch_free(rdev, scratch); radeon_ib_free(rdev, &ib); @@ -3969,7 +4207,6 @@ static void cik_cp_gfx_enable(struct radeon_device *rdev, bool enable) */ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev) { - const __be32 *fw_data; int i; if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw) @@ -3977,31 +4214,72 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev) cik_cp_gfx_enable(rdev, false); - /* PFP */ - fw_data = (const __be32 *)rdev->pfp_fw->data; - WREG32(CP_PFP_UCODE_ADDR, 0); - for (i = 0; i < CIK_PFP_UCODE_SIZE; i++) - WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_PFP_UCODE_ADDR, 0); - - /* CE */ - fw_data = (const __be32 *)rdev->ce_fw->data; - WREG32(CP_CE_UCODE_ADDR, 0); - for (i = 0; i < CIK_CE_UCODE_SIZE; i++) - WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_CE_UCODE_ADDR, 0); - - /* ME */ - fw_data = (const __be32 *)rdev->me_fw->data; - WREG32(CP_ME_RAM_WADDR, 0); - for (i = 0; i < CIK_ME_UCODE_SIZE; i++) - WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_ME_RAM_WADDR, 0); - - WREG32(CP_PFP_UCODE_ADDR, 0); - WREG32(CP_CE_UCODE_ADDR, 0); - WREG32(CP_ME_RAM_WADDR, 0); - WREG32(CP_ME_RAM_RADDR, 0); + if (rdev->new_fw) { + const struct gfx_firmware_header_v1_0 *pfp_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->pfp_fw->data; + const struct gfx_firmware_header_v1_0 *ce_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->ce_fw->data; + const struct gfx_firmware_header_v1_0 *me_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data; + const __le32 *fw_data; + u32 fw_size; + + radeon_ucode_print_gfx_hdr(&pfp_hdr->header); + radeon_ucode_print_gfx_hdr(&ce_hdr->header); + radeon_ucode_print_gfx_hdr(&me_hdr->header); + + /* PFP */ + fw_data = (const __le32 *) + (rdev->pfp_fw->data + le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, le32_to_cpu(pfp_hdr->header.ucode_version)); + + /* CE */ + fw_data = (const __le32 *) + (rdev->ce_fw->data + le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(ce_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_CE_UCODE_ADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_CE_UCODE_ADDR, le32_to_cpu(ce_hdr->header.ucode_version)); + + /* ME */ + fw_data = (const __be32 *) + (rdev->me_fw->data + le32_to_cpu(me_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(me_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_ME_RAM_WADDR, le32_to_cpu(me_hdr->header.ucode_version)); + WREG32(CP_ME_RAM_RADDR, le32_to_cpu(me_hdr->header.ucode_version)); + } else { + const __be32 *fw_data; + + /* PFP */ + fw_data = (const __be32 *)rdev->pfp_fw->data; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < CIK_PFP_UCODE_SIZE; i++) + WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + /* CE */ + fw_data = (const __be32 *)rdev->ce_fw->data; + WREG32(CP_CE_UCODE_ADDR, 0); + for (i = 0; i < CIK_CE_UCODE_SIZE; i++) + WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_CE_UCODE_ADDR, 0); + + /* ME */ + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < CIK_ME_UCODE_SIZE; i++) + WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_ME_RAM_WADDR, 0); + } + return 0; } @@ -4035,8 +4313,8 @@ static int cik_cp_gfx_start(struct radeon_device *rdev) /* init the CE partitions. CE only used for gfx on CIK */ radeon_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2)); radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE)); - radeon_ring_write(ring, 0xc000); - radeon_ring_write(ring, 0xc000); + radeon_ring_write(ring, 0x8000); + radeon_ring_write(ring, 0x8000); /* setup clear context state */ radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0)); @@ -4061,7 +4339,7 @@ static int cik_cp_gfx_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); return 0; } @@ -4261,7 +4539,6 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable) */ static int cik_cp_compute_load_microcode(struct radeon_device *rdev) { - const __be32 *fw_data; int i; if (!rdev->mec_fw) @@ -4269,20 +4546,55 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev) cik_cp_compute_enable(rdev, false); - /* MEC1 */ - fw_data = (const __be32 *)rdev->mec_fw->data; - WREG32(CP_MEC_ME1_UCODE_ADDR, 0); - for (i = 0; i < CIK_MEC_UCODE_SIZE; i++) - WREG32(CP_MEC_ME1_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_MEC_ME1_UCODE_ADDR, 0); + if (rdev->new_fw) { + const struct gfx_firmware_header_v1_0 *mec_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->mec_fw->data; + const __le32 *fw_data; + u32 fw_size; + + radeon_ucode_print_gfx_hdr(&mec_hdr->header); + + /* MEC1 */ + fw_data = (const __le32 *) + (rdev->mec_fw->data + le32_to_cpu(mec_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(mec_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_MEC_ME1_UCODE_ADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_MEC_ME1_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_MEC_ME1_UCODE_ADDR, le32_to_cpu(mec_hdr->header.ucode_version)); - if (rdev->family == CHIP_KAVERI) { /* MEC2 */ + if (rdev->family == CHIP_KAVERI) { + const struct gfx_firmware_header_v1_0 *mec2_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->mec2_fw->data; + + fw_data = (const __le32 *) + (rdev->mec2_fw->data + + le32_to_cpu(mec2_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(mec2_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_MEC_ME2_UCODE_ADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_MEC_ME2_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_MEC_ME2_UCODE_ADDR, le32_to_cpu(mec2_hdr->header.ucode_version)); + } + } else { + const __be32 *fw_data; + + /* MEC1 */ fw_data = (const __be32 *)rdev->mec_fw->data; - WREG32(CP_MEC_ME2_UCODE_ADDR, 0); + WREG32(CP_MEC_ME1_UCODE_ADDR, 0); for (i = 0; i < CIK_MEC_UCODE_SIZE; i++) - WREG32(CP_MEC_ME2_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_MEC_ME2_UCODE_ADDR, 0); + WREG32(CP_MEC_ME1_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_MEC_ME1_UCODE_ADDR, 0); + + if (rdev->family == CHIP_KAVERI) { + /* MEC2 */ + fw_data = (const __be32 *)rdev->mec_fw->data; + WREG32(CP_MEC_ME2_UCODE_ADDR, 0); + for (i = 0; i < CIK_MEC_UCODE_SIZE; i++) + WREG32(CP_MEC_ME2_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_MEC_ME2_UCODE_ADDR, 0); + } } return 0; @@ -4375,7 +4687,7 @@ static int cik_mec_init(struct radeon_device *rdev) r = radeon_bo_create(rdev, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, NULL, + RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL, &rdev->mec.hpd_eop_obj); if (r) { dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r); @@ -4489,7 +4801,7 @@ struct bonaire_mqd */ static int cik_cp_compute_resume(struct radeon_device *rdev) { - int r, i, idx; + int r, i, j, idx; u32 tmp; bool use_doorbell = true; u64 hqd_gpu_addr; @@ -4545,8 +4857,8 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) r = radeon_bo_create(rdev, sizeof(struct bonaire_mqd), PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, NULL, - &rdev->ring[idx].mqd_obj); + RADEON_GEM_DOMAIN_GTT, 0, NULL, + NULL, &rdev->ring[idx].mqd_obj); if (r) { dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r); return r; @@ -4608,7 +4920,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) mqd->queue_state.cp_hqd_pq_wptr= 0; if (RREG32(CP_HQD_ACTIVE) & 1) { WREG32(CP_HQD_DEQUEUE_REQUEST, 1); - for (i = 0; i < rdev->usec_timeout; i++) { + for (j = 0; j < rdev->usec_timeout; j++) { if (!(RREG32(CP_HQD_ACTIVE) & 1)) break; udelay(1); @@ -5402,7 +5714,6 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Setup TLB control */ WREG32(MC_VM_MX_L1_TLB_CNTL, (0xA << 7) | @@ -5436,20 +5747,17 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) WREG32(0x15D8, 0); WREG32(0x15DC, 0); - /* empty context1-15 */ - /* FIXME start with 4G, once using 2 level pt switch to full - * vm size space - */ + /* restore context1-15 */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); for (i = 1; i < 16; i++) { if (i < 8) WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), - rdev->gart.table_addr >> 12); + rdev->vm_manager.saved_table_addr[i]); else WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2), - rdev->gart.table_addr >> 12); + rdev->vm_manager.saved_table_addr[i]); } /* enable context1-15 */ @@ -5514,6 +5822,17 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) */ static void cik_pcie_gart_disable(struct radeon_device *rdev) { + unsigned i; + + for (i = 1; i < 16; ++i) { + uint32_t reg; + if (i < 8) + reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2); + else + reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2); + rdev->vm_manager.saved_table_addr[i] = RREG32(reg); + } + /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); WREG32(VM_CONTEXT1_CNTL, 0); @@ -5642,12 +5961,13 @@ static void cik_vm_decode_fault(struct radeon_device *rdev, void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) { struct radeon_ring *ring = &rdev->ring[ridx]; + int usepfp = (ridx == RADEON_RING_TYPE_GFX_INDEX); if (vm == NULL) return; radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); if (vm->id < 8) { radeon_ring_write(ring, @@ -5661,14 +5981,14 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* update SH_MEM_* regs */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); radeon_ring_write(ring, 0); radeon_ring_write(ring, VMID(vm->id)); radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SH_MEM_BASES >> 2); radeon_ring_write(ring, 0); @@ -5679,7 +5999,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); radeon_ring_write(ring, 0); @@ -5690,14 +6010,14 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* bits 0-15 are the VM contexts0-15 */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); radeon_ring_write(ring, 1 << vm->id); /* compute doesn't have PFP */ - if (ridx == RADEON_RING_TYPE_GFX_INDEX) { + if (usepfp) { /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); @@ -5865,28 +6185,10 @@ static void cik_rlc_start(struct radeon_device *rdev) static int cik_rlc_resume(struct radeon_device *rdev) { u32 i, size, tmp; - const __be32 *fw_data; if (!rdev->rlc_fw) return -EINVAL; - switch (rdev->family) { - case CHIP_BONAIRE: - case CHIP_HAWAII: - default: - size = BONAIRE_RLC_UCODE_SIZE; - break; - case CHIP_KAVERI: - size = KV_RLC_UCODE_SIZE; - break; - case CHIP_KABINI: - size = KB_RLC_UCODE_SIZE; - break; - case CHIP_MULLINS: - size = ML_RLC_UCODE_SIZE; - break; - } - cik_rlc_stop(rdev); /* disable CG */ @@ -5910,11 +6212,45 @@ static int cik_rlc_resume(struct radeon_device *rdev) WREG32(RLC_MC_CNTL, 0); WREG32(RLC_UCODE_CNTL, 0); - fw_data = (const __be32 *)rdev->rlc_fw->data; + if (rdev->new_fw) { + const struct rlc_firmware_header_v1_0 *hdr = + (const struct rlc_firmware_header_v1_0 *)rdev->rlc_fw->data; + const __le32 *fw_data = (const __le32 *) + (rdev->rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + + radeon_ucode_print_rlc_hdr(&hdr->header); + + size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; WREG32(RLC_GPM_UCODE_ADDR, 0); - for (i = 0; i < size; i++) - WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(RLC_GPM_UCODE_ADDR, 0); + for (i = 0; i < size; i++) + WREG32(RLC_GPM_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(RLC_GPM_UCODE_ADDR, le32_to_cpu(hdr->header.ucode_version)); + } else { + const __be32 *fw_data; + + switch (rdev->family) { + case CHIP_BONAIRE: + case CHIP_HAWAII: + default: + size = BONAIRE_RLC_UCODE_SIZE; + break; + case CHIP_KAVERI: + size = KV_RLC_UCODE_SIZE; + break; + case CHIP_KABINI: + size = KB_RLC_UCODE_SIZE; + break; + case CHIP_MULLINS: + size = ML_RLC_UCODE_SIZE; + break; + } + + fw_data = (const __be32 *)rdev->rlc_fw->data; + WREG32(RLC_GPM_UCODE_ADDR, 0); + for (i = 0; i < size; i++) + WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(RLC_GPM_UCODE_ADDR, 0); + } /* XXX - find out what chips support lbpw */ cik_enable_lbpw(rdev, false); @@ -6348,11 +6684,10 @@ static void cik_enable_gds_pg(struct radeon_device *rdev, bool enable) void cik_init_cp_pg_table(struct radeon_device *rdev) { - const __be32 *fw_data; volatile u32 *dst_ptr; int me, i, max_me = 4; u32 bo_offset = 0; - u32 table_offset; + u32 table_offset, table_size; if (rdev->family == CHIP_KAVERI) max_me = 5; @@ -6363,24 +6698,71 @@ void cik_init_cp_pg_table(struct radeon_device *rdev) /* write the cp table buffer */ dst_ptr = rdev->rlc.cp_table_ptr; for (me = 0; me < max_me; me++) { - if (me == 0) { - fw_data = (const __be32 *)rdev->ce_fw->data; - table_offset = CP_ME_TABLE_OFFSET; - } else if (me == 1) { - fw_data = (const __be32 *)rdev->pfp_fw->data; - table_offset = CP_ME_TABLE_OFFSET; - } else if (me == 2) { - fw_data = (const __be32 *)rdev->me_fw->data; - table_offset = CP_ME_TABLE_OFFSET; + if (rdev->new_fw) { + const __le32 *fw_data; + const struct gfx_firmware_header_v1_0 *hdr; + + if (me == 0) { + hdr = (const struct gfx_firmware_header_v1_0 *)rdev->ce_fw->data; + fw_data = (const __le32 *) + (rdev->ce_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + table_offset = le32_to_cpu(hdr->jt_offset); + table_size = le32_to_cpu(hdr->jt_size); + } else if (me == 1) { + hdr = (const struct gfx_firmware_header_v1_0 *)rdev->pfp_fw->data; + fw_data = (const __le32 *) + (rdev->pfp_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + table_offset = le32_to_cpu(hdr->jt_offset); + table_size = le32_to_cpu(hdr->jt_size); + } else if (me == 2) { + hdr = (const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data; + fw_data = (const __le32 *) + (rdev->me_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + table_offset = le32_to_cpu(hdr->jt_offset); + table_size = le32_to_cpu(hdr->jt_size); + } else if (me == 3) { + hdr = (const struct gfx_firmware_header_v1_0 *)rdev->mec_fw->data; + fw_data = (const __le32 *) + (rdev->mec_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + table_offset = le32_to_cpu(hdr->jt_offset); + table_size = le32_to_cpu(hdr->jt_size); + } else { + hdr = (const struct gfx_firmware_header_v1_0 *)rdev->mec2_fw->data; + fw_data = (const __le32 *) + (rdev->mec2_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + table_offset = le32_to_cpu(hdr->jt_offset); + table_size = le32_to_cpu(hdr->jt_size); + } + + for (i = 0; i < table_size; i ++) { + dst_ptr[bo_offset + i] = + cpu_to_le32(le32_to_cpu(fw_data[table_offset + i])); + } + bo_offset += table_size; } else { - fw_data = (const __be32 *)rdev->mec_fw->data; - table_offset = CP_MEC_TABLE_OFFSET; - } + const __be32 *fw_data; + table_size = CP_ME_TABLE_SIZE; + + if (me == 0) { + fw_data = (const __be32 *)rdev->ce_fw->data; + table_offset = CP_ME_TABLE_OFFSET; + } else if (me == 1) { + fw_data = (const __be32 *)rdev->pfp_fw->data; + table_offset = CP_ME_TABLE_OFFSET; + } else if (me == 2) { + fw_data = (const __be32 *)rdev->me_fw->data; + table_offset = CP_ME_TABLE_OFFSET; + } else { + fw_data = (const __be32 *)rdev->mec_fw->data; + table_offset = CP_MEC_TABLE_OFFSET; + } - for (i = 0; i < CP_ME_TABLE_SIZE; i ++) { - dst_ptr[bo_offset + i] = cpu_to_le32(be32_to_cpu(fw_data[table_offset + i])); + for (i = 0; i < table_size; i ++) { + dst_ptr[bo_offset + i] = + cpu_to_le32(be32_to_cpu(fw_data[table_offset + i])); + } + bo_offset += table_size; } - bo_offset += CP_ME_TABLE_SIZE; } } @@ -7367,17 +7749,17 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -7618,7 +8000,8 @@ restart_ih: case 16: /* D5 page flip */ case 18: /* D6 page flip */ DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); - radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); + if (radeon_use_pflipirq > 0) + radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); break; case 42: /* HPD hotplug */ switch (src_data) { @@ -7866,15 +8249,17 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); - if (queue_reset) - schedule_work(&rdev->reset_work); + if (queue_reset) { + rdev->needs_reset = true; + wake_up_all(&rdev->fence_queue); + } if (queue_thermal) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ @@ -7900,6 +8285,7 @@ restart_ih: static int cik_startup(struct radeon_device *rdev) { struct radeon_ring *ring; + u32 nop; int r; /* enable pcie gen2/3 link */ @@ -8033,9 +8419,18 @@ static int cik_startup(struct radeon_device *rdev) } cik_irq_set(rdev); + if (rdev->family == CHIP_HAWAII) { + if (rdev->new_fw) + nop = PACKET3(PACKET3_NOP, 0x3FFF); + else + nop = RADEON_CP_PACKET2; + } else { + nop = PACKET3(PACKET3_NOP, 0x3FFF); + } + ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - PACKET3(PACKET3_NOP, 0x3FFF)); + nop); if (r) return r; @@ -8043,7 +8438,7 @@ static int cik_startup(struct radeon_device *rdev) /* type-2 packets are deprecated on MEC, use type-3 instead */ ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET, - PACKET3(PACKET3_NOP, 0x3FFF)); + nop); if (r) return r; ring->me = 1; /* first MEC */ @@ -8054,7 +8449,7 @@ static int cik_startup(struct radeon_device *rdev) /* type-2 packets are deprecated on MEC, use type-3 instead */ ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET, - PACKET3(PACKET3_NOP, 0x3FFF)); + nop); if (r) return r; /* dGPU only have 1 MEC */ @@ -9052,6 +9447,9 @@ void dce8_bandwidth_update(struct radeon_device *rdev) u32 num_heads = 0, lb_size; int i; + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); for (i = 0; i < rdev->num_crtc; i++) { @@ -9168,6 +9566,9 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) int ret, i; u16 tmp16; + if (pci_is_root_bus(rdev->pdev->bus)) + return; + if (radeon_pcie_gen2 == 0) return; @@ -9394,7 +9795,8 @@ static void cik_program_aspm(struct radeon_device *rdev) if (orig != data) WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data); - if (!disable_clkreq) { + if (!disable_clkreq && + !pci_is_root_bus(rdev->pdev->bus)) { struct pci_dev *root = rdev->pdev->bus->self; u32 lnkcap; diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index 8e9d0f1d858e..d748963af08b 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -24,6 +24,7 @@ #include <linux/firmware.h> #include <drm/drmP.h> #include "radeon.h" +#include "radeon_ucode.h" #include "radeon_asic.h" #include "radeon_trace.h" #include "cikd.h" @@ -118,6 +119,7 @@ void cik_sdma_set_wptr(struct radeon_device *rdev, reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET; WREG32(reg, (ring->wptr << 2) & 0x3fffc); + (void)RREG32(reg); } /** @@ -419,7 +421,6 @@ static int cik_sdma_rlc_resume(struct radeon_device *rdev) */ static int cik_sdma_load_microcode(struct radeon_device *rdev) { - const __be32 *fw_data; int i; if (!rdev->sdma_fw) @@ -428,19 +429,48 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev) /* halt the MEs */ cik_sdma_enable(rdev, false); - /* sdma0 */ - fw_data = (const __be32 *)rdev->sdma_fw->data; - WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); - for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++) - WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, be32_to_cpup(fw_data++)); - WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); - - /* sdma1 */ - fw_data = (const __be32 *)rdev->sdma_fw->data; - WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); - for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++) - WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, be32_to_cpup(fw_data++)); - WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); + if (rdev->new_fw) { + const struct sdma_firmware_header_v1_0 *hdr = + (const struct sdma_firmware_header_v1_0 *)rdev->sdma_fw->data; + const __le32 *fw_data; + u32 fw_size; + + radeon_ucode_print_sdma_hdr(&hdr->header); + + /* sdma0 */ + fw_data = (const __le32 *) + (rdev->sdma_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); + for (i = 0; i < fw_size; i++) + WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, le32_to_cpup(fw_data++)); + WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); + + /* sdma1 */ + fw_data = (const __le32 *) + (rdev->sdma_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); + for (i = 0; i < fw_size; i++) + WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, le32_to_cpup(fw_data++)); + WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); + } else { + const __be32 *fw_data; + + /* sdma0 */ + fw_data = (const __be32 *)rdev->sdma_fw->data; + WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); + for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++) + WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, be32_to_cpup(fw_data++)); + WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); + + /* sdma1 */ + fw_data = (const __be32 *)rdev->sdma_fw->data; + WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); + for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++) + WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, be32_to_cpup(fw_data++)); + WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION); + } WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0); WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0); @@ -459,13 +489,6 @@ int cik_sdma_resume(struct radeon_device *rdev) { int r; - /* Reset dma */ - WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1); - RREG32(SRBM_SOFT_RESET); - udelay(50); - WREG32(SRBM_SOFT_RESET, 0); - RREG32(SRBM_SOFT_RESET); - r = cik_sdma_load_microcode(rdev); if (r) return r; @@ -507,18 +530,19 @@ void cik_sdma_fini(struct radeon_device *rdev) * @src_offset: src GPU address * @dst_offset: dst GPU address * @num_gpu_pages: number of GPU pages to xfer - * @fence: radeon fence object + * @resv: reservation object to sync to * * Copy GPU paging using the DMA engine (CIK). * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ -int cik_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *cik_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; int ring_index = rdev->asic->copy.dma_ring_index; struct radeon_ring *ring = &rdev->ring[ring_index]; u32 size_in_bytes, cur_size_in_bytes; @@ -528,7 +552,7 @@ int cik_copy_dma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); @@ -537,10 +561,10 @@ int cik_copy_dma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); for (i = 0; i < num_loops; i++) { @@ -559,17 +583,17 @@ int cik_copy_dma(struct radeon_device *rdev, dst_offset += cur_size_in_bytes; } - r = radeon_fence_emit(rdev, fence, ring->idx); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } /** @@ -587,16 +611,19 @@ int cik_sdma_ring_test(struct radeon_device *rdev, { unsigned i; int r; - void __iomem *ptr = (void *)rdev->vram_scratch.ptr; + unsigned index; u32 tmp; + u64 gpu_addr; - if (!ptr) { - DRM_ERROR("invalid vram scratch pointer\n"); - return -EINVAL; - } + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + index = R600_WB_DMA_RING_TEST_OFFSET; + else + index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; + + gpu_addr = rdev->wb.gpu_addr + index; tmp = 0xCAFEDEAD; - writel(tmp, ptr); + rdev->wb.wb[index/4] = cpu_to_le32(tmp); r = radeon_ring_lock(rdev, ring, 5); if (r) { @@ -604,14 +631,14 @@ int cik_sdma_ring_test(struct radeon_device *rdev, return r; } radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0)); - radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); - radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr)); + radeon_ring_write(ring, lower_32_bits(gpu_addr)); + radeon_ring_write(ring, upper_32_bits(gpu_addr)); radeon_ring_write(ring, 1); /* number of DWs to follow */ radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { - tmp = readl(ptr); + tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); @@ -640,17 +667,20 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) { struct radeon_ib ib; unsigned i; + unsigned index; int r; - void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp = 0; + u64 gpu_addr; - if (!ptr) { - DRM_ERROR("invalid vram scratch pointer\n"); - return -EINVAL; - } + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + index = R600_WB_DMA_RING_TEST_OFFSET; + else + index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; + + gpu_addr = rdev->wb.gpu_addr + index; tmp = 0xCAFEDEAD; - writel(tmp, ptr); + rdev->wb.wb[index/4] = cpu_to_le32(tmp); r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); if (r) { @@ -659,13 +689,13 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) } ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); - ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc; - ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr); + ib.ptr[1] = lower_32_bits(gpu_addr); + ib.ptr[2] = upper_32_bits(gpu_addr); ib.ptr[3] = 1; ib.ptr[4] = 0xDEADBEEF; ib.length_dw = 5; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); @@ -677,7 +707,7 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) return r; } for (i = 0; i < rdev->usec_timeout; i++) { - tmp = readl(ptr); + tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); @@ -719,7 +749,43 @@ bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) } /** - * cik_sdma_vm_set_page - update the page tables using sDMA + * cik_sdma_vm_copy_pages - update PTEs by copying them from the GART + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @src: src addr to copy from + * @count: number of page entries to update + * + * Update PTEs by copying them from the GART using sDMA (CIK). + */ +void cik_sdma_vm_copy_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count) +{ + while (count) { + unsigned bytes = count * 8; + if (bytes > 0x1FFFF8) + bytes = 0x1FFFF8; + + ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, + SDMA_WRITE_SUB_OPCODE_LINEAR, 0); + ib->ptr[ib->length_dw++] = bytes; + ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ + ib->ptr[ib->length_dw++] = lower_32_bits(src); + ib->ptr[ib->length_dw++] = upper_32_bits(src); + ib->ptr[ib->length_dw++] = lower_32_bits(pe); + ib->ptr[ib->length_dw++] = upper_32_bits(pe); + + pe += bytes; + src += bytes; + count -= bytes / 8; + } +} + +/** + * cik_sdma_vm_write_pages - update PTEs by writing them manually * * @rdev: radeon_device pointer * @ib: indirect buffer to fill with commands @@ -729,84 +795,103 @@ bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) * @incr: increase next addr by incr bytes * @flags: access flags * - * Update the page tables using sDMA (CIK). + * Update PTEs by writing them manually using sDMA (CIK). */ -void cik_sdma_vm_set_page(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags) +void cik_sdma_vm_write_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) { uint64_t value; unsigned ndw; - trace_radeon_vm_set_page(pe, addr, count, incr, flags); - - if (flags == R600_PTE_GART) { - uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; - while (count) { - unsigned bytes = count * 8; - if (bytes > 0x1FFFF8) - bytes = 0x1FFFF8; - - ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); - ib->ptr[ib->length_dw++] = bytes; - ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ - ib->ptr[ib->length_dw++] = lower_32_bits(src); - ib->ptr[ib->length_dw++] = upper_32_bits(src); - ib->ptr[ib->length_dw++] = lower_32_bits(pe); - ib->ptr[ib->length_dw++] = upper_32_bits(pe); - - pe += bytes; - src += bytes; - count -= bytes / 8; - } - } else if (flags & R600_PTE_SYSTEM) { - while (count) { - ndw = count * 2; - if (ndw > 0xFFFFE) - ndw = 0xFFFFE; - - /* for non-physically contiguous pages (system) */ - ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); - ib->ptr[ib->length_dw++] = pe; - ib->ptr[ib->length_dw++] = upper_32_bits(pe); - ib->ptr[ib->length_dw++] = ndw; - for (; ndw > 0; ndw -= 2, --count, pe += 8) { + while (count) { + ndw = count * 2; + if (ndw > 0xFFFFE) + ndw = 0xFFFFE; + + /* for non-physically contiguous pages (system) */ + ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE, + SDMA_WRITE_SUB_OPCODE_LINEAR, 0); + ib->ptr[ib->length_dw++] = pe; + ib->ptr[ib->length_dw++] = upper_32_bits(pe); + ib->ptr[ib->length_dw++] = ndw; + for (; ndw > 0; ndw -= 2, --count, pe += 8) { + if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); value &= 0xFFFFFFFFFFFFF000ULL; - addr += incr; - value |= flags; - ib->ptr[ib->length_dw++] = value; - ib->ptr[ib->length_dw++] = upper_32_bits(value); - } - } - } else { - while (count) { - ndw = count; - if (ndw > 0x7FFFF) - ndw = 0x7FFFF; - - if (flags & R600_PTE_VALID) + } else if (flags & R600_PTE_VALID) { value = addr; - else + } else { value = 0; - /* for physically contiguous pages (vram) */ - ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0); - ib->ptr[ib->length_dw++] = pe; /* dst addr */ - ib->ptr[ib->length_dw++] = upper_32_bits(pe); - ib->ptr[ib->length_dw++] = flags; /* mask */ - ib->ptr[ib->length_dw++] = 0; - ib->ptr[ib->length_dw++] = value; /* value */ + } + addr += incr; + value |= flags; + ib->ptr[ib->length_dw++] = value; ib->ptr[ib->length_dw++] = upper_32_bits(value); - ib->ptr[ib->length_dw++] = incr; /* increment size */ - ib->ptr[ib->length_dw++] = 0; - ib->ptr[ib->length_dw++] = ndw; /* number of entries */ - pe += ndw * 8; - addr += ndw * incr; - count -= ndw; } } +} + +/** + * cik_sdma_vm_set_pages - update the page tables using sDMA + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @addr: dst addr to write into pe + * @count: number of page entries to update + * @incr: increase next addr by incr bytes + * @flags: access flags + * + * Update the page tables using sDMA (CIK). + */ +void cik_sdma_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) +{ + uint64_t value; + unsigned ndw; + + while (count) { + ndw = count; + if (ndw > 0x7FFFF) + ndw = 0x7FFFF; + + if (flags & R600_PTE_VALID) + value = addr; + else + value = 0; + + /* for physically contiguous pages (vram) */ + ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0); + ib->ptr[ib->length_dw++] = pe; /* dst addr */ + ib->ptr[ib->length_dw++] = upper_32_bits(pe); + ib->ptr[ib->length_dw++] = flags; /* mask */ + ib->ptr[ib->length_dw++] = 0; + ib->ptr[ib->length_dw++] = value; /* value */ + ib->ptr[ib->length_dw++] = upper_32_bits(value); + ib->ptr[ib->length_dw++] = incr; /* increment size */ + ib->ptr[ib->length_dw++] = 0; + ib->ptr[ib->length_dw++] = ndw; /* number of entries */ + + pe += ndw * 8; + addr += ndw * incr; + count -= ndw; + } +} + +/** + * cik_sdma_vm_pad_ib - pad the IB to the required number of dw + * + * @ib: indirect buffer to fill with padding + * + */ +void cik_sdma_vm_pad_ib(struct radeon_ib *ib) +{ while (ib->length_dw & 0x7) ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0); } diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 47d31e915758..9aad0327e4d1 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -24,6 +24,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "evergreend.h" #include "r600_dpm.h" #include "cypress_dpm.h" diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c index 51800e340a57..2fe8cfc966d9 100644 --- a/drivers/gpu/drm/radeon/dce3_1_afmt.c +++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c @@ -32,7 +32,7 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) struct drm_connector *connector; struct radeon_connector *radeon_connector = NULL; u32 tmp; - u8 *sadb; + u8 *sadb = NULL; int sad_count; list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { @@ -49,8 +49,8 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); if (sad_count < 0) { - DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - return; + DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); + sad_count = 0; } /* program the speaker allocation */ @@ -165,7 +165,7 @@ void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *m /* disable audio prior to setting up hw */ dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, false); + r600_audio_enable(rdev, dig->afmt->pin, 0); r600_audio_set_dto(encoder, mode->clock); @@ -240,5 +240,5 @@ void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *m r600_hdmi_audio_workaround(encoder); /* enable audio after to setting up hw */ - r600_audio_enable(rdev, dig->afmt->pin, true); + r600_audio_enable(rdev, dig->afmt->pin, 0xf); } diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 0a65dc7e93e7..f312edf4d50e 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -136,13 +136,13 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | AUDIO_LIPSYNC(connector->audio_latency[1]); else - tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); + tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0); } else { if (connector->latency_present[0]) tmp = VIDEO_LIPSYNC(connector->video_latency[0]) | AUDIO_LIPSYNC(connector->audio_latency[0]); else - tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); + tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0); } WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp); } @@ -155,7 +155,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) struct drm_connector *connector; struct radeon_connector *radeon_connector = NULL; u32 offset, tmp; - u8 *sadb; + u8 *sadb = NULL; int sad_count; if (!dig || !dig->afmt || !dig->afmt->pin) @@ -164,8 +164,10 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) offset = dig->afmt->pin->offset; list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) + if (connector->encoder == encoder) { radeon_connector = to_radeon_connector(connector); + break; + } } if (!radeon_connector) { @@ -173,10 +175,10 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) return; } - sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); - if (sad_count <= 0) { - DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - return; + sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); + if (sad_count < 0) { + DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); + sad_count = 0; } /* program the speaker allocation */ @@ -225,8 +227,10 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) offset = dig->afmt->pin->offset; list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) + if (connector->encoder == encoder) { radeon_connector = to_radeon_connector(connector); + break; + } } if (!radeon_connector) { @@ -234,7 +238,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) return; } - sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); + sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); if (sad_count <= 0) { DRM_ERROR("Couldn't read SADs: %d\n", sad_count); return; @@ -280,13 +284,13 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev) void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, - bool enable) + u8 enable_mask) { if (!pin) return; - WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL, - enable ? AUDIO_ENABLED : 0); + WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, + enable_mask ? AUDIO_ENABLED : 0); } static const u32 pin_offsets[7] = diff --git a/drivers/gpu/drm/radeon/drm_buffer.c b/drivers/gpu/drm/radeon/drm_buffer.c new file mode 100644 index 000000000000..f4e0f3a3d7b1 --- /dev/null +++ b/drivers/gpu/drm/radeon/drm_buffer.c @@ -0,0 +1,177 @@ +/************************************************************************** + * + * Copyright 2010 Pauli Nieminen. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + **************************************************************************/ +/* + * Multipart buffer for coping data which is larger than the page size. + * + * Authors: + * Pauli Nieminen <suokkos-at-gmail-dot-com> + */ + +#include <linux/export.h> +#include "drm_buffer.h" + +/** + * Allocate the drm buffer object. + * + * buf: Pointer to a pointer where the object is stored. + * size: The number of bytes to allocate. + */ +int drm_buffer_alloc(struct drm_buffer **buf, int size) +{ + int nr_pages = size / PAGE_SIZE + 1; + int idx; + + /* Allocating pointer table to end of structure makes drm_buffer + * variable sized */ + *buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *), + GFP_KERNEL); + + if (*buf == NULL) { + DRM_ERROR("Failed to allocate drm buffer object to hold" + " %d bytes in %d pages.\n", + size, nr_pages); + return -ENOMEM; + } + + (*buf)->size = size; + + for (idx = 0; idx < nr_pages; ++idx) { + + (*buf)->data[idx] = + kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE), + GFP_KERNEL); + + + if ((*buf)->data[idx] == NULL) { + DRM_ERROR("Failed to allocate %dth page for drm" + " buffer with %d bytes and %d pages.\n", + idx + 1, size, nr_pages); + goto error_out; + } + + } + + return 0; + +error_out: + + for (; idx >= 0; --idx) + kfree((*buf)->data[idx]); + + kfree(*buf); + return -ENOMEM; +} + +/** + * Copy the user data to the begin of the buffer and reset the processing + * iterator. + * + * user_data: A pointer the data that is copied to the buffer. + * size: The Number of bytes to copy. + */ +int drm_buffer_copy_from_user(struct drm_buffer *buf, + void __user *user_data, int size) +{ + int nr_pages = size / PAGE_SIZE + 1; + int idx; + + if (size > buf->size) { + DRM_ERROR("Requesting to copy %d bytes to a drm buffer with" + " %d bytes space\n", + size, buf->size); + return -EFAULT; + } + + for (idx = 0; idx < nr_pages; ++idx) { + + if (copy_from_user(buf->data[idx], + user_data + idx * PAGE_SIZE, + min(PAGE_SIZE, size - idx * PAGE_SIZE))) { + DRM_ERROR("Failed to copy user data (%p) to drm buffer" + " (%p) %dth page.\n", + user_data, buf, idx); + return -EFAULT; + + } + } + buf->iterator = 0; + return 0; +} + +/** + * Free the drm buffer object + */ +void drm_buffer_free(struct drm_buffer *buf) +{ + + if (buf != NULL) { + + int nr_pages = buf->size / PAGE_SIZE + 1; + int idx; + for (idx = 0; idx < nr_pages; ++idx) + kfree(buf->data[idx]); + + kfree(buf); + } +} + +/** + * Read an object from buffer that may be split to multiple parts. If object + * is not split function just returns the pointer to object in buffer. But in + * case of split object data is copied to given stack object that is suplied + * by caller. + * + * The processing location of the buffer is also advanced to the next byte + * after the object. + * + * objsize: The size of the objet in bytes. + * stack_obj: A pointer to a memory location where object can be copied. + */ +void *drm_buffer_read_object(struct drm_buffer *buf, + int objsize, void *stack_obj) +{ + int idx = drm_buffer_index(buf); + int page = drm_buffer_page(buf); + void *obj = NULL; + + if (idx + objsize <= PAGE_SIZE) { + obj = &buf->data[page][idx]; + } else { + /* The object is split which forces copy to temporary object.*/ + int beginsz = PAGE_SIZE - idx; + memcpy(stack_obj, &buf->data[page][idx], beginsz); + + memcpy(stack_obj + beginsz, &buf->data[page + 1][0], + objsize - beginsz); + + obj = stack_obj; + } + + drm_buffer_advance(buf, objsize); + return obj; +} diff --git a/drivers/gpu/drm/radeon/drm_buffer.h b/drivers/gpu/drm/radeon/drm_buffer.h new file mode 100644 index 000000000000..c80d3a340b94 --- /dev/null +++ b/drivers/gpu/drm/radeon/drm_buffer.h @@ -0,0 +1,148 @@ +/************************************************************************** + * + * Copyright 2010 Pauli Nieminen. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + **************************************************************************/ +/* + * Multipart buffer for coping data which is larger than the page size. + * + * Authors: + * Pauli Nieminen <suokkos-at-gmail-dot-com> + */ + +#ifndef _DRM_BUFFER_H_ +#define _DRM_BUFFER_H_ + +#include <drm/drmP.h> + +struct drm_buffer { + int iterator; + int size; + char *data[]; +}; + + +/** + * Return the index of page that buffer is currently pointing at. + */ +static inline int drm_buffer_page(struct drm_buffer *buf) +{ + return buf->iterator / PAGE_SIZE; +} +/** + * Return the index of the current byte in the page + */ +static inline int drm_buffer_index(struct drm_buffer *buf) +{ + return buf->iterator & (PAGE_SIZE - 1); +} +/** + * Return number of bytes that is left to process + */ +static inline int drm_buffer_unprocessed(struct drm_buffer *buf) +{ + return buf->size - buf->iterator; +} + +/** + * Advance the buffer iterator number of bytes that is given. + */ +static inline void drm_buffer_advance(struct drm_buffer *buf, int bytes) +{ + buf->iterator += bytes; +} + +/** + * Allocate the drm buffer object. + * + * buf: A pointer to a pointer where the object is stored. + * size: The number of bytes to allocate. + */ +extern int drm_buffer_alloc(struct drm_buffer **buf, int size); + +/** + * Copy the user data to the begin of the buffer and reset the processing + * iterator. + * + * user_data: A pointer the data that is copied to the buffer. + * size: The Number of bytes to copy. + */ +extern int drm_buffer_copy_from_user(struct drm_buffer *buf, + void __user *user_data, int size); + +/** + * Free the drm buffer object + */ +extern void drm_buffer_free(struct drm_buffer *buf); + +/** + * Read an object from buffer that may be split to multiple parts. If object + * is not split function just returns the pointer to object in buffer. But in + * case of split object data is copied to given stack object that is suplied + * by caller. + * + * The processing location of the buffer is also advanced to the next byte + * after the object. + * + * objsize: The size of the objet in bytes. + * stack_obj: A pointer to a memory location where object can be copied. + */ +extern void *drm_buffer_read_object(struct drm_buffer *buf, + int objsize, void *stack_obj); + +/** + * Returns the pointer to the dword which is offset number of elements from the + * current processing location. + * + * Caller must make sure that dword is not split in the buffer. This + * requirement is easily met if all the sizes of objects in buffer are + * multiples of dword and PAGE_SIZE is multiple dword. + * + * Call to this function doesn't change the processing location. + * + * offset: The index of the dword relative to the internat iterator. + */ +static inline void *drm_buffer_pointer_to_dword(struct drm_buffer *buffer, + int offset) +{ + int iter = buffer->iterator + offset * 4; + return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)]; +} +/** + * Returns the pointer to the dword which is offset number of elements from + * the current processing location. + * + * Call to this function doesn't change the processing location. + * + * offset: The index of the byte relative to the internat iterator. + */ +static inline void *drm_buffer_pointer_to_byte(struct drm_buffer *buffer, + int offset) +{ + int iter = buffer->iterator + offset; + return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)]; +} + +#endif diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 15e4f28015e1..85995b4e3338 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -22,7 +22,6 @@ * Authors: Alex Deucher */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <drm/drmP.h> #include "radeon.h" @@ -2346,6 +2345,9 @@ void evergreen_bandwidth_update(struct radeon_device *rdev) u32 num_heads = 0, lb_size; int i; + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); for (i = 0; i < rdev->num_crtc; i++) { @@ -2424,7 +2426,6 @@ static int evergreen_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Setup L2 cache */ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE | @@ -2554,6 +2555,7 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); @@ -2677,7 +2679,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s if (save->crtc_enabled[i]) { if (ASIC_IS_DCE6(rdev)) { tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); - tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; + tmp &= ~EVERGREEN_CRTC_BLANK_DATA_EN; WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); @@ -2870,7 +2872,7 @@ static int evergreen_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(ring, 0); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); cp_me = 0xff; WREG32(CP_ME_CNTL, cp_me); @@ -2913,7 +2915,7 @@ static int evergreen_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); return 0; } @@ -3007,7 +3009,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) u32 vgt_cache_invalidation; u32 hdp_host_path_cntl, tmp; u32 disabled_rb_mask; - int i, j, num_shader_engines, ps_thread_count; + int i, j, ps_thread_count; switch (rdev->family) { case CHIP_CYPRESS: @@ -3305,8 +3307,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.tile_config |= ((gb_addr_config & 0x30000000) >> 28) << 12; - num_shader_engines = (gb_addr_config & NUM_SHADER_ENGINES(3) >> 12) + 1; - if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) { u32 efuse_straps_4; u32 efuse_straps_3; @@ -4023,7 +4023,8 @@ int sumo_rlc_init(struct radeon_device *rdev) /* save restore block */ if (rdev->rlc.save_restore_obj == NULL) { r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.save_restore_obj); + RADEON_GEM_DOMAIN_VRAM, 0, NULL, + NULL, &rdev->rlc.save_restore_obj); if (r) { dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r); return r; @@ -4101,7 +4102,8 @@ int sumo_rlc_init(struct radeon_device *rdev) if (rdev->rlc.clear_state_obj == NULL) { r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.clear_state_obj); + RADEON_GEM_DOMAIN_VRAM, 0, NULL, + NULL, &rdev->rlc.clear_state_obj); if (r) { dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r); sumo_rlc_fini(rdev); @@ -4175,8 +4177,10 @@ int sumo_rlc_init(struct radeon_device *rdev) if (rdev->rlc.cp_table_size) { if (rdev->rlc.cp_table_obj == NULL) { - r = radeon_bo_create(rdev, rdev->rlc.cp_table_size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.cp_table_obj); + r = radeon_bo_create(rdev, rdev->rlc.cp_table_size, + PAGE_SIZE, true, + RADEON_GEM_DOMAIN_VRAM, 0, NULL, + NULL, &rdev->rlc.cp_table_obj); if (r) { dev_warn(rdev->dev, "(%d) create RLC cp table bo failed\n", r); sumo_rlc_fini(rdev); @@ -4746,17 +4750,17 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -4961,7 +4965,8 @@ restart_ih: case 16: /* D5 page flip */ case 18: /* D6 page flip */ DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); - radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); + if (radeon_use_pflipirq > 0) + radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); break; case 42: /* HPD hotplug */ switch (src_data) { @@ -5133,6 +5138,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -5141,7 +5147,6 @@ restart_ih: if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/evergreen_dma.c b/drivers/gpu/drm/radeon/evergreen_dma.c index 478caefe0fef..66bcfadeedd1 100644 --- a/drivers/gpu/drm/radeon/evergreen_dma.c +++ b/drivers/gpu/drm/radeon/evergreen_dma.c @@ -104,12 +104,14 @@ void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ -int evergreen_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; int ring_index = rdev->asic->copy.dma_ring_index; struct radeon_ring *ring = &rdev->ring[ring_index]; u32 size_in_dw, cur_size_in_dw; @@ -119,7 +121,7 @@ int evergreen_copy_dma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; @@ -128,10 +130,10 @@ int evergreen_copy_dma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); for (i = 0; i < num_loops; i++) { @@ -148,17 +150,17 @@ int evergreen_copy_dma(struct radeon_device *rdev, dst_offset += cur_size_in_dw * 4; } - r = radeon_fence_emit(rdev, fence, ring->idx); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } /** diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index 1ec0e6e83f9f..53abd9b17a50 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -38,6 +38,37 @@ extern void dce6_afmt_select_pin(struct drm_encoder *encoder); extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, struct drm_display_mode *mode); +/* enable the audio stream */ +static void dce4_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, + u8 enable_mask) +{ + u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL); + + if (!pin) + return; + + if (enable_mask) { + tmp |= AUDIO_ENABLED; + if (enable_mask & 1) + tmp |= PIN0_AUDIO_ENABLED; + if (enable_mask & 2) + tmp |= PIN1_AUDIO_ENABLED; + if (enable_mask & 4) + tmp |= PIN2_AUDIO_ENABLED; + if (enable_mask & 8) + tmp |= PIN3_AUDIO_ENABLED; + } else { + tmp &= ~(AUDIO_ENABLED | + PIN0_AUDIO_ENABLED | + PIN1_AUDIO_ENABLED | + PIN2_AUDIO_ENABLED | + PIN3_AUDIO_ENABLED); + } + + WREG32(AZ_HOT_PLUG_CONTROL, tmp); +} + /* * update the N and CTS parameters for a given pixel clock rate */ @@ -102,7 +133,7 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) struct drm_connector *connector; struct radeon_connector *radeon_connector = NULL; u32 tmp; - u8 *sadb; + u8 *sadb = NULL; int sad_count; list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { @@ -117,10 +148,10 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) return; } - sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); - if (sad_count <= 0) { - DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - return; + sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); + if (sad_count < 0) { + DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); + sad_count = 0; } /* program the speaker allocation */ @@ -172,7 +203,7 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) return; } - sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); + sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); if (sad_count <= 0) { DRM_ERROR("Couldn't read SADs: %d\n", sad_count); return; @@ -318,10 +349,10 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode /* disable audio prior to setting up hw */ if (ASIC_IS_DCE6(rdev)) { dig->afmt->pin = dce6_audio_get_pin(rdev); - dce6_audio_enable(rdev, dig->afmt->pin, false); + dce6_audio_enable(rdev, dig->afmt->pin, 0); } else { dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, false); + dce4_audio_enable(rdev, dig->afmt->pin, 0); } evergreen_audio_set_dto(encoder, mode->clock); @@ -463,13 +494,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode /* enable audio after to setting up hw */ if (ASIC_IS_DCE6(rdev)) - dce6_audio_enable(rdev, dig->afmt->pin, true); + dce6_audio_enable(rdev, dig->afmt->pin, 1); else - r600_audio_enable(rdev, dig->afmt->pin, true); + dce4_audio_enable(rdev, dig->afmt->pin, 0xf); } void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; @@ -482,6 +515,14 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) if (!enable && !dig->afmt->enabled) return; + if (!enable && dig->afmt->pin) { + if (ASIC_IS_DCE6(rdev)) + dce6_audio_enable(rdev, dig->afmt->pin, 0); + else + dce4_audio_enable(rdev, dig->afmt->pin, 0); + dig->afmt->pin = NULL; + } + dig->afmt->enabled = enable; DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 9ef8c38f2d66..9b42001295ba 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -33,6 +33,8 @@ #define KV_MINIMUM_ENGINE_CLOCK 800 #define SMC_RAM_END 0x40000 +static int kv_enable_nb_dpm(struct radeon_device *rdev, + bool enable); static void kv_init_graphics_levels(struct radeon_device *rdev); static int kv_calculate_ds_divider(struct radeon_device *rdev); static int kv_calculate_nbps_level_settings(struct radeon_device *rdev); @@ -1295,6 +1297,9 @@ void kv_dpm_disable(struct radeon_device *rdev) { kv_smc_bapm_enable(rdev, false); + if (rdev->family == CHIP_MULLINS) + kv_enable_nb_dpm(rdev, false); + /* powerup blocks */ kv_dpm_powergate_acp(rdev, false); kv_dpm_powergate_samu(rdev, false); @@ -1438,14 +1443,14 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) return kv_enable_uvd_dpm(rdev, !gate); } -static u8 kv_get_vce_boot_level(struct radeon_device *rdev) +static u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk) { u8 i; struct radeon_vce_clock_voltage_dependency_table *table = &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; for (i = 0; i < table->count; i++) { - if (table->entries[i].evclk >= 0) /* XXX */ + if (table->entries[i].evclk >= evclk) break; } @@ -1468,7 +1473,7 @@ static int kv_update_vce_dpm(struct radeon_device *rdev, if (pi->caps_stable_p_state) pi->vce_boot_level = table->count - 1; else - pi->vce_boot_level = kv_get_vce_boot_level(rdev); + pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk); ret = kv_copy_bytes_to_smc(rdev, pi->dpm_table_start + @@ -1769,15 +1774,24 @@ static int kv_update_dfs_bypass_settings(struct radeon_device *rdev, return ret; } -static int kv_enable_nb_dpm(struct radeon_device *rdev) +static int kv_enable_nb_dpm(struct radeon_device *rdev, + bool enable) { struct kv_power_info *pi = kv_get_pi(rdev); int ret = 0; - if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { - ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); - if (ret == 0) - pi->nb_dpm_enabled = true; + if (enable) { + if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { + ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); + if (ret == 0) + pi->nb_dpm_enabled = true; + } + } else { + if (pi->enable_nb_dpm && pi->nb_dpm_enabled) { + ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Disable); + if (ret == 0) + pi->nb_dpm_enabled = false; + } } return ret; @@ -1864,7 +1878,7 @@ int kv_dpm_set_power_state(struct radeon_device *rdev) } kv_update_sclk_t(rdev); if (rdev->family == CHIP_MULLINS) - kv_enable_nb_dpm(rdev); + kv_enable_nb_dpm(rdev, true); } } else { if (pi->enable_dpm) { @@ -1889,7 +1903,7 @@ int kv_dpm_set_power_state(struct radeon_device *rdev) } kv_update_acp_boot_level(rdev); kv_update_sclk_t(rdev); - kv_enable_nb_dpm(rdev); + kv_enable_nb_dpm(rdev, true); } } @@ -2711,7 +2725,11 @@ int kv_dpm_init(struct radeon_device *rdev) pi->sram_end = SMC_RAM_END; - pi->enable_nb_dpm = true; + /* Enabling nb dpm on an asrock system prevents dpm from working */ + if (rdev->pdev->subsystem_vendor == 0x1849) + pi->enable_nb_dpm = false; + else + pi->enable_nb_dpm = true; pi->caps_power_containment = true; pi->caps_cac = true; @@ -2726,7 +2744,19 @@ int kv_dpm_init(struct radeon_device *rdev) pi->caps_sclk_ds = true; pi->enable_auto_thermal_throttling = true; pi->disable_nb_ps3_in_battery = false; - pi->bapm_enable = true; + if (radeon_bapm == -1) { + /* There are stability issues reported on with + * bapm enabled on an asrock system. + */ + if (rdev->pdev->subsystem_vendor == 0x1849) + pi->bapm_enable = false; + else + pi->bapm_enable = true; + } else if (radeon_bapm == 0) { + pi->bapm_enable = false; + } else { + pi->bapm_enable = true; + } pi->voltage_drop_t = 0; pi->caps_sclk_throttle_low_notification = false; pi->caps_fps = false; /* true? */ @@ -2770,6 +2800,8 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >> SMU_VOLTAGE_CURRENT_LEVEL_SHIFT; vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp); + seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en"); + seq_printf(m, "vce %sabled\n", pi->vce_power_gated ? "dis" : "en"); seq_printf(m, "power level %d sclk: %u vddc: %u\n", current_index, sclk, vddc); } diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 5a33ca681867..3faee58946dd 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1229,7 +1229,6 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Setup TLB control */ WREG32(MC_VM_MX_L1_TLB_CNTL, (0xA << 7) | @@ -1272,7 +1271,7 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0); WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), - rdev->gart.table_addr >> 12); + rdev->vm_manager.saved_table_addr[i]); } /* enable context1-7 */ @@ -1304,6 +1303,13 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) static void cayman_pcie_gart_disable(struct radeon_device *rdev) { + unsigned i; + + for (i = 1; i < 8; ++i) { + rdev->vm_manager.saved_table_addr[i] = RREG32( + VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2)); + } + /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); WREG32(VM_CONTEXT1_CNTL, 0); @@ -1506,7 +1512,7 @@ static int cayman_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(ring, 0); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); cayman_cp_enable(rdev, true); @@ -1548,7 +1554,7 @@ static int cayman_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); /* XXX init other rings */ diff --git a/drivers/gpu/drm/radeon/ni_dma.c b/drivers/gpu/drm/radeon/ni_dma.c index 6378e0276691..f26f0a9fb522 100644 --- a/drivers/gpu/drm/radeon/ni_dma.c +++ b/drivers/gpu/drm/radeon/ni_dma.c @@ -191,12 +191,6 @@ int cayman_dma_resume(struct radeon_device *rdev) u32 reg_offset, wb_offset; int i, r; - /* Reset dma */ - WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); - RREG32(SRBM_SOFT_RESET); - udelay(50); - WREG32(SRBM_SOFT_RESET, 0); - for (i = 0; i < 2; i++) { if (i == 0) { ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; @@ -307,7 +301,43 @@ bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) } /** - * cayman_dma_vm_set_page - update the page tables using the DMA + * cayman_dma_vm_copy_pages - update PTEs by copying them from the GART + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @src: src addr where to copy from + * @count: number of page entries to update + * + * Update PTEs by copying them from the GART using the DMA (cayman/TN). + */ +void cayman_dma_vm_copy_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count) +{ + unsigned ndw; + + while (count) { + ndw = count * 2; + if (ndw > 0xFFFFE) + ndw = 0xFFFFE; + + ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, + 0, 0, ndw); + ib->ptr[ib->length_dw++] = lower_32_bits(pe); + ib->ptr[ib->length_dw++] = lower_32_bits(src); + ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; + ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff; + + pe += ndw * 4; + src += ndw * 4; + count -= ndw / 2; + } +} + +/** + * cayman_dma_vm_write_pages - update PTEs by writing them manually * * @rdev: radeon_device pointer * @ib: indirect buffer to fill with commands @@ -315,71 +345,103 @@ bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) * @addr: dst addr to write into pe * @count: number of page entries to update * @incr: increase next addr by incr bytes - * @flags: hw access flags + * @flags: hw access flags * - * Update the page tables using the DMA (cayman/TN). + * Update PTEs by writing them manually using the DMA (cayman/TN). */ -void cayman_dma_vm_set_page(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags) +void cayman_dma_vm_write_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) { uint64_t value; unsigned ndw; - trace_radeon_vm_set_page(pe, addr, count, incr, flags); - - if ((flags & R600_PTE_SYSTEM) || (count == 1)) { - while (count) { - ndw = count * 2; - if (ndw > 0xFFFFE) - ndw = 0xFFFFE; - - /* for non-physically contiguous pages (system) */ - ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, ndw); - ib->ptr[ib->length_dw++] = pe; - ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; - for (; ndw > 0; ndw -= 2, --count, pe += 8) { - if (flags & R600_PTE_SYSTEM) { - value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; - } else if (flags & R600_PTE_VALID) { - value = addr; - } else { - value = 0; - } - addr += incr; - value |= flags; - ib->ptr[ib->length_dw++] = value; - ib->ptr[ib->length_dw++] = upper_32_bits(value); - } - } - } else { - while (count) { - ndw = count * 2; - if (ndw > 0xFFFFE) - ndw = 0xFFFFE; - - if (flags & R600_PTE_VALID) + while (count) { + ndw = count * 2; + if (ndw > 0xFFFFE) + ndw = 0xFFFFE; + + /* for non-physically contiguous pages (system) */ + ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, + 0, 0, ndw); + ib->ptr[ib->length_dw++] = pe; + ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; + for (; ndw > 0; ndw -= 2, --count, pe += 8) { + if (flags & R600_PTE_SYSTEM) { + value = radeon_vm_map_gart(rdev, addr); + value &= 0xFFFFFFFFFFFFF000ULL; + } else if (flags & R600_PTE_VALID) { value = addr; - else + } else { value = 0; - /* for physically contiguous pages (vram) */ - ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw); - ib->ptr[ib->length_dw++] = pe; /* dst addr */ - ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; - ib->ptr[ib->length_dw++] = flags; /* mask */ - ib->ptr[ib->length_dw++] = 0; - ib->ptr[ib->length_dw++] = value; /* value */ + } + addr += incr; + value |= flags; + ib->ptr[ib->length_dw++] = value; ib->ptr[ib->length_dw++] = upper_32_bits(value); - ib->ptr[ib->length_dw++] = incr; /* increment size */ - ib->ptr[ib->length_dw++] = 0; - pe += ndw * 4; - addr += (ndw / 2) * incr; - count -= ndw / 2; } } +} + +/** + * cayman_dma_vm_set_pages - update the page tables using the DMA + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @addr: dst addr to write into pe + * @count: number of page entries to update + * @incr: increase next addr by incr bytes + * @flags: hw access flags + * + * Update the page tables using the DMA (cayman/TN). + */ +void cayman_dma_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) +{ + uint64_t value; + unsigned ndw; + + while (count) { + ndw = count * 2; + if (ndw > 0xFFFFE) + ndw = 0xFFFFE; + + if (flags & R600_PTE_VALID) + value = addr; + else + value = 0; + + /* for physically contiguous pages (vram) */ + ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw); + ib->ptr[ib->length_dw++] = pe; /* dst addr */ + ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; + ib->ptr[ib->length_dw++] = flags; /* mask */ + ib->ptr[ib->length_dw++] = 0; + ib->ptr[ib->length_dw++] = value; /* value */ + ib->ptr[ib->length_dw++] = upper_32_bits(value); + ib->ptr[ib->length_dw++] = incr; /* increment size */ + ib->ptr[ib->length_dw++] = 0; + + pe += ndw * 4; + addr += (ndw / 2) * incr; + count -= ndw / 2; + } +} + +/** + * cayman_dma_vm_pad_ib - pad the IB to the required number of dw + * + * @ib: indirect buffer to fill with padding + * + */ +void cayman_dma_vm_pad_ib(struct radeon_ib *ib) +{ while (ib->length_dw & 0x7) ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0); } diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 01fc4888e6fe..6d2f16cf2c1c 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -23,6 +23,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "nid.h" #include "r600_dpm.h" #include "ni_dpm.h" @@ -789,7 +790,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev, bool disable_mclk_switching; u32 mclk; u16 vddci; - u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; int i; if ((rdev->pm.dpm.new_active_crtc_count > 1) || @@ -816,29 +816,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev, } } - /* limit clocks to max supported clocks based on voltage dependency tables */ - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, - &max_sclk_vddc); - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, - &max_mclk_vddci); - btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, - &max_mclk_vddc); - - for (i = 0; i < ps->performance_level_count; i++) { - if (max_sclk_vddc) { - if (ps->performance_levels[i].sclk > max_sclk_vddc) - ps->performance_levels[i].sclk = max_sclk_vddc; - } - if (max_mclk_vddci) { - if (ps->performance_levels[i].mclk > max_mclk_vddci) - ps->performance_levels[i].mclk = max_mclk_vddci; - } - if (max_mclk_vddc) { - if (ps->performance_levels[i].mclk > max_mclk_vddc) - ps->performance_levels[i].mclk = max_mclk_vddc; - } - } - /* XXX validate the min clocks required for display */ /* adjust low state */ diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 1544efcf1c3a..b53b31a7b76f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -652,7 +652,6 @@ int r100_pci_gart_enable(struct radeon_device *rdev) { uint32_t tmp; - radeon_gart_restore(rdev); /* discard memory request outside of configured range */ tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; WREG32(RADEON_AIC_CNTL, tmp); @@ -683,7 +682,7 @@ void r100_pci_gart_disable(struct radeon_device *rdev) } void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr) + uint64_t addr, uint32_t flags) { u32 *gtt = rdev->gart.ptr; gtt[i] = cpu_to_le32(lower_32_bits(addr)); @@ -822,6 +821,20 @@ u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc) return RREG32(RADEON_CRTC2_CRNT_FRAME); } +/** + * r100_ring_hdp_flush - flush Host Data Path via the ring buffer + * rdev: radeon device structure + * ring: ring buffer struct for emitting packets + */ +static void r100_ring_hdp_flush(struct radeon_device *rdev, struct radeon_ring *ring) +{ + radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); + radeon_ring_write(ring, rdev->config.r100.hdp_cntl | + RADEON_HDP_READ_BUFFER_INVALIDATE); + radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); + radeon_ring_write(ring, rdev->config.r100.hdp_cntl); +} + /* Who ever call radeon_fence_emit should call ring_lock and ask * for enough space (today caller are ib schedule and buffer move) */ void r100_fence_ring_emit(struct radeon_device *rdev, @@ -838,11 +851,7 @@ void r100_fence_ring_emit(struct radeon_device *rdev, /* Wait until IDLE & CLEAN */ radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); radeon_ring_write(ring, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN); - radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); - radeon_ring_write(ring, rdev->config.r100.hdp_cntl | - RADEON_HDP_READ_BUFFER_INVALIDATE); - radeon_ring_write(ring, PACKET0(RADEON_HOST_PATH_CNTL, 0)); - radeon_ring_write(ring, rdev->config.r100.hdp_cntl); + r100_ring_hdp_flush(rdev, ring); /* Emit fence sequence & fire IRQ */ radeon_ring_write(ring, PACKET0(rdev->fence_drv[fence->ring].scratch_reg, 0)); radeon_ring_write(ring, fence->seq); @@ -860,13 +869,14 @@ bool r100_semaphore_ring_emit(struct radeon_device *rdev, return false; } -int r100_copy_blit(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; + struct radeon_fence *fence; uint32_t cur_pages; uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE; uint32_t pitch; @@ -887,7 +897,7 @@ int r100_copy_blit(struct radeon_device *rdev, r = radeon_ring_lock(rdev, ring, ndw); if (r) { DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw); - return -EINVAL; + return ERR_PTR(-EINVAL); } while (num_gpu_pages > 0) { cur_pages = num_gpu_pages; @@ -927,11 +937,13 @@ int r100_copy_blit(struct radeon_device *rdev, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE); - if (fence) { - r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); + r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - return r; + radeon_ring_unlock_commit(rdev, ring, false); + return fence; } static int r100_cp_wait_for_idle(struct radeon_device *rdev) @@ -963,7 +975,7 @@ void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) RADEON_ISYNC_ANY3D_IDLE2D | RADEON_ISYNC_WAIT_IDLEGUI | RADEON_ISYNC_CPSCRATCH_IDLEGUI); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } @@ -1401,7 +1413,6 @@ int r100_cs_parse_packet0(struct radeon_cs_parser *p, */ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) { - struct drm_mode_object *obj; struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; struct radeon_cs_packet p3reloc, waitreloc; @@ -1441,12 +1452,11 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p) header = radeon_get_ib_value(p, h_idx); crtc_id = radeon_get_ib_value(p, h_idx + 5); reg = R100_CP_PACKET0_GET_REG(header); - obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(p->rdev->ddev, crtc_id); + if (!crtc) { DRM_ERROR("cannot find crtc %d\n", crtc_id); return -ENOENT; } - crtc = obj_to_crtc(obj); radeon_crtc = to_radeon_crtc(crtc); crtc_id = radeon_crtc->crtc_id; @@ -3197,6 +3207,9 @@ void r100_bandwidth_update(struct radeon_device *rdev) uint32_t pixel_bytes1 = 0; uint32_t pixel_bytes2 = 0; + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); if (rdev->mode_info.crtcs[0]->base.enabled) { @@ -3631,7 +3644,7 @@ int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) } radeon_ring_write(ring, PACKET0(scratch, 0)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) { @@ -3693,7 +3706,7 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[6] = PACKET2(0); ib.ptr[7] = PACKET2(0); ib.length_dw = 8; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); goto free_ib; @@ -4067,39 +4080,6 @@ int r100_init(struct radeon_device *rdev) return 0; } -uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, - bool always_indirect) -{ - if (reg < rdev->rmmio_size && !always_indirect) - return readl(((void __iomem *)rdev->rmmio) + reg); - else { - unsigned long flags; - uint32_t ret; - - spin_lock_irqsave(&rdev->mmio_idx_lock, flags); - writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); - ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); - spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); - - return ret; - } -} - -void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, - bool always_indirect) -{ - if (reg < rdev->rmmio_size && !always_indirect) - writel(v, ((void __iomem *)rdev->rmmio) + reg); - else { - unsigned long flags; - - spin_lock_irqsave(&rdev->mmio_idx_lock, flags); - writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); - writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); - spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); - } -} - u32 r100_io_rreg(struct radeon_device *rdev, u32 reg) { if (reg < rdev->rio_mem_size) diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index 58f0473aa73f..732d4938aab7 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -80,13 +80,14 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0) return vtx_size; } -int r200_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *r200_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; + struct radeon_fence *fence; uint32_t size; uint32_t cur_size; int i, num_loops; @@ -98,7 +99,7 @@ int r200_copy_dma(struct radeon_device *rdev, r = radeon_ring_lock(rdev, ring, num_loops * 4 + 64); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } /* Must wait for 2D idle & clean before DMA or hangs might happen */ radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); @@ -118,11 +119,13 @@ int r200_copy_dma(struct radeon_device *rdev, } radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); radeon_ring_write(ring, RADEON_WAIT_DMA_GUI_IDLE); - if (fence) { - r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); + r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - return r; + radeon_ring_unlock_commit(rdev, ring, false); + return fence; } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 3c21d77a483d..1bc4704034ce 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -69,17 +69,23 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) mb(); } +#define R300_PTE_UNSNOOPED (1 << 0) #define R300_PTE_WRITEABLE (1 << 2) #define R300_PTE_READABLE (1 << 3) void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr) + uint64_t addr, uint32_t flags) { void __iomem *ptr = rdev->gart.ptr; addr = (lower_32_bits(addr) >> 8) | - ((upper_32_bits(addr) & 0xff) << 24) | - R300_PTE_WRITEABLE | R300_PTE_READABLE; + ((upper_32_bits(addr) & 0xff) << 24); + if (flags & RADEON_GART_PAGE_READ) + addr |= R300_PTE_READABLE; + if (flags & RADEON_GART_PAGE_WRITE) + addr |= R300_PTE_WRITEABLE; + if (!(flags & RADEON_GART_PAGE_SNOOP)) + addr |= R300_PTE_UNSNOOPED; /* on x86 we want this to be CPU endian, on powerpc * on powerpc without HW swappers, it'll get swapped on way * into VRAM - so no need for cpu_to_le32 on VRAM tables */ @@ -120,7 +126,6 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* discard memory request outside of configured range */ tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); @@ -290,7 +295,7 @@ void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, R300_GEOMETRY_ROUND_NEAREST | R300_COLOR_ROUND_NEAREST); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } static void r300_errata(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 84b1d5367a11..9418e388b045 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c @@ -34,10 +34,10 @@ */ #include <drm/drmP.h> -#include <drm/drm_buffer.h> #include <drm/radeon_drm.h> #include "radeon_drv.h" #include "r300_reg.h" +#include "drm_buffer.h" #include <asm/unaligned.h> diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 802b19220a21..2828605aef3f 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -219,7 +219,7 @@ static void r420_cp_errata_init(struct radeon_device *rdev) radeon_ring_write(ring, PACKET0(R300_CP_RESYNC_ADDR, 1)); radeon_ring_write(ring, rdev->config.r300.resync_scratch); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } static void r420_cp_errata_fini(struct radeon_device *rdev) @@ -232,7 +232,7 @@ static void r420_cp_errata_fini(struct radeon_device *rdev) radeon_ring_lock(rdev, ring, 8); radeon_ring_write(ring, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); radeon_ring_write(ring, R300_RB3D_DC_FINISH); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_scratch_free(rdev, rdev->config.r300.resync_scratch); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 3c69f58e46ef..56b02927cd3d 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -122,6 +122,94 @@ u32 r600_get_xclk(struct radeon_device *rdev) int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) { + unsigned fb_div = 0, ref_div, vclk_div = 0, dclk_div = 0; + int r; + + /* bypass vclk and dclk with bclk */ + WREG32_P(CG_UPLL_FUNC_CNTL_2, + VCLK_SRC_SEL(1) | DCLK_SRC_SEL(1), + ~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK)); + + /* assert BYPASS_EN, deassert UPLL_RESET, UPLL_SLEEP and UPLL_CTLREQ */ + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~( + UPLL_RESET_MASK | UPLL_SLEEP_MASK | UPLL_CTLREQ_MASK)); + + if (rdev->family >= CHIP_RS780) + WREG32_P(GFX_MACRO_BYPASS_CNTL, UPLL_BYPASS_CNTL, + ~UPLL_BYPASS_CNTL); + + if (!vclk || !dclk) { + /* keep the Bypass mode, put PLL to sleep */ + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); + return 0; + } + + if (rdev->clock.spll.reference_freq == 10000) + ref_div = 34; + else + ref_div = 4; + + r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000, + ref_div + 1, 0xFFF, 2, 30, ~0, + &fb_div, &vclk_div, &dclk_div); + if (r) + return r; + + if (rdev->family >= CHIP_RV670 && rdev->family < CHIP_RS780) + fb_div >>= 1; + else + fb_div |= 1; + + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); + if (r) + return r; + + /* assert PLL_RESET */ + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_RESET_MASK, ~UPLL_RESET_MASK); + + /* For RS780 we have to choose ref clk */ + if (rdev->family >= CHIP_RS780) + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REFCLK_SRC_SEL_MASK, + ~UPLL_REFCLK_SRC_SEL_MASK); + + /* set the required fb, ref and post divder values */ + WREG32_P(CG_UPLL_FUNC_CNTL, + UPLL_FB_DIV(fb_div) | + UPLL_REF_DIV(ref_div), + ~(UPLL_FB_DIV_MASK | UPLL_REF_DIV_MASK)); + WREG32_P(CG_UPLL_FUNC_CNTL_2, + UPLL_SW_HILEN(vclk_div >> 1) | + UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) | + UPLL_SW_HILEN2(dclk_div >> 1) | + UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)) | + UPLL_DIVEN_MASK | UPLL_DIVEN2_MASK, + ~UPLL_SW_MASK); + + /* give the PLL some time to settle */ + mdelay(15); + + /* deassert PLL_RESET */ + WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_RESET_MASK); + + mdelay(15); + + /* deassert BYPASS EN */ + WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); + + if (rdev->family >= CHIP_RS780) + WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~UPLL_BYPASS_CNTL); + + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); + if (r) + return r; + + /* switch VCLK and DCLK selection */ + WREG32_P(CG_UPLL_FUNC_CNTL_2, + VCLK_SRC_SEL(2) | DCLK_SRC_SEL(2), + ~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK)); + + mdelay(100); + return 0; } @@ -968,7 +1056,6 @@ static int r600_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Setup L2 cache */ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | @@ -993,6 +1080,8 @@ static int r600_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); @@ -1043,6 +1132,8 @@ static void r600_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp); radeon_gart_table_vram_unpin(rdev); } @@ -1339,7 +1430,7 @@ int r600_vram_scratch_init(struct radeon_device *rdev) if (rdev->vram_scratch.robj == NULL) { r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - NULL, &rdev->vram_scratch.robj); + 0, NULL, NULL, &rdev->vram_scratch.robj); if (r) { return r; } @@ -1813,7 +1904,6 @@ static void r600_gpu_init(struct radeon_device *rdev) { u32 tiling_config; u32 ramcfg; - u32 cc_rb_backend_disable; u32 cc_gc_shader_pipe_config; u32 tmp; int i, j; @@ -1940,29 +2030,20 @@ static void r600_gpu_init(struct radeon_device *rdev) } tiling_config |= BANK_SWAPS(1); - cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; - tmp = R6XX_MAX_BACKENDS - - r600_count_pipe_bits((cc_rb_backend_disable >> 16) & R6XX_MAX_BACKENDS_MASK); - if (tmp < rdev->config.r600.max_backends) { - rdev->config.r600.max_backends = tmp; - } - cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0x00ffff00; - tmp = R6XX_MAX_PIPES - - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R6XX_MAX_PIPES_MASK); - if (tmp < rdev->config.r600.max_pipes) { - rdev->config.r600.max_pipes = tmp; - } - tmp = R6XX_MAX_SIMDS - - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK); - if (tmp < rdev->config.r600.max_simds) { - rdev->config.r600.max_simds = tmp; - } tmp = rdev->config.r600.max_simds - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK); rdev->config.r600.active_simds = tmp; disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R6XX_MAX_BACKENDS_MASK; + tmp = 0; + for (i = 0; i < rdev->config.r600.max_backends; i++) + tmp |= (1 << i); + /* if all the backends are disabled, fix it up here */ + if ((disabled_rb_mask & tmp) == tmp) { + for (i = 0; i < rdev->config.r600.max_backends; i++) + disabled_rb_mask &= ~(1 << i); + } tmp = (tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.r600.max_backends, R6XX_MAX_BACKENDS, disabled_rb_mask); @@ -2548,7 +2629,7 @@ int r600_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(ring, 0); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); cp_me = 0xff; WREG32(R_0086D8_CP_ME_CNTL, cp_me); @@ -2684,7 +2765,7 @@ int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); radeon_ring_write(ring, ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) @@ -2754,6 +2835,17 @@ void r600_fence_ring_emit(struct radeon_device *rdev, } } +/** + * r600_semaphore_ring_emit - emit a semaphore on the CP ring + * + * @rdev: radeon_device pointer + * @ring: radeon ring buffer object + * @semaphore: radeon semaphore object + * @emit_wait: Is this a sempahore wait? + * + * Emits a semaphore signal/wait packet to the CP ring and prevents the PFP + * from running ahead of semaphore waits. + */ bool r600_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring, struct radeon_semaphore *semaphore, @@ -2769,6 +2861,13 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, lower_32_bits(addr)); radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel); + /* PFP_SYNC_ME packet only exists on 7xx+, only enable it on eg+ */ + if (emit_wait && (rdev->family >= CHIP_CEDAR)) { + /* Prevent the PFP from running ahead of the semaphore wait */ + radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); + radeon_ring_write(ring, 0x0); + } + return true; } @@ -2785,12 +2884,13 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev, * 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_fence *r600_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; 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; @@ -2800,7 +2900,7 @@ int r600_copy_cpdma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); @@ -2809,10 +2909,10 @@ int r600_copy_cpdma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); @@ -2839,17 +2939,17 @@ int r600_copy_cpdma(struct radeon_device *rdev, 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); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } int r600_set_surface_reg(struct radeon_device *rdev, int reg, @@ -2900,6 +3000,18 @@ static int r600_startup(struct radeon_device *rdev) return r; } + if (rdev->has_uvd) { + r = uvd_v1_0_resume(rdev); + if (!r) { + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + } + } + if (r) + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + } + /* Enable IRQ */ if (!rdev->irq.installed) { r = radeon_irq_kms_init(rdev); @@ -2928,6 +3040,18 @@ static int r600_startup(struct radeon_device *rdev) if (r) return r; + if (rdev->has_uvd) { + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + if (ring->ring_size) { + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, + RADEON_CP_PACKET2); + if (!r) + r = uvd_v1_0_init(rdev); + if (r) + DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + } + } + r = radeon_ib_pool_init(rdev); if (r) { dev_err(rdev->dev, "IB initialization failed (%d).\n", r); @@ -2987,6 +3111,10 @@ int r600_suspend(struct radeon_device *rdev) radeon_pm_suspend(rdev); r600_audio_fini(rdev); r600_cp_stop(rdev); + if (rdev->has_uvd) { + uvd_v1_0_fini(rdev); + radeon_uvd_suspend(rdev); + } r600_irq_suspend(rdev); radeon_wb_disable(rdev); r600_pcie_gart_disable(rdev); @@ -3066,6 +3194,14 @@ int r600_init(struct radeon_device *rdev) rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); + if (rdev->has_uvd) { + r = radeon_uvd_init(rdev); + if (!r) { + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); + } + } + rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -3095,6 +3231,10 @@ void r600_fini(struct radeon_device *rdev) r600_audio_fini(rdev); r600_cp_fini(rdev); r600_irq_fini(rdev); + if (rdev->has_uvd) { + uvd_v1_0_fini(rdev); + radeon_uvd_fini(rdev); + } radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); @@ -3166,7 +3306,7 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); ib.ptr[2] = 0xDEADBEEF; ib.length_dw = 3; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); goto free_ib; @@ -3227,8 +3367,8 @@ int r600_ih_ring_alloc(struct radeon_device *rdev) if (rdev->ih.ring_obj == NULL) { r = radeon_bo_create(rdev, rdev->ih.ring_size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, - NULL, &rdev->ih.ring_obj); + RADEON_GEM_DOMAIN_GTT, 0, + NULL, NULL, &rdev->ih.ring_obj); if (r) { DRM_ERROR("radeon: failed to create ih ring buffer (%d).\n", r); return r; @@ -3785,17 +3925,17 @@ static u32 r600_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -3924,11 +4064,13 @@ restart_ih: break; case 9: /* D1 pflip */ DRM_DEBUG("IH: D1 flip\n"); - radeon_crtc_handle_flip(rdev, 0); + if (radeon_use_pflipirq > 0) + radeon_crtc_handle_flip(rdev, 0); break; case 11: /* D2 pflip */ DRM_DEBUG("IH: D2 flip\n"); - radeon_crtc_handle_flip(rdev, 1); + if (radeon_use_pflipirq > 0) + radeon_crtc_handle_flip(rdev, 1); break; case 19: /* HPD/DAC hotplug */ switch (src_data) { @@ -4039,6 +4181,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -4047,7 +4190,6 @@ restart_ih: if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ @@ -4089,16 +4231,15 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev) } /** - * r600_ioctl_wait_idle - flush host path cache on wait idle ioctl + * r600_mmio_hdp_flush - flush Host Data Path cache via MMIO * rdev: radeon device structure - * bo: buffer object struct which userspace is waiting for idle * - * Some R6XX/R7XX doesn't seems to take into account HDP flush performed - * through ring buffer, this leads to corruption in rendering, see - * http://bugzilla.kernel.org/show_bug.cgi?id=15186 to avoid this we - * directly perform HDP flush by writing register through MMIO. + * Some R6XX/R7XX don't seem to take into account HDP flushes performed + * through the ring buffer. This leads to corruption in rendering, see + * http://bugzilla.kernel.org/show_bug.cgi?id=15186 . To avoid this, we + * directly perform the HDP flush by writing the register through MMIO. */ -void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) +void r600_mmio_hdp_flush(struct radeon_device *rdev) { /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL. diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c deleted file mode 100644 index bffac10c4296..000000000000 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2008 Advanced Micro Devices, Inc. - * Copyright 2008 Red Hat Inc. - * Copyright 2009 Christian König. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Christian König - */ -#include <drm/drmP.h> -#include "radeon.h" -#include "radeon_reg.h" -#include "radeon_asic.h" -#include "atom.h" - -/* - * check if enc_priv stores radeon_encoder_atom_dig - */ -static bool radeon_dig_encoder(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - return true; - } - return false; -} - -/* - * check if the chipset is supported - */ -static int r600_audio_chipset_supported(struct radeon_device *rdev) -{ - return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); -} - -struct r600_audio_pin r600_audio_status(struct radeon_device *rdev) -{ - struct r600_audio_pin status; - uint32_t value; - - value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL); - - /* number of channels */ - status.channels = (value & 0x7) + 1; - - /* bits per sample */ - switch ((value & 0xF0) >> 4) { - case 0x0: - status.bits_per_sample = 8; - break; - case 0x1: - status.bits_per_sample = 16; - break; - case 0x2: - status.bits_per_sample = 20; - break; - case 0x3: - status.bits_per_sample = 24; - break; - case 0x4: - status.bits_per_sample = 32; - break; - default: - dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n", - (int)value); - status.bits_per_sample = 16; - } - - /* current sampling rate in HZ */ - if (value & 0x4000) - status.rate = 44100; - else - status.rate = 48000; - status.rate *= ((value >> 11) & 0x7) + 1; - status.rate /= ((value >> 8) & 0x7) + 1; - - value = RREG32(R600_AUDIO_STATUS_BITS); - - /* iec 60958 status bits */ - status.status_bits = value & 0xff; - - /* iec 60958 category code */ - status.category_code = (value >> 8) & 0xff; - - return status; -} - -/* - * update all hdmi interfaces with current audio parameters - */ -void r600_audio_update_hdmi(struct work_struct *work) -{ - struct radeon_device *rdev = container_of(work, struct radeon_device, - audio_work); - struct drm_device *dev = rdev->ddev; - struct r600_audio_pin audio_status = r600_audio_status(rdev); - struct drm_encoder *encoder; - bool changed = false; - - if (rdev->audio.pin[0].channels != audio_status.channels || - rdev->audio.pin[0].rate != audio_status.rate || - rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample || - rdev->audio.pin[0].status_bits != audio_status.status_bits || - rdev->audio.pin[0].category_code != audio_status.category_code) { - rdev->audio.pin[0] = audio_status; - changed = true; - } - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (!radeon_dig_encoder(encoder)) - continue; - if (changed || r600_hdmi_buffer_status_changed(encoder)) - r600_hdmi_update_audio_settings(encoder); - } -} - -/* enable the audio stream */ -void r600_audio_enable(struct radeon_device *rdev, - struct r600_audio_pin *pin, - bool enable) -{ - u32 value = 0; - - if (!pin) - return; - - if (ASIC_IS_DCE4(rdev)) { - if (enable) { - value |= 0x81000000; /* Required to enable audio */ - value |= 0x0e1000f0; /* fglrx sets that too */ - } - WREG32(EVERGREEN_AUDIO_ENABLE, value); - } else { - WREG32_P(R600_AUDIO_ENABLE, - enable ? 0x81000000 : 0x0, ~0x81000000); - } -} - -/* - * initialize the audio vars - */ -int r600_audio_init(struct radeon_device *rdev) -{ - if (!radeon_audio || !r600_audio_chipset_supported(rdev)) - return 0; - - rdev->audio.enabled = true; - - rdev->audio.num_pins = 1; - rdev->audio.pin[0].channels = -1; - rdev->audio.pin[0].rate = -1; - rdev->audio.pin[0].bits_per_sample = -1; - rdev->audio.pin[0].status_bits = 0; - rdev->audio.pin[0].category_code = 0; - rdev->audio.pin[0].id = 0; - /* disable audio. it will be set up later */ - r600_audio_enable(rdev, &rdev->audio.pin[0], false); - - return 0; -} - -/* - * release the audio timer - * TODO: How to do this correctly on SMP systems? - */ -void r600_audio_fini(struct radeon_device *rdev) -{ - if (!rdev->audio.enabled) - return; - - r600_audio_enable(rdev, &rdev->audio.pin[0], false); - - rdev->audio.enabled = false; -} - -struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev) -{ - /* only one pin on 6xx-NI */ - return &rdev->audio.pin[0]; -} diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 8c9b7e26533c..09e3f39925fa 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -1949,15 +1949,15 @@ int r600_do_cleanup_cp(struct drm_device *dev) #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { if (dev_priv->cp_ring != NULL) { - drm_core_ioremapfree(dev_priv->cp_ring, dev); + drm_legacy_ioremapfree(dev_priv->cp_ring, dev); dev_priv->cp_ring = NULL; } if (dev_priv->ring_rptr != NULL) { - drm_core_ioremapfree(dev_priv->ring_rptr, dev); + drm_legacy_ioremapfree(dev_priv->ring_rptr, dev); dev_priv->ring_rptr = NULL; } if (dev->agp_buffer_map != NULL) { - drm_core_ioremapfree(dev->agp_buffer_map, dev); + drm_legacy_ioremapfree(dev->agp_buffer_map, dev); dev->agp_buffer_map = NULL; } } else @@ -1968,7 +1968,7 @@ int r600_do_cleanup_cp(struct drm_device *dev) r600_page_table_cleanup(dev, &dev_priv->gart_info); if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { - drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); + drm_legacy_ioremapfree(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = NULL; } } @@ -2052,27 +2052,27 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->buffers_offset = init->buffers_offset; dev_priv->gart_textures_offset = init->gart_textures_offset; - master_priv->sarea = drm_getsarea(dev); + master_priv->sarea = drm_legacy_getsarea(dev); if (!master_priv->sarea) { DRM_ERROR("could not find sarea!\n"); r600_do_cleanup_cp(dev); return -EINVAL; } - dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset); + dev_priv->cp_ring = drm_legacy_findmap(dev, init->ring_offset); if (!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); r600_do_cleanup_cp(dev); return -EINVAL; } - dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); + dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset); if (!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); r600_do_cleanup_cp(dev); return -EINVAL; } dev->agp_buffer_token = init->buffers_offset; - dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); r600_do_cleanup_cp(dev); @@ -2081,7 +2081,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, if (init->gart_textures_offset) { dev_priv->gart_textures = - drm_core_findmap(dev, init->gart_textures_offset); + drm_legacy_findmap(dev, init->gart_textures_offset); if (!dev_priv->gart_textures) { DRM_ERROR("could not find GART texture region!\n"); r600_do_cleanup_cp(dev); @@ -2092,9 +2092,9 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, #if __OS_HAS_AGP /* XXX */ if (dev_priv->flags & RADEON_IS_AGP) { - drm_core_ioremap_wc(dev_priv->cp_ring, dev); - drm_core_ioremap_wc(dev_priv->ring_rptr, dev); - drm_core_ioremap_wc(dev->agp_buffer_map, dev); + drm_legacy_ioremap_wc(dev_priv->cp_ring, dev); + drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev); + drm_legacy_ioremap_wc(dev->agp_buffer_map, dev); if (!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev->agp_buffer_map->handle) { @@ -2235,7 +2235,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->gart_info.mapping.size = dev_priv->gart_info.table_size; - drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev); + drm_legacy_ioremap_wc(&dev_priv->gart_info.mapping, dev); if (!dev_priv->gart_info.mapping.handle) { DRM_ERROR("ioremap failed.\n"); r600_do_cleanup_cp(dev); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 12511bb5fd6f..c47537a1ddba 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -825,7 +825,6 @@ int r600_cs_common_vline_parse(struct radeon_cs_parser *p, uint32_t *vline_start_end, uint32_t *vline_status) { - struct drm_mode_object *obj; struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; struct radeon_cs_packet p3reloc, wait_reg_mem; @@ -887,12 +886,11 @@ int r600_cs_common_vline_parse(struct radeon_cs_parser *p, crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); reg = R600_CP_PACKET0_GET_REG(header); - obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); - if (!obj) { + crtc = drm_crtc_find(p->rdev->ddev, crtc_id); + if (!crtc) { DRM_ERROR("cannot find crtc %d\n", crtc_id); return -ENOENT; } - crtc = obj_to_crtc(obj); radeon_crtc = to_radeon_crtc(crtc); crtc_id = radeon_crtc->crtc_id; diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 4969cef44a19..cf0df45d455e 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c @@ -124,15 +124,6 @@ int r600_dma_resume(struct radeon_device *rdev) u32 rb_bufsz; int r; - /* Reset dma */ - if (rdev->family >= CHIP_RV770) - WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA); - else - WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); - RREG32(SRBM_SOFT_RESET); - udelay(50); - WREG32(SRBM_SOFT_RESET, 0); - WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL, 0); WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL, 0); @@ -241,16 +232,19 @@ int r600_dma_ring_test(struct radeon_device *rdev, { unsigned i; int r; - void __iomem *ptr = (void *)rdev->vram_scratch.ptr; + unsigned index; u32 tmp; + u64 gpu_addr; - if (!ptr) { - DRM_ERROR("invalid vram scratch pointer\n"); - return -EINVAL; - } + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + index = R600_WB_DMA_RING_TEST_OFFSET; + else + index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; + + gpu_addr = rdev->wb.gpu_addr + index; tmp = 0xCAFEDEAD; - writel(tmp, ptr); + rdev->wb.wb[index/4] = cpu_to_le32(tmp); r = radeon_ring_lock(rdev, ring, 4); if (r) { @@ -258,13 +252,13 @@ int r600_dma_ring_test(struct radeon_device *rdev, return r; } radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); - radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); - radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff); + radeon_ring_write(ring, lower_32_bits(gpu_addr)); + radeon_ring_write(ring, upper_32_bits(gpu_addr) & 0xff); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { - tmp = readl(ptr); + tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); @@ -344,17 +338,17 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) { struct radeon_ib ib; unsigned i; + unsigned index; int r; - void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp = 0; + u64 gpu_addr; - if (!ptr) { - DRM_ERROR("invalid vram scratch pointer\n"); - return -EINVAL; - } + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + index = R600_WB_DMA_RING_TEST_OFFSET; + else + index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; - tmp = 0xCAFEDEAD; - writel(tmp, ptr); + gpu_addr = rdev->wb.gpu_addr + index; r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); if (r) { @@ -363,12 +357,12 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) } ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1); - ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc; - ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff; + ib.ptr[1] = lower_32_bits(gpu_addr); + ib.ptr[2] = upper_32_bits(gpu_addr) & 0xff; ib.ptr[3] = 0xDEADBEEF; ib.length_dw = 4; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); @@ -380,7 +374,7 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) return r; } for (i = 0; i < rdev->usec_timeout; i++) { - tmp = readl(ptr); + tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); @@ -436,18 +430,19 @@ void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) * @src_offset: src GPU address * @dst_offset: dst GPU address * @num_gpu_pages: number of GPU pages to xfer - * @fence: radeon fence object + * @resv: reservation object to sync to * * Copy GPU paging using the DMA engine (r6xx). * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ -int r600_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *r600_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; int ring_index = rdev->asic->copy.dma_ring_index; struct radeon_ring *ring = &rdev->ring[ring_index]; u32 size_in_dw, cur_size_in_dw; @@ -457,7 +452,7 @@ int r600_copy_dma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; @@ -466,10 +461,10 @@ int r600_copy_dma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); for (i = 0; i < num_loops; i++) { @@ -486,15 +481,15 @@ int r600_copy_dma(struct radeon_device *rdev, dst_offset += cur_size_in_dw * 4; } - r = radeon_fence_emit(rdev, fence, ring->idx); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 9c61b74ef441..f6309bd23e01 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -24,6 +24,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "r600d.h" #include "r600_dpm.h" #include "atom.h" diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 26ef8ced6f89..b90dc0eb08e6 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -72,6 +72,169 @@ static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { /* + * check if the chipset is supported + */ +static int r600_audio_chipset_supported(struct radeon_device *rdev) +{ + return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); +} + +static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev) +{ + struct r600_audio_pin status; + uint32_t value; + + value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL); + + /* number of channels */ + status.channels = (value & 0x7) + 1; + + /* bits per sample */ + switch ((value & 0xF0) >> 4) { + case 0x0: + status.bits_per_sample = 8; + break; + case 0x1: + status.bits_per_sample = 16; + break; + case 0x2: + status.bits_per_sample = 20; + break; + case 0x3: + status.bits_per_sample = 24; + break; + case 0x4: + status.bits_per_sample = 32; + break; + default: + dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n", + (int)value); + status.bits_per_sample = 16; + } + + /* current sampling rate in HZ */ + if (value & 0x4000) + status.rate = 44100; + else + status.rate = 48000; + status.rate *= ((value >> 11) & 0x7) + 1; + status.rate /= ((value >> 8) & 0x7) + 1; + + value = RREG32(R600_AUDIO_STATUS_BITS); + + /* iec 60958 status bits */ + status.status_bits = value & 0xff; + + /* iec 60958 category code */ + status.category_code = (value >> 8) & 0xff; + + return status; +} + +/* + * update all hdmi interfaces with current audio parameters + */ +void r600_audio_update_hdmi(struct work_struct *work) +{ + struct radeon_device *rdev = container_of(work, struct radeon_device, + audio_work); + struct drm_device *dev = rdev->ddev; + struct r600_audio_pin audio_status = r600_audio_status(rdev); + struct drm_encoder *encoder; + bool changed = false; + + if (rdev->audio.pin[0].channels != audio_status.channels || + rdev->audio.pin[0].rate != audio_status.rate || + rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample || + rdev->audio.pin[0].status_bits != audio_status.status_bits || + rdev->audio.pin[0].category_code != audio_status.category_code) { + rdev->audio.pin[0] = audio_status; + changed = true; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (!radeon_encoder_is_digital(encoder)) + continue; + if (changed || r600_hdmi_buffer_status_changed(encoder)) + r600_hdmi_update_audio_settings(encoder); + } +} + +/* enable the audio stream */ +void r600_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, + u8 enable_mask) +{ + u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL); + + if (!pin) + return; + + if (enable_mask) { + tmp |= AUDIO_ENABLED; + if (enable_mask & 1) + tmp |= PIN0_AUDIO_ENABLED; + if (enable_mask & 2) + tmp |= PIN1_AUDIO_ENABLED; + if (enable_mask & 4) + tmp |= PIN2_AUDIO_ENABLED; + if (enable_mask & 8) + tmp |= PIN3_AUDIO_ENABLED; + } else { + tmp &= ~(AUDIO_ENABLED | + PIN0_AUDIO_ENABLED | + PIN1_AUDIO_ENABLED | + PIN2_AUDIO_ENABLED | + PIN3_AUDIO_ENABLED); + } + + WREG32(AZ_HOT_PLUG_CONTROL, tmp); +} + +/* + * initialize the audio vars + */ +int r600_audio_init(struct radeon_device *rdev) +{ + if (!radeon_audio || !r600_audio_chipset_supported(rdev)) + return 0; + + rdev->audio.enabled = true; + + rdev->audio.num_pins = 1; + rdev->audio.pin[0].channels = -1; + rdev->audio.pin[0].rate = -1; + rdev->audio.pin[0].bits_per_sample = -1; + rdev->audio.pin[0].status_bits = 0; + rdev->audio.pin[0].category_code = 0; + rdev->audio.pin[0].id = 0; + /* disable audio. it will be set up later */ + r600_audio_enable(rdev, &rdev->audio.pin[0], 0); + + return 0; +} + +/* + * release the audio timer + * TODO: How to do this correctly on SMP systems? + */ +void r600_audio_fini(struct radeon_device *rdev) +{ + if (!rdev->audio.enabled) + return; + + r600_audio_enable(rdev, &rdev->audio.pin[0], 0); + + rdev->audio.enabled = false; +} + +struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev) +{ + /* only one pin on 6xx-NI */ + return &rdev->audio.pin[0]; +} + +/* * calculate CTS and N values if they are not found in the table */ static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq) @@ -357,7 +520,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod /* disable audio prior to setting up hw */ dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, false); + r600_audio_enable(rdev, dig->afmt->pin, 0xf); r600_audio_set_dto(encoder, mode->clock); @@ -443,7 +606,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); /* enable audio after to setting up hw */ - r600_audio_enable(rdev, dig->afmt->pin, true); + r600_audio_enable(rdev, dig->afmt->pin, 0xf); } /** @@ -528,6 +691,11 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) if (!enable && !dig->afmt->enabled) return; + if (!enable && dig->afmt->pin) { + r600_audio_enable(rdev, dig->afmt->pin, 0); + dig->afmt->pin = NULL; + } + /* Older chipsets require setting HDMI and routing manually */ if (!ASIC_IS_DCE3(rdev)) { if (enable) diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index f94e7a9afe75..1e8495cca41e 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -44,13 +44,6 @@ #define R6XX_MAX_PIPES 8 #define R6XX_MAX_PIPES_MASK 0xff -/* PTE flags */ -#define PTE_VALID (1 << 0) -#define PTE_SYSTEM (1 << 1) -#define PTE_SNOOPED (1 << 2) -#define PTE_READABLE (1 << 5) -#define PTE_WRITEABLE (1 << 6) - /* tiling bits */ #define ARRAY_LINEAR_GENERAL 0x00000000 #define ARRAY_LINEAR_ALIGNED 0x00000001 @@ -330,11 +323,12 @@ #define HDP_TILING_CONFIG 0x2F3C #define HDP_DEBUG1 0x2F34 +#define MC_CONFIG 0x2000 #define MC_VM_AGP_TOP 0x2184 #define MC_VM_AGP_BOT 0x2188 #define MC_VM_AGP_BASE 0x218C #define MC_VM_FB_LOCATION 0x2180 -#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C +#define MC_VM_L1_TLB_MCB_RD_UVD_CNTL 0x2124 #define ENABLE_L1_TLB (1 << 0) #define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1) #define ENABLE_L1_STRICT_ORDERING (1 << 2) @@ -354,12 +348,14 @@ #define EFFECTIVE_L1_QUEUE_SIZE(x) (((x) & 7) << 15) #define EFFECTIVE_L1_QUEUE_SIZE_MASK 0x00038000 #define EFFECTIVE_L1_QUEUE_SIZE_SHIFT 15 +#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C #define MC_VM_L1_TLB_MCD_RD_B_CNTL 0x21A0 #define MC_VM_L1_TLB_MCB_RD_GFX_CNTL 0x21FC #define MC_VM_L1_TLB_MCB_RD_HDP_CNTL 0x2204 #define MC_VM_L1_TLB_MCB_RD_PDMA_CNTL 0x2208 #define MC_VM_L1_TLB_MCB_RD_SEM_CNTL 0x220C #define MC_VM_L1_TLB_MCB_RD_SYS_CNTL 0x2200 +#define MC_VM_L1_TLB_MCB_WR_UVD_CNTL 0x212c #define MC_VM_L1_TLB_MCD_WR_A_CNTL 0x21A4 #define MC_VM_L1_TLB_MCD_WR_B_CNTL 0x21A8 #define MC_VM_L1_TLB_MCB_WR_GFX_CNTL 0x2210 @@ -373,6 +369,8 @@ #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194 #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198 +#define RS_DQ_RD_RET_CONF 0x2348 + #define PA_CL_ENHANCE 0x8A14 #define CLIP_VTX_REORDER_ENA (1 << 0) #define NUM_CLIP_SEQ(x) ((x) << 1) @@ -929,6 +927,23 @@ # define TARGET_LINK_SPEED_MASK (0xf << 0) # define SELECTABLE_DEEMPHASIS (1 << 6) +/* Audio */ +#define AZ_HOT_PLUG_CONTROL 0x7300 +# define AZ_FORCE_CODEC_WAKE (1 << 0) +# define JACK_DETECTION_ENABLE (1 << 4) +# define UNSOLICITED_RESPONSE_ENABLE (1 << 8) +# define CODEC_HOT_PLUG_ENABLE (1 << 12) +# define AUDIO_ENABLED (1 << 31) +/* DCE3 adds */ +# define PIN0_JACK_DETECTION_ENABLE (1 << 4) +# define PIN1_JACK_DETECTION_ENABLE (1 << 5) +# define PIN2_JACK_DETECTION_ENABLE (1 << 6) +# define PIN3_JACK_DETECTION_ENABLE (1 << 7) +# define PIN0_AUDIO_ENABLED (1 << 24) +# define PIN1_AUDIO_ENABLED (1 << 25) +# define PIN2_AUDIO_ENABLED (1 << 26) +# define PIN3_AUDIO_ENABLED (1 << 27) + /* Audio clocks DCE 2.0/3.0 */ #define AUDIO_DTO 0x7340 # define AUDIO_DTO_PHASE(x) (((x) & 0xffff) << 0) @@ -1483,6 +1498,7 @@ #define UVD_CGC_GATE 0xf4a8 #define UVD_LMI_CTRL2 0xf4f4 #define UVD_MASTINT_EN 0xf500 +#define UVD_FW_START 0xf51C #define UVD_LMI_ADDR_EXT 0xf594 #define UVD_LMI_CTRL 0xf598 #define UVD_LMI_SWAP_CNTL 0xf5b4 @@ -1495,6 +1511,13 @@ #define UVD_MPC_SET_MUX 0xf5f4 #define UVD_MPC_SET_ALU 0xf5f8 +#define UVD_VCPU_CACHE_OFFSET0 0xf608 +#define UVD_VCPU_CACHE_SIZE0 0xf60c +#define UVD_VCPU_CACHE_OFFSET1 0xf610 +#define UVD_VCPU_CACHE_SIZE1 0xf614 +#define UVD_VCPU_CACHE_OFFSET2 0xf618 +#define UVD_VCPU_CACHE_SIZE2 0xf61c + #define UVD_VCPU_CNTL 0xf660 #define UVD_SOFT_RESET 0xf680 #define RBC_SOFT_RESET (1<<0) @@ -1524,9 +1547,35 @@ #define UVD_CONTEXT_ID 0xf6f4 +/* rs780 only */ +#define GFX_MACRO_BYPASS_CNTL 0x30c0 +#define SPLL_BYPASS_CNTL (1 << 0) +#define UPLL_BYPASS_CNTL (1 << 1) + +#define CG_UPLL_FUNC_CNTL 0x7e0 +# define UPLL_RESET_MASK 0x00000001 +# define UPLL_SLEEP_MASK 0x00000002 +# define UPLL_BYPASS_EN_MASK 0x00000004 # define UPLL_CTLREQ_MASK 0x00000008 +# define UPLL_FB_DIV(x) ((x) << 4) +# define UPLL_FB_DIV_MASK 0x0000FFF0 +# define UPLL_REF_DIV(x) ((x) << 16) +# define UPLL_REF_DIV_MASK 0x003F0000 +# define UPLL_REFCLK_SRC_SEL_MASK 0x20000000 # define UPLL_CTLACK_MASK 0x40000000 # define UPLL_CTLACK2_MASK 0x80000000 +#define CG_UPLL_FUNC_CNTL_2 0x7e4 +# define UPLL_SW_HILEN(x) ((x) << 0) +# define UPLL_SW_LOLEN(x) ((x) << 4) +# define UPLL_SW_HILEN2(x) ((x) << 8) +# define UPLL_SW_LOLEN2(x) ((x) << 12) +# define UPLL_DIVEN_MASK 0x00010000 +# define UPLL_DIVEN2_MASK 0x00020000 +# define UPLL_SW_MASK 0x0003FFFF +# define VCLK_SRC_SEL(x) ((x) << 20) +# define VCLK_SRC_SEL_MASK 0x01F00000 +# define DCLK_SRC_SEL(x) ((x) << 25) +# define DCLK_SRC_SEL_MASK 0x3E000000 /* * PM4 @@ -1597,6 +1646,7 @@ */ # define PACKET3_CP_DMA_CMD_SAIC (1 << 28) # define PACKET3_CP_DMA_CMD_DAIC (1 << 29) +#define PACKET3_PFP_SYNC_ME 0x42 /* r7xx+ only */ #define PACKET3_SURFACE_SYNC 0x43 # define PACKET3_CB0_DEST_BASE_ENA (1 << 6) # define PACKET3_FULL_CACHE_ENA (1 << 20) /* r7xx+ only */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 60c47f829122..a9717b3fbf1b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -64,6 +64,9 @@ #include <linux/wait.h> #include <linux/list.h> #include <linux/kref.h> +#include <linux/interval_tree.h> +#include <linux/hashtable.h> +#include <linux/fence.h> #include <ttm/ttm_bo_api.h> #include <ttm/ttm_bo_driver.h> @@ -71,6 +74,8 @@ #include <ttm/ttm_module.h> #include <ttm/ttm_execbuf_util.h> +#include <drm/drm_gem.h> + #include "radeon_family.h" #include "radeon_mode.h" #include "radeon_reg.h" @@ -103,6 +108,9 @@ extern int radeon_hard_reset; extern int radeon_vm_size; extern int radeon_vm_block_size; extern int radeon_deep_color; +extern int radeon_use_pflipirq; +extern int radeon_bapm; +extern int radeon_backlight; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -116,9 +124,6 @@ extern int radeon_deep_color; #define RADEONFB_CONN_LIMIT 4 #define RADEON_BIOS_NUM_SCRATCH 8 -/* fence seq are set to this number when signaled */ -#define RADEON_FENCE_SIGNALED_SEQ 0LL - /* internal ring indices */ /* r1xx+ has gfx CP ring */ #define RADEON_RING_TYPE_GFX_INDEX 0 @@ -304,6 +309,9 @@ int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *r u16 *vddc, u16 *vddci, u16 virtual_voltage_id, u16 vbios_voltage_id); +int radeon_atom_get_voltage_evv(struct radeon_device *rdev, + u16 virtual_voltage_id, + u16 *voltage); int radeon_atom_round_to_true_voltage(struct radeon_device *rdev, u8 voltage_type, u16 nominal_voltage, @@ -317,6 +325,9 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev, struct atom_voltage_table *voltage_table); bool radeon_atom_is_voltage_gpio(struct radeon_device *rdev, u8 voltage_type, u8 voltage_mode); +int radeon_atom_get_svi2_info(struct radeon_device *rdev, + u8 voltage_type, + u8 *svd_gpio_id, u8 *svc_gpio_id); void radeon_atom_update_memory_dll(struct radeon_device *rdev, u32 mem_clock); void radeon_atom_set_ac_timing(struct radeon_device *rdev, @@ -340,28 +351,32 @@ extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw, * Fences. */ struct radeon_fence_driver { + struct radeon_device *rdev; uint32_t scratch_reg; uint64_t gpu_addr; volatile uint32_t *cpu_addr; /* sync_seq is protected by ring emission lock */ uint64_t sync_seq[RADEON_NUM_RINGS]; atomic64_t last_seq; - bool initialized; + bool initialized, delayed_irq; + struct delayed_work lockup_work; }; struct radeon_fence { + struct fence base; + struct radeon_device *rdev; - struct kref kref; - /* protected by radeon_fence.lock */ uint64_t seq; /* RB, DMA, etc. */ unsigned ring; + + wait_queue_t fence_wake; }; int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); int radeon_fence_driver_init(struct radeon_device *rdev); void radeon_fence_driver_fini(struct radeon_device *rdev); -void radeon_fence_driver_force_completion(struct radeon_device *rdev); +void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring); int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); @@ -441,14 +456,12 @@ struct radeon_mman { struct radeon_bo_va { /* protected by bo being reserved */ struct list_head bo_list; - uint64_t soffset; - uint64_t eoffset; uint32_t flags; - bool valid; + uint64_t addr; unsigned ref_count; /* protected by vm mutex */ - struct list_head vm_list; + struct interval_tree_node it; struct list_head vm_status; /* constant after initialization */ @@ -461,10 +474,11 @@ struct radeon_bo { struct list_head list; /* Protected by tbo.reserved */ u32 initial_domain; - u32 placements[3]; + struct ttm_place placements[3]; struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; + u32 flags; unsigned pin_count; void *kptr; u32 tiling_flags; @@ -480,6 +494,9 @@ struct radeon_bo { struct ttm_bo_kmap_obj dma_buf_vmap; pid_t pid; + + struct radeon_mn *mn; + struct interval_tree_node mn_it; }; #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) @@ -543,9 +560,9 @@ struct radeon_gem { int radeon_gem_init(struct radeon_device *rdev); void radeon_gem_fini(struct radeon_device *rdev); -int radeon_gem_object_create(struct radeon_device *rdev, int size, +int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size, int alignment, int initial_domain, - bool discardable, bool kernel, + u32 flags, bool kernel, struct drm_gem_object **obj); int radeon_mode_dumb_create(struct drm_file *file_priv, @@ -571,8 +588,12 @@ bool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring, struct radeon_semaphore *semaphore); bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring, struct radeon_semaphore *semaphore); -void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore, - struct radeon_fence *fence); +void radeon_semaphore_sync_fence(struct radeon_semaphore *semaphore, + struct radeon_fence *fence); +int radeon_semaphore_sync_resv(struct radeon_device *rdev, + struct radeon_semaphore *semaphore, + struct reservation_object *resv, + bool shared); int radeon_semaphore_sync_rings(struct radeon_device *rdev, struct radeon_semaphore *semaphore, int waiting_ring); @@ -590,6 +611,12 @@ struct radeon_mc; #define RADEON_GPU_PAGE_SHIFT 12 #define RADEON_GPU_PAGE_ALIGN(a) (((a) + RADEON_GPU_PAGE_MASK) & ~RADEON_GPU_PAGE_MASK) +#define RADEON_GART_PAGE_DUMMY 0 +#define RADEON_GART_PAGE_VALID (1 << 0) +#define RADEON_GART_PAGE_READ (1 << 1) +#define RADEON_GART_PAGE_WRITE (1 << 2) +#define RADEON_GART_PAGE_SNOOP (1 << 3) + struct radeon_gart { dma_addr_t table_addr; struct radeon_bo *robj; @@ -614,8 +641,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, int pages); int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages, struct page **pagelist, - dma_addr_t *dma_addr); -void radeon_gart_restore(struct radeon_device *rdev); + dma_addr_t *dma_addr, uint32_t flags); /* @@ -688,7 +714,7 @@ struct radeon_flip_work { uint64_t base; struct drm_pending_vblank_event *event; struct radeon_bo *old_rbo; - struct radeon_fence *fence; + struct fence *fence; }; struct r500_irq_stat_regs { @@ -766,6 +792,7 @@ struct radeon_irq { int radeon_irq_kms_init(struct radeon_device *rdev); void radeon_irq_kms_fini(struct radeon_device *rdev); void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring); +bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring); void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring); void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc); void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc); @@ -855,9 +882,9 @@ struct radeon_mec { #define R600_PTE_FRAG_64KB (4 << 7) #define R600_PTE_FRAG_256KB (6 << 7) -/* flags used for GART page table entries on R600+ */ -#define R600_PTE_GART ( R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED \ - | R600_PTE_READABLE | R600_PTE_WRITEABLE) +/* flags needed to be set so we can copy directly from the GART table */ +#define R600_PTE_GART_MASK ( R600_PTE_READABLE | R600_PTE_WRITEABLE | \ + R600_PTE_SYSTEM | R600_PTE_VALID ) struct radeon_vm_pt { struct radeon_bo *bo; @@ -865,9 +892,12 @@ struct radeon_vm_pt { }; struct radeon_vm { - struct list_head va; + struct rb_root va; unsigned id; + /* BOs moved, but not yet updated in the PT */ + struct list_head invalidated; + /* BOs freed, but not yet updated in the PT */ struct list_head freed; @@ -899,6 +929,8 @@ struct radeon_vm_manager { u64 vram_base_offset; /* is vm enabled? */ bool enabled; + /* for hw to save the PD addr on suspend/resume */ + uint32_t saved_table_addr[RADEON_NUM_VM]; }; /* @@ -952,7 +984,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring, unsigned size); void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib); int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, - struct radeon_ib *const_ib); + struct radeon_ib *const_ib, bool hdp_flush); int radeon_ib_pool_init(struct radeon_device *rdev); void radeon_ib_pool_fini(struct radeon_device *rdev); int radeon_ib_ring_tests(struct radeon_device *rdev); @@ -962,8 +994,10 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev, void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp); int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw); int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw); -void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp); -void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp); +void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp, + bool hdp_flush); +void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp, + bool hdp_flush); void radeon_ring_undo(struct radeon_ring *ring); void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp); int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); @@ -1099,6 +1133,8 @@ struct radeon_wb { #define R600_WB_EVENT_OFFSET 3072 #define CIK_WB_CP1_WPTR_OFFSET 3328 #define CIK_WB_CP2_WPTR_OFFSET 3584 +#define R600_WB_DMA_RING_TEST_OFFSET 3588 +#define CAYMAN_WB_DMA1_RING_TEST_OFFSET 3592 /** * struct radeon_pm - power management datas @@ -1621,7 +1657,8 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence); int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence); -void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo); +void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, + uint32_t allowed_domains); void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp); int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); @@ -1710,6 +1747,11 @@ void radeon_test_ring_sync(struct radeon_device *rdev, struct radeon_ring *cpB); void radeon_test_syncing(struct radeon_device *rdev); +/* + * MMU Notifier + */ +int radeon_mn_register(struct radeon_bo *bo, unsigned long addr); +void radeon_mn_unregister(struct radeon_bo *bo); /* * Debugfs @@ -1740,6 +1782,7 @@ struct radeon_asic_ring { /* command emmit functions */ void (*ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib); void (*emit_fence)(struct radeon_device *rdev, struct radeon_fence *fence); + void (*hdp_flush)(struct radeon_device *rdev, struct radeon_ring *ring); bool (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp, struct radeon_semaphore *semaphore, bool emit_wait); void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); @@ -1763,13 +1806,8 @@ struct radeon_asic { int (*suspend)(struct radeon_device *rdev); void (*vga_set_state)(struct radeon_device *rdev, bool state); int (*asic_reset)(struct radeon_device *rdev); - /* ioctl hw specific callback. Some hw might want to perform special - * operation on specific ioctl. For instance on wait idle some hw - * might want to perform and HDP flush through MMIO as it seems that - * some R6XX/R7XX hw doesn't take HDP flush into account if programmed - * through ring. - */ - void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); + /* Flush the HDP cache via MMIO */ + void (*mmio_hdp_flush)(struct radeon_device *rdev); /* check if 3D engine is idle */ bool (*gui_idle)(struct radeon_device *rdev); /* wait for mc_idle */ @@ -1782,16 +1820,26 @@ struct radeon_asic { struct { void (*tlb_flush)(struct radeon_device *rdev); void (*set_page)(struct radeon_device *rdev, unsigned i, - uint64_t addr); + uint64_t addr, uint32_t flags); } gart; struct { int (*init)(struct radeon_device *rdev); void (*fini)(struct radeon_device *rdev); - void (*set_page)(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags); + void (*copy_pages)(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count); + void (*write_pages)(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); + void (*set_pages)(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); + void (*pad_ib)(struct radeon_ib *ib); } vm; /* ring specific callbacks */ struct radeon_asic_ring *ring[RADEON_NUM_RINGS]; @@ -1818,24 +1866,24 @@ struct radeon_asic { } display; /* copy functions for bo handling */ struct { - int (*blit)(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); + struct radeon_fence *(*blit)(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); u32 blit_ring_index; - int (*dma)(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); + struct radeon_fence *(*dma)(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); u32 dma_ring_index; /* method used for bo copy */ - int (*copy)(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); + struct radeon_fence *(*copy)(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); /* ring used for bo copies */ u32 copy_ring_index; } copy; @@ -2117,6 +2165,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int radeon_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, @@ -2273,6 +2323,7 @@ struct radeon_device { struct radeon_mman mman; struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; wait_queue_head_t fence_queue; + unsigned fence_context; struct mutex ring_lock; struct radeon_ring ring[RADEON_NUM_RINGS]; bool ib_pool_ready; @@ -2291,7 +2342,7 @@ struct radeon_device { bool need_dma32; bool accel_working; bool fastfb_working; /* IGP feature*/ - bool needs_reset; + bool needs_reset, in_reset; struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES]; const struct firmware *me_fw; /* all family ME firmware */ const struct firmware *pfp_fw; /* r6/700 PFP firmware */ @@ -2299,10 +2350,12 @@ struct radeon_device { const struct firmware *mc_fw; /* NI MC firmware */ const struct firmware *ce_fw; /* SI CE firmware */ const struct firmware *mec_fw; /* CIK MEC firmware */ + const struct firmware *mec2_fw; /* KV MEC2 firmware */ const struct firmware *sdma_fw; /* CIK SDMA firmware */ const struct firmware *smc_fw; /* SMC firmware */ const struct firmware *uvd_fw; /* UVD firmware */ const struct firmware *vce_fw; /* VCE firmware */ + bool new_fw; struct r600_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ struct r600_ih ih; /* r6/700 interrupt ring */ @@ -2310,7 +2363,6 @@ struct radeon_device { struct radeon_mec mec; struct work_struct hotplug_work; struct work_struct audio_work; - struct work_struct reset_work; int num_crtc; /* number of crtcs */ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ bool has_uvd; @@ -2342,6 +2394,14 @@ struct radeon_device { struct dev_pm_domain vga_pm_domain; bool have_disp_power_ref; + u32 px_quirk_flags; + + /* tracking pinned memory */ + u64 vram_pin_size; + u64 gart_pin_size; + + struct mutex mn_lock; + DECLARE_HASHTABLE(mn_hash, 7); }; bool radeon_is_px(struct drm_device *dev); @@ -2352,10 +2412,42 @@ int radeon_device_init(struct radeon_device *rdev, void radeon_device_fini(struct radeon_device *rdev); int radeon_gpu_wait_for_idle(struct radeon_device *rdev); -uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, - bool always_indirect); -void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, - bool always_indirect); +#define RADEON_MIN_MMIO_SIZE 0x10000 + +static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, + bool always_indirect) +{ + /* The mmio size is 64kb at minimum. Allows the if to be optimized out. */ + if ((reg < rdev->rmmio_size || reg < RADEON_MIN_MMIO_SIZE) && !always_indirect) + return readl(((void __iomem *)rdev->rmmio) + reg); + else { + unsigned long flags; + uint32_t ret; + + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); + writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); + ret = readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); + + return ret; + } +} + +static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, + bool always_indirect) +{ + if ((reg < rdev->rmmio_size || reg < RADEON_MIN_MMIO_SIZE) && !always_indirect) + writel(v, ((void __iomem *)rdev->rmmio) + reg); + else { + unsigned long flags; + + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); + writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); + writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); + } +} + u32 r100_io_rreg(struct radeon_device *rdev, u32 reg); void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); @@ -2365,7 +2457,17 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v); /* * Cast helper */ -#define to_radeon_fence(p) ((struct radeon_fence *)(p)) +extern const struct fence_ops radeon_fence_ops; + +static inline struct radeon_fence *to_radeon_fence(struct fence *f) +{ + struct radeon_fence *__f = container_of(f, struct radeon_fence, base); + + if (__f->base.ops == &radeon_fence_ops) + return __f; + + return NULL; +} /* * Registers read & write functions. @@ -2685,18 +2787,25 @@ void radeon_atombios_fini(struct radeon_device *rdev); /* * RING helpers. */ -#if DRM_DEBUG_CODE == 0 + +/** + * radeon_ring_write - write a value to the ring + * + * @ring: radeon_ring structure holding ring information + * @v: dword (dw) value to write + * + * Write a value to the requested ring buffer (all asics). + */ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) { + if (ring->count_dw <= 0) + DRM_ERROR("radeon: writing more dwords to the ring than expected!\n"); + ring->ring[ring->wptr++] = v; ring->wptr &= ring->ptr_mask; ring->count_dw--; ring->ring_free_dw--; } -#else -/* With debugging this is just too big to inline */ -void radeon_ring_write(struct radeon_ring *ring, uint32_t v); -#endif /* * ASICs macro. @@ -2709,10 +2818,13 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev)) -#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p)) +#define radeon_gart_set_page(rdev, i, p, f) (rdev)->asic->gart.set_page((rdev), (i), (p), (f)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) -#define radeon_asic_vm_set_page(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_page((rdev), (ib), (pe), (addr), (count), (incr), (flags))) +#define radeon_asic_vm_copy_pages(rdev, ib, pe, src, count) ((rdev)->asic->vm.copy_pages((rdev), (ib), (pe), (src), (count))) +#define radeon_asic_vm_write_pages(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.write_pages((rdev), (ib), (pe), (addr), (count), (incr), (flags))) +#define radeon_asic_vm_set_pages(rdev, ib, pe, addr, count, incr, flags) ((rdev)->asic->vm.set_pages((rdev), (ib), (pe), (addr), (count), (incr), (flags))) +#define radeon_asic_vm_pad_ib(rdev, ib) ((rdev)->asic->vm.pad_ib((ib))) #define radeon_ring_start(rdev, r, cp) (rdev)->asic->ring[(r)]->ring_start((rdev), (cp)) #define radeon_ring_test(rdev, r, cp) (rdev)->asic->ring[(r)]->ring_test((rdev), (cp)) #define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)]->ib_test((rdev), (cp)) @@ -2732,9 +2844,9 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_hdmi_setmode(rdev, e, m) (rdev)->asic->display.hdmi_setmode((e), (m)) #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)]->emit_fence((rdev), (fence)) #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)]->emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) -#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f)) -#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (f)) -#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (f)) +#define radeon_copy_blit(rdev, s, d, np, resv) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (resv)) +#define radeon_copy_dma(rdev, s, d, np, resv) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (resv)) +#define radeon_copy(rdev, s, d, np, resv) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (resv)) #define radeon_copy_blit_ring_index(rdev) (rdev)->asic->copy.blit_ring_index #define radeon_copy_dma_ring_index(rdev) (rdev)->asic->copy.dma_ring_index #define radeon_copy_ring_index(rdev) (rdev)->asic->copy.copy_ring_index @@ -2808,6 +2920,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain); extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo); +extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, + uint32_t flags); +extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm); +extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm); extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base); extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); @@ -2840,6 +2956,8 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev, struct radeon_vm *vm); int radeon_vm_clear_freed(struct radeon_device *rdev, struct radeon_vm *vm); +int radeon_vm_clear_invalids(struct radeon_device *rdev, + struct radeon_vm *vm); int radeon_vm_bo_update(struct radeon_device *rdev, struct radeon_bo_va *bo_va, struct ttm_mem_reg *mem); @@ -2863,10 +2981,10 @@ struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev); struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev); void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, - bool enable); + u8 enable_mask); void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, - bool enable); + u8 enable_mask); /* * R600 vram scratch functions diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 34b9aa9e3c06..850de57069be 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -194,7 +194,7 @@ static struct radeon_asic r100_asic = { .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &r100_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r100_mc_wait_for_idle, .gart = { @@ -260,7 +260,7 @@ static struct radeon_asic r200_asic = { .resume = &r100_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &r100_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r100_mc_wait_for_idle, .gart = { @@ -340,7 +340,7 @@ static struct radeon_asic r300_asic = { .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &r300_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { @@ -406,7 +406,7 @@ static struct radeon_asic r300_asic_pcie = { .resume = &r300_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &r300_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { @@ -472,7 +472,7 @@ static struct radeon_asic r420_asic = { .resume = &r420_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &r300_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { @@ -538,7 +538,7 @@ static struct radeon_asic rs400_asic = { .resume = &rs400_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &r300_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rs400_mc_wait_for_idle, .gart = { @@ -604,7 +604,7 @@ static struct radeon_asic rs600_asic = { .resume = &rs600_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &rs600_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rs600_mc_wait_for_idle, .gart = { @@ -672,7 +672,7 @@ static struct radeon_asic rs690_asic = { .resume = &rs690_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &rs600_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rs690_mc_wait_for_idle, .gart = { @@ -740,7 +740,7 @@ static struct radeon_asic rv515_asic = { .resume = &rv515_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &rs600_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rv515_mc_wait_for_idle, .gart = { @@ -806,7 +806,7 @@ static struct radeon_asic r520_asic = { .resume = &r520_resume, .vga_set_state = &r100_vga_set_state, .asic_reset = &rs600_asic_reset, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r520_mc_wait_for_idle, .gart = { @@ -898,7 +898,7 @@ static struct radeon_asic r600_asic = { .resume = &r600_resume, .vga_set_state = &r600_vga_set_state, .asic_reset = &r600_asic_reset, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &r600_get_xclk, @@ -963,6 +963,19 @@ static struct radeon_asic r600_asic = { }, }; +static struct radeon_asic_ring rv6xx_uvd_ring = { + .ib_execute = &uvd_v1_0_ib_execute, + .emit_fence = &uvd_v1_0_fence_emit, + .emit_semaphore = &uvd_v1_0_semaphore_emit, + .cs_parse = &radeon_uvd_cs_parse, + .ring_test = &uvd_v1_0_ring_test, + .ib_test = &uvd_v1_0_ib_test, + .is_lockup = &radeon_ring_test_lockup, + .get_rptr = &uvd_v1_0_get_rptr, + .get_wptr = &uvd_v1_0_get_wptr, + .set_wptr = &uvd_v1_0_set_wptr, +}; + static struct radeon_asic rv6xx_asic = { .init = &r600_init, .fini = &r600_fini, @@ -970,7 +983,7 @@ static struct radeon_asic rv6xx_asic = { .resume = &r600_resume, .vga_set_state = &r600_vga_set_state, .asic_reset = &r600_asic_reset, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &r600_get_xclk, @@ -982,6 +995,7 @@ static struct radeon_asic rv6xx_asic = { .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, + [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring, }, .irq = { .set = &r600_irq_set, @@ -1060,7 +1074,7 @@ static struct radeon_asic rs780_asic = { .resume = &r600_resume, .vga_set_state = &r600_vga_set_state, .asic_reset = &r600_asic_reset, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &r600_get_xclk, @@ -1072,6 +1086,7 @@ static struct radeon_asic rs780_asic = { .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, + [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring, }, .irq = { .set = &r600_irq_set, @@ -1163,7 +1178,7 @@ static struct radeon_asic rv770_asic = { .resume = &rv770_resume, .asic_reset = &r600_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, @@ -1281,7 +1296,7 @@ static struct radeon_asic evergreen_asic = { .resume = &evergreen_resume, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, @@ -1373,7 +1388,7 @@ static struct radeon_asic sumo_asic = { .resume = &evergreen_resume, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &r600_get_xclk, @@ -1464,7 +1479,7 @@ static struct radeon_asic btc_asic = { .resume = &evergreen_resume, .asic_reset = &evergreen_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, @@ -1599,7 +1614,7 @@ static struct radeon_asic cayman_asic = { .resume = &cayman_resume, .asic_reset = &cayman_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, @@ -1611,7 +1626,10 @@ static struct radeon_asic cayman_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .set_page = &cayman_dma_vm_set_page, + .copy_pages = &cayman_dma_vm_copy_pages, + .write_pages = &cayman_dma_vm_write_pages, + .set_pages = &cayman_dma_vm_set_pages, + .pad_ib = &cayman_dma_vm_pad_ib, }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &cayman_gfx_ring, @@ -1699,7 +1717,7 @@ static struct radeon_asic trinity_asic = { .resume = &cayman_resume, .asic_reset = &cayman_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &r600_get_xclk, @@ -1711,7 +1729,10 @@ static struct radeon_asic trinity_asic = { .vm = { .init = &cayman_vm_init, .fini = &cayman_vm_fini, - .set_page = &cayman_dma_vm_set_page, + .copy_pages = &cayman_dma_vm_copy_pages, + .write_pages = &cayman_dma_vm_write_pages, + .set_pages = &cayman_dma_vm_set_pages, + .pad_ib = &cayman_dma_vm_pad_ib, }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &cayman_gfx_ring, @@ -1829,7 +1850,7 @@ static struct radeon_asic si_asic = { .resume = &si_resume, .asic_reset = &si_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = r600_ioctl_wait_idle, + .mmio_hdp_flush = r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &si_get_xclk, @@ -1841,7 +1862,10 @@ static struct radeon_asic si_asic = { .vm = { .init = &si_vm_init, .fini = &si_vm_fini, - .set_page = &si_dma_vm_set_page, + .copy_pages = &si_dma_vm_copy_pages, + .write_pages = &si_dma_vm_write_pages, + .set_pages = &si_dma_vm_set_pages, + .pad_ib = &cayman_dma_vm_pad_ib, }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &si_gfx_ring, @@ -1987,7 +2011,7 @@ static struct radeon_asic ci_asic = { .resume = &cik_resume, .asic_reset = &cik_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = &r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &cik_get_xclk, @@ -1999,7 +2023,10 @@ static struct radeon_asic ci_asic = { .vm = { .init = &cik_vm_init, .fini = &cik_vm_fini, - .set_page = &cik_sdma_vm_set_page, + .copy_pages = &cik_sdma_vm_copy_pages, + .write_pages = &cik_sdma_vm_write_pages, + .set_pages = &cik_sdma_vm_set_pages, + .pad_ib = &cik_sdma_vm_pad_ib, }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &ci_gfx_ring, @@ -2091,7 +2118,7 @@ static struct radeon_asic kv_asic = { .resume = &cik_resume, .asic_reset = &cik_asic_reset, .vga_set_state = &r600_vga_set_state, - .ioctl_wait_idle = NULL, + .mmio_hdp_flush = &r600_mmio_hdp_flush, .gui_idle = &r600_gui_idle, .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &cik_get_xclk, @@ -2103,7 +2130,10 @@ static struct radeon_asic kv_asic = { .vm = { .init = &cik_vm_init, .fini = &cik_vm_fini, - .set_page = &cik_sdma_vm_set_page, + .copy_pages = &cik_sdma_vm_copy_pages, + .write_pages = &cik_sdma_vm_write_pages, + .set_pages = &cik_sdma_vm_set_pages, + .pad_ib = &cik_sdma_vm_pad_ib, }, .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &ci_gfx_ring, @@ -2281,7 +2311,15 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_RS780: case CHIP_RS880: rdev->asic = &rs780_asic; - rdev->has_uvd = true; + /* 760G/780V/880V don't have UVD */ + if ((rdev->pdev->device == 0x9616)|| + (rdev->pdev->device == 0x9611)|| + (rdev->pdev->device == 0x9613)|| + (rdev->pdev->device == 0x9711)|| + (rdev->pdev->device == 0x9713)) + rdev->has_uvd = false; + else + rdev->has_uvd = true; break; case CHIP_RV770: case CHIP_RV730: @@ -2457,7 +2495,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - RADEON_CG_SUPPORT_GFX_CGCG | + /*RADEON_CG_SUPPORT_GFX_CGCG |*/ RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CGTS_LS | @@ -2476,7 +2514,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - RADEON_CG_SUPPORT_GFX_CGCG | + /*RADEON_CG_SUPPORT_GFX_CGCG |*/ RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CP_LS | @@ -2502,7 +2540,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - RADEON_CG_SUPPORT_GFX_CGCG | + /*RADEON_CG_SUPPORT_GFX_CGCG |*/ RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CGTS_LS | @@ -2530,7 +2568,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - RADEON_CG_SUPPORT_GFX_CGCG | + /*RADEON_CG_SUPPORT_GFX_CGCG |*/ RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CGTS_LS | diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 01e7c0ad8f01..d8ace5b28a5b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -68,7 +68,7 @@ int r100_asic_reset(struct radeon_device *rdev); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); void r100_pci_gart_tlb_flush(struct radeon_device *rdev); void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr); + uint64_t addr, uint32_t flags); void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring); int r100_irq_set(struct radeon_device *rdev); int r100_irq_process(struct radeon_device *rdev); @@ -81,11 +81,11 @@ bool r100_semaphore_ring_emit(struct radeon_device *rdev, int r100_cs_parse(struct radeon_cs_parser *p); void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg); -int r100_copy_blit(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); +struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); int r100_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); @@ -152,11 +152,11 @@ void r100_gfx_set_wptr(struct radeon_device *rdev, /* * r200,rv250,rs300,rv280 */ -extern int r200_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); +struct radeon_fence *r200_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); void r200_set_safe_registers(struct radeon_device *rdev); /* @@ -173,7 +173,7 @@ extern void r300_fence_ring_emit(struct radeon_device *rdev, extern int r300_cs_parse(struct radeon_cs_parser *p); extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr); + uint64_t addr, uint32_t flags); extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int rv370_get_pcie_lanes(struct radeon_device *rdev); extern void r300_set_reg_safe(struct radeon_device *rdev); @@ -209,7 +209,7 @@ extern int rs400_suspend(struct radeon_device *rdev); extern int rs400_resume(struct radeon_device *rdev); void rs400_gart_tlb_flush(struct radeon_device *rdev); void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr); + uint64_t addr, uint32_t flags); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); int rs400_gart_init(struct radeon_device *rdev); @@ -233,7 +233,7 @@ void rs600_irq_disable(struct radeon_device *rdev); u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc); void rs600_gart_tlb_flush(struct radeon_device *rdev); void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr); + uint64_t addr, uint32_t flags); uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs600_bandwidth_update(struct radeon_device *rdev); @@ -340,18 +340,20 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); -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); +struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); +struct radeon_fence *r600_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); void r600_hpd_init(struct radeon_device *rdev); void r600_hpd_fini(struct radeon_device *rdev); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); void r600_hpd_set_polarity(struct radeon_device *rdev, enum radeon_hpd_id hpd); -extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); +extern void r600_mmio_hdp_flush(struct radeon_device *rdev); extern bool r600_gui_idle(struct radeon_device *rdev); extern void r600_pm_misc(struct radeon_device *rdev); extern void r600_pm_init_profile(struct radeon_device *rdev); @@ -389,7 +391,6 @@ void r600_disable_interrupts(struct radeon_device *rdev); void r600_rlc_stop(struct radeon_device *rdev); /* r600 audio */ int r600_audio_init(struct radeon_device *rdev); -struct r600_audio_pin r600_audio_status(struct radeon_device *rdev); void r600_audio_fini(struct radeon_device *rdev); void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock); void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, @@ -461,10 +462,10 @@ bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc); void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); void r700_cp_stop(struct radeon_device *rdev); void r700_cp_fini(struct radeon_device *rdev); -int rv770_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); +struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); u32 rv770_get_xclk(struct radeon_device *rdev); int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int rv770_get_temp(struct radeon_device *rdev); @@ -535,10 +536,10 @@ void evergreen_dma_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); -int evergreen_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); +struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable); void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); int evergreen_get_temp(struct radeon_device *rdev); @@ -606,11 +607,22 @@ void cayman_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); -void cayman_dma_vm_set_page(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags); + +void cayman_dma_vm_copy_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count); +void cayman_dma_vm_write_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); +void cayman_dma_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); +void cayman_dma_vm_pad_ib(struct radeon_ib *ib); void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); @@ -689,15 +701,26 @@ int si_vm_init(struct radeon_device *rdev); void si_vm_fini(struct radeon_device *rdev); void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); -int si_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); -void si_dma_vm_set_page(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags); +struct radeon_fence *si_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); + +void si_dma_vm_copy_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count); +void si_dma_vm_write_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); +void si_dma_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); + void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); u32 si_get_xclk(struct radeon_device *rdev); uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev); @@ -737,14 +760,14 @@ bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_semaphore *semaphore, bool emit_wait); void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); -int cik_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); -int cik_copy_cpdma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence); +struct radeon_fence *cik_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); +struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv); int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); @@ -771,11 +794,23 @@ int cik_irq_process(struct radeon_device *rdev); int cik_vm_init(struct radeon_device *rdev); void cik_vm_fini(struct radeon_device *rdev); void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); -void cik_sdma_vm_set_page(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags); + +void cik_sdma_vm_copy_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count); +void cik_sdma_vm_write_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); +void cik_sdma_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags); +void cik_sdma_vm_pad_ib(struct radeon_ib *ib); + void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); u32 cik_gfx_get_rptr(struct radeon_device *rdev, @@ -848,6 +883,7 @@ uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev, struct radeon_ring *ring); void uvd_v1_0_set_wptr(struct radeon_device *rdev, struct radeon_ring *ring); +int uvd_v1_0_resume(struct radeon_device *rdev); int uvd_v1_0_init(struct radeon_device *rdev); void uvd_v1_0_fini(struct radeon_device *rdev); @@ -855,6 +891,8 @@ int uvd_v1_0_start(struct radeon_device *rdev); void uvd_v1_0_stop(struct radeon_device *rdev); int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); +void uvd_v1_0_fence_emit(struct radeon_device *rdev, + struct radeon_fence *fence); int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, struct radeon_ring *ring, diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 173f378428a9..df69b92ba164 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -447,11 +447,18 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } + /* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */ + if ((dev->pdev->device == 0x9805) && + (dev->pdev->subsystem_vendor == 0x1734) && + (dev->pdev->subsystem_device == 0x11bd)) { + if (*connector_type == DRM_MODE_CONNECTOR_VGA) + return false; + } return true; } -const int supported_devices_connector_convert[] = { +static const int supported_devices_connector_convert[] = { DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTOR_DVII, @@ -470,7 +477,7 @@ const int supported_devices_connector_convert[] = { DRM_MODE_CONNECTOR_DisplayPort }; -const uint16_t supported_devices_connector_object_id_convert[] = { +static const uint16_t supported_devices_connector_object_id_convert[] = { CONNECTOR_OBJECT_ID_NONE, CONNECTOR_OBJECT_ID_VGA, CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */ @@ -487,7 +494,7 @@ const uint16_t supported_devices_connector_object_id_convert[] = { CONNECTOR_OBJECT_ID_SVIDEO }; -const int object_connector_convert[] = { +static const int object_connector_convert[] = { DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_DVII, DRM_MODE_CONNECTOR_DVII, @@ -1963,7 +1970,7 @@ static const char *thermal_controller_names[] = { "adm1032", "adm1030", "max6649", - "lm64", + "lm63", /* lm64 */ "f75375", "asc7xxx", }; @@ -1974,7 +1981,7 @@ static const char *pp_lib_thermal_controller_names[] = { "adm1032", "adm1030", "max6649", - "lm64", + "lm63", /* lm64 */ "f75375", "RV6xx", "RV770", @@ -2281,19 +2288,31 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); rdev->pm.int_thermal_type = THERMAL_TYPE_KV; - } else if ((controller->ucType == - ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || - (controller->ucType == - ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) || - (controller->ucType == - ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { - DRM_INFO("Special thermal controller config\n"); + } else if (controller->ucType == + ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) { + DRM_INFO("External GPIO thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO; + } else if (controller->ucType == + ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) { + DRM_INFO("ADT7473 with internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL; + } else if (controller->ucType == + ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) { + DRM_INFO("EMC2103 with internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL; } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", pp_lib_thermal_controller_names[controller->ucType], controller->ucI2cAddress >> 1, (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL; i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); if (rdev->pm.i2c_bus) { @@ -3236,6 +3255,41 @@ int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *r return 0; } +union get_voltage_info { + struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in; + struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out; +}; + +int radeon_atom_get_voltage_evv(struct radeon_device *rdev, + u16 virtual_voltage_id, + u16 *voltage) +{ + int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo); + u32 entry_id; + u32 count = rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; + union get_voltage_info args; + + for (entry_id = 0; entry_id < count; entry_id++) { + if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v == + virtual_voltage_id) + break; + } + + if (entry_id >= count) + return -EINVAL; + + args.in.ucVoltageType = VOLTAGE_TYPE_VDDC; + args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; + args.in.ulSCLKFreq = + cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + *voltage = le16_to_cpu(args.evv_out.usVoltageLevel); + + return 0; +} + int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type, u32 *gpio_value, u32 *gpio_mask) @@ -3397,6 +3451,50 @@ radeon_atom_is_voltage_gpio(struct radeon_device *rdev, return false; } +int radeon_atom_get_svi2_info(struct radeon_device *rdev, + u8 voltage_type, + u8 *svd_gpio_id, u8 *svc_gpio_id) +{ + int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); + u8 frev, crev; + u16 data_offset, size; + union voltage_object_info *voltage_info; + union voltage_object *voltage_object = NULL; + + if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, + &frev, &crev, &data_offset)) { + voltage_info = (union voltage_object_info *) + (rdev->mode_info.atom_context->bios + data_offset); + + switch (frev) { + case 3: + switch (crev) { + case 1: + voltage_object = (union voltage_object *) + atom_lookup_voltage_object_v3(&voltage_info->v3, + voltage_type, + VOLTAGE_OBJ_SVID2); + if (voltage_object) { + *svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId; + *svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId; + } else { + return -EINVAL; + } + break; + default: + DRM_ERROR("unknown voltage object table\n"); + return -EINVAL; + } + break; + default: + DRM_ERROR("unknown voltage object table\n"); + return -EINVAL; + } + + } + return 0; +} + int radeon_atom_get_max_voltage(struct radeon_device *rdev, u8 voltage_type, u16 *max_voltage) { diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index a9fb0d016d38..8bc7d0bbd3c8 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -33,7 +33,6 @@ static struct radeon_atpx_priv { bool atpx_detected; /* handle for device - and atpx */ acpi_handle dhandle; - acpi_handle other_handle; struct radeon_atpx atpx; } radeon_atpx_priv; @@ -453,10 +452,9 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) return false; status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); - if (ACPI_FAILURE(status)) { - radeon_atpx_priv.other_handle = dhandle; + if (ACPI_FAILURE(status)) return false; - } + radeon_atpx_priv.dhandle = dhandle; radeon_atpx_priv.atpx.handle = atpx_handle; return true; @@ -540,16 +538,6 @@ static bool radeon_atpx_detect(void) printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", acpi_method_name); radeon_atpx_priv.atpx_detected = true; - /* - * On some systems hotplug events are generated for the device - * being switched off when ATPX is executed. They cause ACPI - * hotplug to trigger and attempt to remove the device from - * the system, which causes it to break down. Prevent that from - * happening by setting the no_hotplug flag for the involved - * ACPI device objects. - */ - acpi_bus_no_hotplug(radeon_atpx_priv.dhandle); - acpi_bus_no_hotplug(radeon_atpx_priv.other_handle); return true; } return false; diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 6e05a2e75a46..9e7f23dd14bd 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -45,33 +45,29 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size, for (i = 0; i < n; i++) { switch (flag) { case RADEON_BENCHMARK_COPY_DMA: - r = radeon_copy_dma(rdev, saddr, daddr, - size / RADEON_GPU_PAGE_SIZE, - &fence); + fence = radeon_copy_dma(rdev, saddr, daddr, + size / RADEON_GPU_PAGE_SIZE, + NULL); break; case RADEON_BENCHMARK_COPY_BLIT: - r = radeon_copy_blit(rdev, saddr, daddr, - size / RADEON_GPU_PAGE_SIZE, - &fence); + fence = radeon_copy_blit(rdev, saddr, daddr, + size / RADEON_GPU_PAGE_SIZE, + NULL); break; default: DRM_ERROR("Unknown copy method\n"); - r = -EINVAL; + return -EINVAL; } - if (r) - goto exit_do_move; + if (IS_ERR(fence)) + return PTR_ERR(fence); + r = radeon_fence_wait(fence, false); - if (r) - goto exit_do_move; radeon_fence_unref(&fence); + if (r) + return r; } end_jiffies = jiffies; - r = jiffies_to_msecs(end_jiffies - start_jiffies); - -exit_do_move: - if (fence) - radeon_fence_unref(&fence); - return r; + return jiffies_to_msecs(end_jiffies - start_jiffies); } @@ -97,7 +93,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, int time; n = RADEON_BENCHMARK_ITERATIONS; - r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, NULL, &sobj); + r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, 0, NULL, NULL, &sobj); if (r) { goto out_cleanup; } @@ -109,7 +105,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, if (r) { goto out_cleanup; } - r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, NULL, &dobj); + r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, 0, NULL, NULL, &dobj); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 6a03624fadaa..63ccb8fa799c 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -658,12 +658,10 @@ bool radeon_get_bios(struct radeon_device *rdev) r = igp_read_bios_from_vram(rdev); if (r == false) r = radeon_read_bios(rdev); - if (r == false) { + if (r == false) r = radeon_read_disabled_bios(rdev); - } - if (r == false) { + if (r == false) r = radeon_read_platform_bios(rdev); - } if (r == false || rdev->bios == NULL) { DRM_ERROR("Unable to locate a BIOS ROM\n"); rdev->bios = NULL; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 6651177110f0..3e5f6b71f3ad 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -116,7 +116,7 @@ enum radeon_combios_connector { CONNECTOR_UNSUPPORTED_LEGACY }; -const int legacy_connector_convert[] = { +static const int legacy_connector_convert[] = { DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_DVID, DRM_MODE_CONNECTOR_VGA, diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 44831197e82e..300c4b3d4669 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -107,7 +107,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: if (radeon_connector->use_digital) { - if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { if (connector->display_info.bpc) bpc = connector->display_info.bpc; } @@ -115,7 +115,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) break; case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_HDMIA: - if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { if (connector->display_info.bpc) bpc = connector->display_info.bpc; } @@ -124,7 +124,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) dig_connector = radeon_connector->con_priv; if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) || - drm_detect_hdmi_monitor(radeon_connector->edid)) { + drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { if (connector->display_info.bpc) bpc = connector->display_info.bpc; } @@ -148,7 +148,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) break; } - if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { /* hdmi deep color only implemented on DCE4+ */ if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) { DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n", @@ -197,10 +197,19 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) connector->name, bpc); } } + else if (bpc > 8) { + /* max_tmds_clock missing, but hdmi spec mandates it for deep color. */ + DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n", + connector->name); + bpc = 8; + } } - if ((radeon_deep_color == 0) && (bpc > 8)) + if ((radeon_deep_color == 0) && (bpc > 8)) { + DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n", + connector->name); bpc = 8; + } DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n", connector->name, connector->display_info.bpc, bpc); @@ -216,7 +225,6 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c struct drm_encoder *best_encoder = NULL; struct drm_encoder *encoder = NULL; struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; - struct drm_mode_object *obj; bool connected; int i; @@ -226,14 +234,11 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c if (connector->encoder_ids[i] == 0) break; - obj = drm_mode_object_find(connector->dev, - connector->encoder_ids[i], - DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(connector->dev, + connector->encoder_ids[i]); + if (!encoder) continue; - encoder = obj_to_encoder(obj); - if ((encoder == best_encoder) && (status == connector_status_connected)) connected = true; else @@ -249,7 +254,6 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) { - struct drm_mode_object *obj; struct drm_encoder *encoder; int i; @@ -257,34 +261,134 @@ static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, if (connector->encoder_ids[i] == 0) break; - obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); + if (!encoder) continue; - encoder = obj_to_encoder(obj); if (encoder->encoder_type == encoder_type) return encoder; } return NULL; } +struct edid *radeon_connector_edid(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_property_blob *edid_blob = connector->edid_blob_ptr; + + if (radeon_connector->edid) { + return radeon_connector->edid; + } else if (edid_blob) { + struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); + if (edid) + radeon_connector->edid = edid; + } + return radeon_connector->edid; +} + +static void radeon_connector_get_edid(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_connector->edid) + return; + + /* on hw with routers, select right port */ + if (radeon_connector->router.ddc_valid) + radeon_router_select_ddc_port(radeon_connector); + + if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != + ENCODER_OBJECT_ID_NONE) && + radeon_connector->ddc_bus->has_aux) { + radeon_connector->edid = drm_get_edid(connector, + &radeon_connector->ddc_bus->aux.ddc); + } else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; + + if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || + dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && + radeon_connector->ddc_bus->has_aux) + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &radeon_connector->ddc_bus->aux.ddc); + else if (radeon_connector->ddc_bus) + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &radeon_connector->ddc_bus->adapter); + } else if (radeon_connector->ddc_bus) { + radeon_connector->edid = drm_get_edid(&radeon_connector->base, + &radeon_connector->ddc_bus->adapter); + } + + if (!radeon_connector->edid) { + if (rdev->is_atom_bios) { + /* some laptops provide a hardcoded edid in rom for LCDs */ + if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || + (connector->connector_type == DRM_MODE_CONNECTOR_eDP))) + radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); + } else { + /* some servers provide a hardcoded edid in rom for KVMs */ + radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); + } + } +} + +static void radeon_connector_free_edid(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_connector->edid) { + kfree(radeon_connector->edid); + radeon_connector->edid = NULL; + } +} + +static int radeon_ddc_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret; + + if (radeon_connector->edid) { + drm_mode_connector_update_edid_property(connector, radeon_connector->edid); + ret = drm_add_edid_modes(connector, radeon_connector->edid); + drm_edid_to_eld(connector, radeon_connector->edid); + return ret; + } + drm_mode_connector_update_edid_property(connector, NULL); + return 0; +} + static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; - struct drm_mode_object *obj; - struct drm_encoder *encoder; - /* pick the encoder ids */ - if (enc_id) { - obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); - if (!obj) - return NULL; - encoder = obj_to_encoder(obj); - return encoder; - } + if (enc_id) + return drm_encoder_find(connector->dev, enc_id); return NULL; } +static void radeon_get_native_mode(struct drm_connector *connector) +{ + struct drm_encoder *encoder = radeon_best_single_encoder(connector); + struct radeon_encoder *radeon_encoder; + + if (encoder == NULL) + return; + + radeon_encoder = to_radeon_encoder(encoder); + + if (!list_empty(&connector->probed_modes)) { + struct drm_display_mode *preferred_mode = + list_first_entry(&connector->probed_modes, + struct drm_display_mode, head); + + radeon_encoder->native_mode = *preferred_mode; + } else { + radeon_encoder->native_mode.clock = 0; + } +} + /* * radeon_connector_analog_encoder_conflict_solve * - search for other connectors sharing this encoder @@ -585,6 +689,35 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct radeon_property_change_mode(&radeon_encoder->base); } + if (property == dev->mode_config.scaling_mode_property) { + enum radeon_rmx_type rmx_type; + + if (connector->encoder) + radeon_encoder = to_radeon_encoder(connector->encoder); + else { + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); + } + + switch (val) { + default: + case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; + case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; + case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; + case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; + } + if (radeon_encoder->rmx_type == rmx_type) + return 0; + + if ((rmx_type != DRM_MODE_SCALE_NONE) && + (radeon_encoder->native_mode.clock == 0)) + return 0; + + radeon_encoder->rmx_type = rmx_type; + + radeon_property_change_mode(&radeon_encoder->base); + } + return 0; } @@ -625,22 +758,20 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, static int radeon_lvds_get_modes(struct drm_connector *connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; int ret = 0; struct drm_display_mode *mode; - if (radeon_connector->ddc_bus) { - ret = radeon_ddc_get_modes(radeon_connector); - if (ret > 0) { - encoder = radeon_best_single_encoder(connector); - if (encoder) { - radeon_fixup_lvds_native_mode(encoder, connector); - /* add scaled modes */ - radeon_add_common_modes(encoder, connector); - } - return ret; + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); + if (ret > 0) { + encoder = radeon_best_single_encoder(connector); + if (encoder) { + radeon_fixup_lvds_native_mode(encoder, connector); + /* add scaled modes */ + radeon_add_common_modes(encoder, connector); } + return ret; } encoder = radeon_best_single_encoder(connector); @@ -715,16 +846,9 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) } /* check for edid as well */ + radeon_connector_get_edid(connector); if (radeon_connector->edid) ret = connector_status_connected; - else { - if (radeon_connector->ddc_bus) { - radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &radeon_connector->ddc_bus->adapter); - if (radeon_connector->edid) - ret = connector_status_connected; - } - } /* check acpi lid status ??? */ radeon_connector_update_scratch_regs(connector, ret); @@ -737,10 +861,9 @@ static void radeon_connector_destroy(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - if (radeon_connector->edid) - kfree(radeon_connector->edid); + radeon_connector_free_edid(connector); kfree(radeon_connector->con_priv); - drm_sysfs_connector_remove(connector); + drm_connector_unregister(connector); drm_connector_cleanup(connector); kfree(connector); } @@ -797,10 +920,12 @@ static const struct drm_connector_funcs radeon_lvds_connector_funcs = { static int radeon_vga_get_modes(struct drm_connector *connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); int ret; - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); + + radeon_get_native_mode(connector); return ret; } @@ -843,28 +968,26 @@ radeon_vga_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; - if (radeon_connector->edid) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; - } - radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_connector_free_edid(connector); + radeon_connector_get_edid(connector); if (!radeon_connector->edid) { DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", connector->name); ret = connector_status_connected; } else { - radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); + radeon_connector->use_digital = + !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); /* some oems have boards with separate digital and analog connectors * with a shared ddc line (often vga + hdmi) */ if (radeon_connector->use_digital && radeon_connector->shared_ddc) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; + radeon_connector_free_edid(connector); ret = connector_status_disconnected; - } else + } else { ret = connector_status_connected; + } } } else { @@ -999,15 +1122,6 @@ static const struct drm_connector_funcs radeon_tv_connector_funcs = { .set_property = radeon_connector_set_property, }; -static int radeon_dvi_get_modes(struct drm_connector *connector) -{ - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - int ret; - - ret = radeon_ddc_get_modes(radeon_connector); - return ret; -} - static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -1048,7 +1162,6 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = NULL; struct drm_encoder_helper_funcs *encoder_funcs; - struct drm_mode_object *obj; int i, r; enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; @@ -1066,18 +1179,16 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; - if (radeon_connector->edid) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; - } - radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_connector_free_edid(connector); + radeon_connector_get_edid(connector); if (!radeon_connector->edid) { DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", connector->name); /* rs690 seems to have a problem with connectors not existing and always * return a block of 0's. If we see this just stop polling on this output */ - if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && radeon_connector->base.null_edid_counter) { + if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && + radeon_connector->base.null_edid_counter) { ret = connector_status_disconnected; DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", connector->name); @@ -1087,18 +1198,18 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) broken_edid = true; /* defer use_digital to later */ } } else { - radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); + radeon_connector->use_digital = + !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); /* some oems have boards with separate digital and analog connectors * with a shared ddc line (often vga + hdmi) */ if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; + radeon_connector_free_edid(connector); ret = connector_status_disconnected; - } else + } else { ret = connector_status_connected; - + } /* This gets complicated. We have boards with VGA + HDMI with a * shared DDC line and we have boards with DVI-D + HDMI with a shared * DDC line. The latter is more complex because with DVI<->HDMI adapters @@ -1118,8 +1229,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { /* hpd is our only option in this case */ if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; + radeon_connector_free_edid(connector); ret = connector_status_disconnected; } } @@ -1153,14 +1263,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if (connector->encoder_ids[i] == 0) break; - obj = drm_mode_object_find(connector->dev, - connector->encoder_ids[i], - DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(connector->dev, + connector->encoder_ids[i]); + if (!encoder) continue; - encoder = obj_to_encoder(obj); - if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) continue; @@ -1225,19 +1332,16 @@ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_mode_object *obj; struct drm_encoder *encoder; int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) break; - obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); + if (!encoder) continue; - encoder = obj_to_encoder(obj); - if (radeon_connector->use_digital == true) { if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) return encoder; @@ -1252,13 +1356,8 @@ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) /* then check use digitial */ /* pick the first one */ - if (enc_id) { - obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); - if (!obj) - return NULL; - encoder = obj_to_encoder(obj); - return encoder; - } + if (enc_id) + return drm_encoder_find(connector->dev, enc_id); return NULL; } @@ -1291,7 +1390,7 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector, (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) return MODE_OK; - else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { + else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { /* HDMI 1.3+ supports max clock of 340 Mhz */ if (mode->clock > 340000) return MODE_CLOCK_HIGH; @@ -1310,7 +1409,7 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector, } static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { - .get_modes = radeon_dvi_get_modes, + .get_modes = radeon_vga_get_modes, .mode_valid = radeon_dvi_mode_valid, .best_encoder = radeon_dvi_encoder, }; @@ -1339,7 +1438,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_ON); - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); @@ -1350,7 +1450,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); } - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); } if (ret > 0) { @@ -1383,7 +1484,10 @@ static int radeon_dp_get_modes(struct drm_connector *connector) if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); } - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); + + radeon_get_native_mode(connector); } return ret; @@ -1391,7 +1495,6 @@ static int radeon_dp_get_modes(struct drm_connector *connector) u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) { - struct drm_mode_object *obj; struct drm_encoder *encoder; struct radeon_encoder *radeon_encoder; int i; @@ -1400,11 +1503,10 @@ u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn if (connector->encoder_ids[i] == 0) break; - obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); + if (!encoder) continue; - encoder = obj_to_encoder(obj); radeon_encoder = to_radeon_encoder(encoder); switch (radeon_encoder->encoder_id) { @@ -1419,9 +1521,8 @@ u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn return ENCODER_OBJECT_ID_NONE; } -bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) +static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) { - struct drm_mode_object *obj; struct drm_encoder *encoder; struct radeon_encoder *radeon_encoder; int i; @@ -1431,11 +1532,10 @@ bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) if (connector->encoder_ids[i] == 0) break; - obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); - if (!obj) + encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); + if (!encoder) continue; - encoder = obj_to_encoder(obj); radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) found = true; @@ -1478,10 +1578,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) goto out; } - if (radeon_connector->edid) { - kfree(radeon_connector->edid); - radeon_connector->edid = NULL; - } + radeon_connector_free_edid(connector); if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { @@ -1587,7 +1684,7 @@ static int radeon_dp_mode_valid(struct drm_connector *connector, (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { return radeon_dp_mode_valid_helper(connector, mode); } else { - if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { /* HDMI 1.3+ supports max clock of 340 Mhz */ if (mode->clock > 340000) return MODE_CLOCK_HIGH; @@ -1747,6 +1844,9 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); + drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1768,6 +1868,10 @@ radeon_add_atom_connector(struct drm_device *dev, 0); drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); + + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.dither_property, RADEON_FMT_DITHER_DISABLE); @@ -1817,6 +1921,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); + if (ASIC_IS_AVIVO(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; @@ -1835,6 +1943,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); + if (ASIC_IS_AVIVO(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->interlace_allowed = true; @@ -1868,17 +1980,18 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.dither_property, + RADEON_FMT_DITHER_DISABLE); + drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); } if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); } - if (ASIC_IS_AVIVO(rdev)) { - drm_object_attach_property(&radeon_connector->base.base, - rdev->mode_info.dither_property, - RADEON_FMT_DITHER_DISABLE); - } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; drm_object_attach_property(&radeon_connector->base.base, @@ -1918,17 +2031,18 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.dither_property, + RADEON_FMT_DITHER_DISABLE); + drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); } if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); } - if (ASIC_IS_AVIVO(rdev)) { - drm_object_attach_property(&radeon_connector->base.base, - rdev->mode_info.dither_property, - RADEON_FMT_DITHER_DISABLE); - } subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = true; if (connector_type == DRM_MODE_CONNECTOR_HDMIB) @@ -1965,18 +2079,18 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.dither_property, + RADEON_FMT_DITHER_DISABLE); + drm_object_attach_property(&radeon_connector->base.base, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); } if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); } - if (ASIC_IS_AVIVO(rdev)) { - drm_object_attach_property(&radeon_connector->base.base, - rdev->mode_info.dither_property, - RADEON_FMT_DITHER_DISABLE); - - } connector->interlace_allowed = true; /* in theory with a DP to VGA converter... */ connector->doublescan_allowed = false; @@ -2050,7 +2164,7 @@ radeon_add_atom_connector(struct drm_device *dev, connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; - drm_sysfs_connector_add(connector); + drm_connector_register(connector); if (has_aux) radeon_dp_aux_init(radeon_connector); @@ -2211,5 +2325,5 @@ radeon_add_legacy_connector(struct drm_device *dev, } else connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; - drm_sysfs_connector_add(connector); + drm_connector_register(connector); } diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index bb0d5c3a8311..ea134a7d51a5 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -1298,27 +1298,27 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->buffers_offset = init->buffers_offset; dev_priv->gart_textures_offset = init->gart_textures_offset; - master_priv->sarea = drm_getsarea(dev); + master_priv->sarea = drm_legacy_getsarea(dev); if (!master_priv->sarea) { DRM_ERROR("could not find sarea!\n"); radeon_do_cleanup_cp(dev); return -EINVAL; } - dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset); + dev_priv->cp_ring = drm_legacy_findmap(dev, init->ring_offset); if (!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); radeon_do_cleanup_cp(dev); return -EINVAL; } - dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); + dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset); if (!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); radeon_do_cleanup_cp(dev); return -EINVAL; } dev->agp_buffer_token = init->buffers_offset; - dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); + dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); radeon_do_cleanup_cp(dev); @@ -1327,7 +1327,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, if (init->gart_textures_offset) { dev_priv->gart_textures = - drm_core_findmap(dev, init->gart_textures_offset); + drm_legacy_findmap(dev, init->gart_textures_offset); if (!dev_priv->gart_textures) { DRM_ERROR("could not find GART texture region!\n"); radeon_do_cleanup_cp(dev); @@ -1337,9 +1337,9 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { - drm_core_ioremap_wc(dev_priv->cp_ring, dev); - drm_core_ioremap_wc(dev_priv->ring_rptr, dev); - drm_core_ioremap_wc(dev->agp_buffer_map, dev); + drm_legacy_ioremap_wc(dev_priv->cp_ring, dev); + drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev); + drm_legacy_ioremap_wc(dev->agp_buffer_map, dev); if (!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev->agp_buffer_map->handle) { @@ -1475,7 +1475,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->gart_info.mapping.size = dev_priv->gart_info.table_size; - drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev); + drm_legacy_ioremap_wc(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = dev_priv->gart_info.mapping.handle; @@ -1569,15 +1569,15 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { if (dev_priv->cp_ring != NULL) { - drm_core_ioremapfree(dev_priv->cp_ring, dev); + drm_legacy_ioremapfree(dev_priv->cp_ring, dev); dev_priv->cp_ring = NULL; } if (dev_priv->ring_rptr != NULL) { - drm_core_ioremapfree(dev_priv->ring_rptr, dev); + drm_legacy_ioremapfree(dev_priv->ring_rptr, dev); dev_priv->ring_rptr = NULL; } if (dev->agp_buffer_map != NULL) { - drm_core_ioremapfree(dev->agp_buffer_map, dev); + drm_legacy_ioremapfree(dev->agp_buffer_map, dev); dev->agp_buffer_map = NULL; } } else @@ -1597,7 +1597,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { - drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); + drm_legacy_ioremapfree(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = NULL; } } @@ -2106,9 +2106,9 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) else dev_priv->flags |= RADEON_IS_PCI; - ret = drm_addmap(dev, pci_resource_start(dev->pdev, 2), - pci_resource_len(dev->pdev, 2), _DRM_REGISTERS, - _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio); + ret = drm_legacy_addmap(dev, pci_resource_start(dev->pdev, 2), + pci_resource_len(dev->pdev, 2), _DRM_REGISTERS, + _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio); if (ret != 0) return ret; @@ -2135,8 +2135,8 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master) /* prebuild the SAREA */ sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE); - ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, - &master_priv->sarea); + ret = drm_legacy_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, + &master_priv->sarea); if (ret) { DRM_ERROR("SAREA setup failed\n"); kfree(master_priv); @@ -2162,7 +2162,7 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) master_priv->sarea_priv = NULL; if (master_priv->sarea) - drm_rmmap_locked(dev, master_priv->sarea); + drm_legacy_rmmap_locked(dev, master_priv->sarea); kfree(master_priv); @@ -2181,9 +2181,9 @@ int radeon_driver_firstopen(struct drm_device *dev) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; dev_priv->fb_aper_offset = pci_resource_start(dev->pdev, 0); - ret = drm_addmap(dev, dev_priv->fb_aper_offset, - pci_resource_len(dev->pdev, 0), _DRM_FRAME_BUFFER, - _DRM_WRITE_COMBINING, &map); + ret = drm_legacy_addmap(dev, dev_priv->fb_aper_offset, + pci_resource_len(dev->pdev, 0), + _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &map); if (ret != 0) return ret; @@ -2196,7 +2196,7 @@ int radeon_driver_unload(struct drm_device *dev) DRM_DEBUG("\n"); - drm_rmmap(dev, dev_priv->mmio); + drm_legacy_rmmap(dev, dev_priv->mmio); kfree(dev_priv); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index ae763f60c8a0..a3e7aed7e680 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -78,7 +78,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) struct radeon_cs_chunk *chunk; struct radeon_cs_buckets buckets; unsigned i, j; - bool duplicate; + bool duplicate, need_mmap_lock = false; + int r; if (p->chunk_relocs_idx == -1) { return 0; @@ -132,13 +133,17 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) * the buffers used for read only, which doubles the range * to 0 to 31. 32 is reserved for the kernel driver. */ - priority = (r->flags & 0xf) * 2 + !!r->write_domain; + priority = (r->flags & RADEON_RELOC_PRIO_MASK) * 2 + + !!r->write_domain; /* the first reloc of an UVD job is the msg and that must be in - VRAM, also but everything into VRAM on AGP cards to avoid - image corruptions */ + VRAM, also but everything into VRAM on AGP cards and older + IGP chips to avoid image corruptions */ if (p->ring == R600_RING_TYPE_UVD_INDEX && - (i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) { + (i == 0 || drm_pci_device_is_agp(p->rdev->ddev) || + p->rdev->family == CHIP_RS780 || + p->rdev->family == CHIP_RS880)) { + /* TODO: is this still needed for NI+ ? */ p->relocs[i].prefered_domains = RADEON_GEM_DOMAIN_VRAM; @@ -164,7 +169,21 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) p->relocs[i].allowed_domains = domain; } + if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) { + uint32_t domain = p->relocs[i].prefered_domains; + if (!(domain & RADEON_GEM_DOMAIN_GTT)) { + DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is " + "allowed for userptr BOs\n"); + return -EINVAL; + } + need_mmap_lock = true; + domain = RADEON_GEM_DOMAIN_GTT; + p->relocs[i].prefered_domains = domain; + p->relocs[i].allowed_domains = domain; + } + p->relocs[i].tv.bo = &p->relocs[i].robj->tbo; + p->relocs[i].tv.shared = !r->write_domain; p->relocs[i].handle = r->handle; radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head, @@ -176,8 +195,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) if (p->cs_flags & RADEON_CS_USE_VM) p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm, &p->validated); + if (need_mmap_lock) + down_read(¤t->mm->mmap_sem); - return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring); + r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring); + + if (need_mmap_lock) + up_read(¤t->mm->mmap_sem); + + return r; } static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) @@ -223,17 +249,24 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority return 0; } -static void radeon_cs_sync_rings(struct radeon_cs_parser *p) +static int radeon_cs_sync_rings(struct radeon_cs_parser *p) { - int i; + int i, r = 0; for (i = 0; i < p->nrelocs; i++) { + struct reservation_object *resv; + if (!p->relocs[i].robj) continue; - radeon_semaphore_sync_to(p->ib.semaphore, - p->relocs[i].robj->tbo.sync_obj); + resv = p->relocs[i].robj->tbo.resv; + r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv, + p->relocs[i].tv.shared); + + if (r) + break; } + return r; } /* XXX: note that this is called from the legacy UMS CS ioctl as well */ @@ -402,7 +435,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo ttm_eu_fence_buffer_objects(&parser->ticket, &parser->validated, - parser->ib.fence); + &parser->ib.fence->base); } else if (backoff) { ttm_eu_backoff_reservation(&parser->ticket, &parser->validated); @@ -417,7 +450,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo kfree(parser->track); kfree(parser->relocs); kfree(parser->relocs_ptr); - kfree(parser->vm_bos); + drm_free_large(parser->vm_bos); for (i = 0; i < parser->nchunks; i++) drm_free_large(parser->chunks[i].kdata); kfree(parser->chunks); @@ -443,14 +476,20 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, return r; } + r = radeon_cs_sync_rings(parser); + if (r) { + if (r != -ERESTARTSYS) + DRM_ERROR("Failed to sync rings: %i\n", r); + return r; + } + if (parser->ring == R600_RING_TYPE_UVD_INDEX) radeon_uvd_note_usage(rdev); else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) || (parser->ring == TN_RING_TYPE_VCE2_INDEX)) radeon_vce_note_usage(rdev); - radeon_cs_sync_rings(parser); - r = radeon_ib_schedule(rdev, &parser->ib, NULL); + r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); if (r) { DRM_ERROR("Failed to schedule IB !\n"); } @@ -500,7 +539,8 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p, if (r) return r; } - return 0; + + return radeon_vm_clear_invalids(rdev, vm); } static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, @@ -535,14 +575,20 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, if (r) { goto out; } - radeon_cs_sync_rings(parser); - radeon_semaphore_sync_to(parser->ib.semaphore, vm->fence); + + r = radeon_cs_sync_rings(parser); + if (r) { + if (r != -ERESTARTSYS) + DRM_ERROR("Failed to sync rings: %i\n", r); + goto out; + } + radeon_semaphore_sync_fence(parser->ib.semaphore, vm->fence); if ((rdev->family >= CHIP_TAHITI) && (parser->chunk_const_ib_idx != -1)) { - r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib); + r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true); } else { - r = radeon_ib_schedule(rdev, &parser->ib, NULL); + r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); } out: @@ -627,6 +673,13 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) up_read(&rdev->exclusive_lock); return -EBUSY; } + if (rdev->in_reset) { + up_read(&rdev->exclusive_lock); + r = radeon_gpu_reset(rdev); + if (!r) + r = -EAGAIN; + return r; + } /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 697add2cd4e3..995a8b1770dd 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -103,6 +103,35 @@ static const char radeon_family_name[][16] = { "LAST", }; +#define RADEON_PX_QUIRK_DISABLE_PX (1 << 0) +#define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1) + +struct radeon_px_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 px_quirk_flags; +}; + +static struct radeon_px_quirk radeon_px_quirk_list[] = { + /* Acer aspire 5560g (CPU: AMD A4-3305M; GPU: AMD Radeon HD 6480g + 7470m) + * https://bugzilla.kernel.org/show_bug.cgi?id=74551 + */ + { PCI_VENDOR_ID_ATI, 0x6760, 0x1025, 0x0672, RADEON_PX_QUIRK_DISABLE_PX }, + /* Asus K73TA laptop with AMD A6-3400M APU and Radeon 6550 GPU + * https://bugzilla.kernel.org/show_bug.cgi?id=51381 + */ + { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, + /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU + * https://bugzilla.kernel.org/show_bug.cgi?id=51381 + */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, + /* macbook pro 8.2 */ + { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, + { 0, 0, 0, 0, 0 }, +}; + bool radeon_is_px(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; @@ -112,6 +141,26 @@ bool radeon_is_px(struct drm_device *dev) return false; } +static void radeon_device_handle_px_quirks(struct radeon_device *rdev) +{ + struct radeon_px_quirk *p = radeon_px_quirk_list; + + /* Apply PX quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + rdev->px_quirk_flags = p->px_quirk_flags; + break; + } + ++p; + } + + if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX) + rdev->flags &= ~RADEON_IS_PX; +} + /** * radeon_program_register_sequence - program an array of registers. * @@ -385,7 +434,8 @@ int radeon_wb_init(struct radeon_device *rdev) if (rdev->wb.wb_obj == NULL) { r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, NULL, &rdev->wb.wb_obj); + RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL, + &rdev->wb.wb_obj); if (r) { dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); return r; @@ -902,6 +952,7 @@ int radeon_atombios_init(struct radeon_device *rdev) } mutex_init(&rdev->mode_info.atom_context->mutex); + mutex_init(&rdev->mode_info.atom_context->scratch_mutex); radeon_atom_initialize_bios_scratch_regs(rdev->ddev); atom_allocate_fb_scratch(rdev->mode_info.atom_context); return 0; @@ -1077,7 +1128,19 @@ static void radeon_check_arguments(struct radeon_device *rdev) /* defines number of bits in page table versus page directory, * a page is 4KB so we have 12 bits offset, minimum 9 bits in the * page table and the remaining bits are in the page directory */ - if (radeon_vm_block_size < 9) { + if (radeon_vm_block_size == -1) { + + /* Total bits covered by PD + PTs */ + unsigned bits = ilog2(radeon_vm_size) + 18; + + /* Make sure the PD is 4K in size up to 8GB address space. + Above that split equal between PD and PTs */ + if (radeon_vm_size <= 8) + radeon_vm_block_size = bits - 9; + else + radeon_vm_block_size = (bits + 3) / 2; + + } else if (radeon_vm_block_size < 9) { dev_warn(rdev->dev, "VM page table size (%d) too small\n", radeon_vm_block_size); radeon_vm_block_size = 9; @@ -1092,25 +1155,6 @@ static void radeon_check_arguments(struct radeon_device *rdev) } /** - * radeon_switcheroo_quirk_long_wakeup - return true if longer d3 delay is - * needed for waking up. - * - * @pdev: pci dev pointer - */ -static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev) -{ - - /* 6600m in a macbook pro */ - if (pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && - pdev->subsystem_device == 0x00e2) { - printk(KERN_INFO "radeon: quirking longer d3 wakeup delay\n"); - return true; - } - - return false; -} - -/** * radeon_switcheroo_set_state - set switcheroo state * * @pdev: pci dev pointer @@ -1122,6 +1166,7 @@ static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev) static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { struct drm_device *dev = pci_get_drvdata(pdev); + struct radeon_device *rdev = dev->dev_private; if (radeon_is_px(dev) && state == VGA_SWITCHEROO_OFF) return; @@ -1133,7 +1178,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero /* don't suspend or resume card normally */ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - if (d3_delay < 20 && radeon_switcheroo_quirk_long_wakeup(pdev)) + if (d3_delay < 20 && (rdev->px_quirk_flags & RADEON_PX_QUIRK_LONG_WAKEUP)) dev->pdev->d3_delay = 20; radeon_resume_kms(dev, true, true); @@ -1213,6 +1258,7 @@ int radeon_device_init(struct radeon_device *rdev, for (i = 0; i < RADEON_NUM_RINGS; i++) { rdev->ring[i].idx = i; } + rdev->fence_context = fence_context_alloc(RADEON_NUM_RINGS); DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", radeon_family_name[rdev->family], pdev->vendor, pdev->device, @@ -1230,6 +1276,8 @@ int radeon_device_init(struct radeon_device *rdev, init_rwsem(&rdev->pm.mclk_lock); init_rwsem(&rdev->exclusive_lock); init_waitqueue_head(&rdev->irq.vblank_queue); + mutex_init(&rdev->mn_lock); + hash_init(rdev->mn_hash); r = radeon_gem_init(rdev); if (r) return r; @@ -1337,6 +1385,9 @@ int radeon_device_init(struct radeon_device *rdev, if (rdev->rio_mem == NULL) DRM_ERROR("Unable to find PCI I/O BAR\n"); + if (rdev->flags & RADEON_IS_PX) + radeon_device_handle_px_quirks(rdev); + /* if we have > 1 VGA cards, then disable the radeon VGA resources */ /* this will fail for cards that aren't VGA class devices, just * ignore it */ @@ -1350,11 +1401,7 @@ int radeon_device_init(struct radeon_device *rdev, r = radeon_init(rdev); if (r) - return r; - - r = radeon_ib_ring_tests(rdev); - if (r) - DRM_ERROR("ib ring test failed (%d).\n", r); + goto failed; r = radeon_gem_debugfs_init(rdev); if (r) { @@ -1370,9 +1417,13 @@ int radeon_device_init(struct radeon_device *rdev, radeon_agp_disable(rdev); r = radeon_init(rdev); if (r) - return r; + goto failed; } + r = radeon_ib_ring_tests(rdev); + if (r) + DRM_ERROR("ib ring test failed (%d).\n", r); + if ((radeon_testing & 1)) { if (rdev->accel_working) radeon_test_moves(rdev); @@ -1392,6 +1443,11 @@ int radeon_device_init(struct radeon_device *rdev, DRM_INFO("radeon: acceleration disabled, skipping benchmarks\n"); } return 0; + +failed: + if (runtime) + vga_switcheroo_fini_domain_pm_ops(rdev->dev); + return r; } static void radeon_debugfs_remove_files(struct radeon_device *rdev); @@ -1412,6 +1468,8 @@ void radeon_device_fini(struct radeon_device *rdev) radeon_bo_evict_vram(rdev); radeon_fini(rdev); vga_switcheroo_unregister_client(rdev->pdev); + if (rdev->flags & RADEON_IS_PX) + vga_switcheroo_fini_domain_pm_ops(rdev->dev); vga_client_register(rdev->pdev, NULL, NULL, NULL); if (rdev->rio_mem) pci_iounmap(rdev->pdev, rdev->rio_mem); @@ -1443,7 +1501,6 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) struct drm_crtc *crtc; struct drm_connector *connector; int i, r; - bool force_completion = false; if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; @@ -1487,12 +1544,9 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) r = radeon_fence_wait_empty(rdev, i); if (r) { /* delay GPU reset to resume */ - force_completion = true; + radeon_fence_driver_force_completion(rdev, i); } } - if (force_completion) { - radeon_fence_driver_force_completion(rdev); - } radeon_save_bios_scratch_regs(rdev); @@ -1632,13 +1686,11 @@ int radeon_gpu_reset(struct radeon_device *rdev) return 0; } - rdev->needs_reset = false; - radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); - radeon_pm_suspend(rdev); radeon_suspend(rdev); + radeon_hpd_fini(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i], @@ -1650,7 +1702,6 @@ int radeon_gpu_reset(struct radeon_device *rdev) } } -retry: r = radeon_asic_reset(rdev); if (!r) { dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n"); @@ -1659,40 +1710,69 @@ retry: radeon_restore_bios_scratch_regs(rdev); - if (!r) { - for (i = 0; i < RADEON_NUM_RINGS; ++i) { + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!r && ring_data[i]) { radeon_ring_restore(rdev, &rdev->ring[i], ring_sizes[i], ring_data[i]); - ring_sizes[i] = 0; - ring_data[i] = NULL; + } else { + radeon_fence_driver_force_completion(rdev, i); + kfree(ring_data[i]); } + } - r = radeon_ib_ring_tests(rdev); + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { + /* do dpm late init */ + r = radeon_pm_late_init(rdev); if (r) { - dev_err(rdev->dev, "ib ring test failed (%d).\n", r); - if (saved) { - saved = false; - radeon_suspend(rdev); - goto retry; - } + rdev->pm.dpm_enabled = false; + DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); } } else { - radeon_fence_driver_force_completion(rdev); - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - kfree(ring_data[i]); + /* resume old pm late */ + radeon_pm_resume(rdev); + } + + /* init dig PHYs, disp eng pll */ + if (rdev->is_atom_bios) { + radeon_atom_encoder_init(rdev); + radeon_atom_disp_eng_pll_init(rdev); + /* turn on the BL */ + if (rdev->mode_info.bl_encoder) { + u8 bl_level = radeon_get_backlight_level(rdev, + rdev->mode_info.bl_encoder); + radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, + bl_level); } } + /* reset hpd state */ + radeon_hpd_init(rdev); + + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); + + rdev->in_reset = true; + rdev->needs_reset = false; + + downgrade_write(&rdev->exclusive_lock); - radeon_pm_resume(rdev); drm_helper_resume_force_mode(rdev->ddev); - ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); - if (r) { + /* set the power state here in case we are a PX system or headless */ + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) + radeon_pm_compute_clocks(rdev); + + if (!r) { + r = radeon_ib_ring_tests(rdev); + if (r && saved) + r = -EAGAIN; + } else { /* bad news, how to tell it to userspace ? */ dev_info(rdev->dev, "GPU reset failed\n"); } - up_write(&rdev->exclusive_lock); + rdev->needs_reset = r == -EAGAIN; + rdev->in_reset = false; + + up_read(&rdev->exclusive_lock); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index bf25061c8ac4..00ead8c2758a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -293,6 +293,18 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) if (radeon_crtc == NULL) return; + /* Skip the pageflip completion check below (based on polling) on + * asics which reliably support hw pageflip completion irqs. pflip + * irqs are a reliable and race-free method of handling pageflip + * completion detection. A use_pflipirq module parameter < 2 allows + * to override this in case of asics with faulty pflip irqs. + * A module parameter of 0 would only use this polling based path, + * a parameter of 1 would use pflip irq only as a backup to this + * path, as in Linux 3.16. + */ + if ((radeon_use_pflipirq == 2) && ASIC_IS_DCE4(rdev)) + return; + spin_lock_irqsave(&rdev->ddev->event_lock, flags); if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " @@ -390,12 +402,21 @@ static void radeon_flip_work_func(struct work_struct *__work) down_read(&rdev->exclusive_lock); if (work->fence) { - r = radeon_fence_wait(work->fence, false); - if (r == -EDEADLK) { - up_read(&rdev->exclusive_lock); - r = radeon_gpu_reset(rdev); - down_read(&rdev->exclusive_lock); - } + struct radeon_fence *fence; + + fence = to_radeon_fence(work->fence); + if (fence && fence->rdev == rdev) { + r = radeon_fence_wait(fence, false); + if (r == -EDEADLK) { + up_read(&rdev->exclusive_lock); + do { + r = radeon_gpu_reset(rdev); + } while (r == -EAGAIN); + down_read(&rdev->exclusive_lock); + } + } else + r = fence_wait(work->fence, false); + if (r) DRM_ERROR("failed to wait on page flip fence (%d)!\n", r); @@ -404,7 +425,8 @@ static void radeon_flip_work_func(struct work_struct *__work) * confused about which BO the CRTC is scanning out */ - radeon_fence_unref(&work->fence); + fence_put(work->fence); + work->fence = NULL; } /* We borrow the event spin lock for protecting flip_status */ @@ -462,11 +484,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, obj = new_radeon_fb->obj; new_rbo = gem_to_radeon_bo(obj); - spin_lock(&new_rbo->tbo.bdev->fence_lock); - if (new_rbo->tbo.sync_obj) - work->fence = radeon_fence_ref(new_rbo->tbo.sync_obj); - spin_unlock(&new_rbo->tbo.bdev->fence_lock); - /* pin the new buffer */ DRM_DEBUG_DRIVER("flip-ioctl() cur_rbo = %p, new_rbo = %p\n", work->old_rbo, new_rbo); @@ -485,6 +502,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, DRM_ERROR("failed to pin new rbo buffer before flip\n"); goto cleanup; } + work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv)); radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL); radeon_bo_unreserve(new_rbo); @@ -566,9 +584,8 @@ pflip_cleanup: cleanup: drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); - radeon_fence_unref(&work->fence); + fence_put(work->fence); kfree(work); - return r; } @@ -823,64 +840,6 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) return ret; } -int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) -{ - struct drm_device *dev = radeon_connector->base.dev; - struct radeon_device *rdev = dev->dev_private; - int ret = 0; - - /* don't leak the edid if we already fetched it in detect() */ - if (radeon_connector->edid) - goto got_edid; - - /* on hw with routers, select right port */ - if (radeon_connector->router.ddc_valid) - radeon_router_select_ddc_port(radeon_connector); - - if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != - ENCODER_OBJECT_ID_NONE) { - if (radeon_connector->ddc_bus->has_aux) - radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &radeon_connector->ddc_bus->aux.ddc); - } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { - struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - - if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || - dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && - radeon_connector->ddc_bus->has_aux) - radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &radeon_connector->ddc_bus->aux.ddc); - else if (radeon_connector->ddc_bus && !radeon_connector->edid) - radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &radeon_connector->ddc_bus->adapter); - } else { - if (radeon_connector->ddc_bus && !radeon_connector->edid) - radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &radeon_connector->ddc_bus->adapter); - } - - if (!radeon_connector->edid) { - if (rdev->is_atom_bios) { - /* some laptops provide a hardcoded edid in rom for LCDs */ - if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) - radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); - } else - /* some servers provide a hardcoded edid in rom for KVMs */ - radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); - } - if (radeon_connector->edid) { -got_edid: - drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); - ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); - drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); - return ret; - } - drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); - return 0; -} - /* avivo */ /** @@ -1749,7 +1708,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) && ((radeon_encoder->underscan_type == UNDERSCAN_ON) || ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && - drm_detect_hdmi_monitor(radeon_connector->edid) && + drm_detect_hdmi_monitor(radeon_connector_edid(connector)) && is_hdtv_mode(mode)))) { if (radeon_encoder->underscan_hborder != 0) radeon_crtc->h_border = radeon_encoder->underscan_hborder; @@ -1963,7 +1922,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl /* In vblank? */ if (in_vbl) - ret |= DRM_SCANOUTPOS_INVBL; + ret |= DRM_SCANOUTPOS_IN_VBLANK; /* Is vpos outside nominal vblank area, but less than * 1/100 of a frame height away from start of vblank? diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 959f0866d993..dcffa30ee2db 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -38,6 +38,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/vga_switcheroo.h> +#include <drm/drm_gem.h> + #include "drm_crtc_helper.h" /* * KMS wrapper. @@ -82,9 +84,11 @@ * 2.38.0 - RADEON_GEM_OP (GET_INITIAL_DOMAIN, SET_INITIAL_DOMAIN), * CIK: 1D and linear tiling modes contain valid PIPE_CONFIG * 2.39.0 - Add INFO query for number of active CUs + * 2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting + * CS to GPU on >= r600 */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 39 +#define KMS_DRIVER_MINOR 40 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); @@ -112,6 +116,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv); void radeon_gem_object_close(struct drm_gem_object *obj, struct drm_file *file_priv); +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gobj, + int flags); extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, int *vpos, int *hpos, ktime_t *stime, @@ -128,7 +135,7 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args); struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj); struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev, - size_t size, + struct dma_buf_attachment *, struct sg_table *sg); int radeon_gem_prime_pin(struct drm_gem_object *obj); void radeon_gem_prime_unpin(struct drm_gem_object *obj); @@ -174,9 +181,12 @@ int radeon_dpm = -1; int radeon_aspm = -1; int radeon_runtime_pm = -1; int radeon_hard_reset = 0; -int radeon_vm_size = 4; -int radeon_vm_block_size = 9; +int radeon_vm_size = 8; +int radeon_vm_block_size = -1; int radeon_deep_color = 0; +int radeon_use_pflipirq = 2; +int radeon_bapm = -1; +int radeon_backlight = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -247,12 +257,21 @@ module_param_named(hard_reset, radeon_hard_reset, int, 0444); MODULE_PARM_DESC(vm_size, "VM address space size in gigabytes (default 4GB)"); module_param_named(vm_size, radeon_vm_size, int, 0444); -MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default 9)"); +MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default depending on vm_size)"); module_param_named(vm_block_size, radeon_vm_block_size, int, 0444); MODULE_PARM_DESC(deep_color, "Deep Color support (1 = enable, 0 = disable (default))"); module_param_named(deep_color, radeon_deep_color, int, 0444); +MODULE_PARM_DESC(use_pflipirq, "Pflip irqs for pageflip completion (0 = disable, 1 = as fallback, 2 = exclusive (default))"); +module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444); + +MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(bapm, radeon_bapm, int, 0444); + +MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(backlight, radeon_backlight, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; @@ -295,7 +314,7 @@ static const struct file_operations radeon_driver_old_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, - .mmap = drm_mmap, + .mmap = drm_legacy_mmap, .poll = drm_poll, .read = drm_read, #ifdef CONFIG_COMPAT @@ -315,6 +334,7 @@ static struct drm_driver driver_old = { .preclose = radeon_driver_preclose, .postclose = radeon_driver_postclose, .lastclose = radeon_driver_lastclose, + .set_busid = drm_pci_set_busid, .unload = radeon_driver_unload, .suspend = radeon_suspend, .resume = radeon_resume, @@ -430,6 +450,7 @@ static int radeon_pmops_runtime_suspend(struct device *dev) ret = radeon_suspend_kms(drm_dev, false, false); pci_save_state(pdev); pci_disable_device(pdev); + pci_ignore_hotplug(pdev); pci_set_power_state(pdev, PCI_D3cold); drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; @@ -538,6 +559,7 @@ static struct drm_driver kms_driver = { .preclose = radeon_driver_preclose_kms, .postclose = radeon_driver_postclose_kms, .lastclose = radeon_driver_lastclose_kms, + .set_busid = drm_pci_set_busid, .unload = radeon_driver_unload_kms, .get_vblank_counter = radeon_get_vblank_counter_kms, .enable_vblank = radeon_enable_vblank_kms, @@ -563,7 +585,7 @@ static struct drm_driver kms_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = drm_gem_prime_export, + .gem_prime_export = radeon_gem_prime_export, .gem_prime_import = drm_gem_prime_import, .gem_prime_pin = radeon_gem_prime_pin, .gem_prime_unpin = radeon_gem_prime_unpin, diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index dafd812e4571..46bd3938282c 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -33,7 +33,9 @@ #include <linux/firmware.h> #include <linux/platform_device.h> +#include <drm/drm_legacy.h> +#include <drm/ati_pcigart.h> #include "radeon_family.h" /* General customization: diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index bd4959ca23aa..9a19e52cc655 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -158,10 +158,43 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 return ret; } +static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + bool use_bl = false; + + if (!(radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))) + return; + + if (radeon_backlight == 0) { + return; + } else if (radeon_backlight == 1) { + use_bl = true; + } else if (radeon_backlight == -1) { + /* Quirks */ + /* Amilo Xi 2550 only works with acpi bl */ + if ((rdev->pdev->device == 0x9583) && + (rdev->pdev->subsystem_vendor == 0x1734) && + (rdev->pdev->subsystem_device == 0x1107)) + use_bl = false; + else + use_bl = true; + } + + if (use_bl) { + if (rdev->is_atom_bios) + radeon_atom_backlight_init(radeon_encoder, connector); + else + radeon_legacy_backlight_init(radeon_encoder, connector); + rdev->mode_info.bl_encoder = radeon_encoder; + } +} + void radeon_link_encoder_connector(struct drm_device *dev) { - struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct drm_encoder *encoder; @@ -174,13 +207,8 @@ radeon_link_encoder_connector(struct drm_device *dev) radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->devices & radeon_connector->devices) { drm_mode_connector_attach_encoder(connector, encoder); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (rdev->is_atom_bios) - radeon_atom_backlight_init(radeon_encoder, connector); - else - radeon_legacy_backlight_init(radeon_encoder, connector); - rdev->mode_info.bl_encoder = radeon_encoder; - } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_encoder_add_backlight(radeon_encoder, connector); } } } @@ -343,7 +371,7 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder, case DRM_MODE_CONNECTOR_HDMIB: if (radeon_connector->use_digital) { /* HDMI 1.3 supports up to 340 Mhz over single link */ - if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { if (pixel_clock > 340000) return true; else @@ -365,7 +393,7 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder, return false; else { /* HDMI 1.3 supports up to 340 Mhz over single link */ - if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { if (pixel_clock > 340000) return true; else @@ -382,3 +410,24 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder, } } +bool radeon_encoder_is_digital(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: + return true; + default: + return false; + } +} diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 665ced3b7313..0ea1db83d573 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -127,8 +127,7 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, aligned_size = ALIGN(size, PAGE_SIZE); ret = radeon_gem_object_create(rdev, aligned_size, 0, RADEON_GEM_DOMAIN_VRAM, - false, true, - &gobj); + 0, true, &gobj); if (ret) { printk(KERN_ERR "failed to allocate framebuffer (%d)\n", aligned_size); @@ -190,7 +189,8 @@ out_unref: static int radeonfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper; + struct radeon_fbdev *rfbdev = + container_of(helper, struct radeon_fbdev, helper); struct radeon_device *rdev = rfbdev->rdev; struct fb_info *info; struct drm_framebuffer *fb = NULL; @@ -331,7 +331,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb return 0; } -static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { +static const struct drm_fb_helper_funcs radeon_fb_helper_funcs = { .gamma_set = radeon_crtc_fb_gamma_set, .gamma_get = radeon_crtc_fb_gamma_get, .fb_probe = radeonfb_create, @@ -353,7 +353,9 @@ int radeon_fbdev_init(struct radeon_device *rdev) rfbdev->rdev = rdev; rdev->mode_info.rfbdev = rfbdev; - rfbdev->helper.funcs = &radeon_fb_helper_funcs; + + drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper, + &radeon_fb_helper_funcs); ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, rdev->num_crtc, diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 913787085dfa..995167025282 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -98,6 +98,25 @@ static u32 radeon_fence_read(struct radeon_device *rdev, int ring) } /** + * radeon_fence_schedule_check - schedule lockup check + * + * @rdev: radeon_device pointer + * @ring: ring index we should work with + * + * Queues a delayed work item to check for lockups. + */ +static void radeon_fence_schedule_check(struct radeon_device *rdev, int ring) +{ + /* + * Do not reset the timer here with mod_delayed_work, + * this can livelock in an interaction with TTM delayed destroy. + */ + queue_delayed_work(system_power_efficient_wq, + &rdev->fence_drv[ring].lockup_work, + RADEON_FENCE_JIFFIES_TIMEOUT); +} + +/** * radeon_fence_emit - emit a fence on the requested ring * * @rdev: radeon_device pointer @@ -111,30 +130,70 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring) { + u64 seq = ++rdev->fence_drv[ring].sync_seq[ring]; + /* we are protected by the ring emission mutex */ *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL); if ((*fence) == NULL) { return -ENOMEM; } - kref_init(&((*fence)->kref)); (*fence)->rdev = rdev; - (*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring]; + (*fence)->seq = seq; (*fence)->ring = ring; + fence_init(&(*fence)->base, &radeon_fence_ops, + &rdev->fence_queue.lock, rdev->fence_context + ring, seq); radeon_fence_ring_emit(rdev, ring, *fence); trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq); + radeon_fence_schedule_check(rdev, ring); return 0; } /** - * radeon_fence_process - process a fence + * radeon_fence_check_signaled - callback from fence_queue + * + * this function is called with fence_queue lock held, which is also used + * for the fence locking itself, so unlocked variants are used for + * fence_signal, and remove_wait_queue. + */ +static int radeon_fence_check_signaled(wait_queue_t *wait, unsigned mode, int flags, void *key) +{ + struct radeon_fence *fence; + u64 seq; + + fence = container_of(wait, struct radeon_fence, fence_wake); + + /* + * We cannot use radeon_fence_process here because we're already + * in the waitqueue, in a call from wake_up_all. + */ + seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq); + if (seq >= fence->seq) { + int ret = fence_signal_locked(&fence->base); + + if (!ret) + FENCE_TRACE(&fence->base, "signaled from irq context\n"); + else + FENCE_TRACE(&fence->base, "was already signaled\n"); + + radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring); + __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake); + fence_put(&fence->base); + } else + FENCE_TRACE(&fence->base, "pending\n"); + return 0; +} + +/** + * radeon_fence_activity - check for fence activity * * @rdev: radeon_device pointer * @ring: ring index the fence is associated with * - * Checks the current fence value and wakes the fence queue - * if the sequence number has increased (all asics). + * Checks the current fence value and calculates the last + * signalled fence value. Returns true if activity occured + * on the ring, and the fence_queue should be waken up. */ -void radeon_fence_process(struct radeon_device *rdev, int ring) +static bool radeon_fence_activity(struct radeon_device *rdev, int ring) { uint64_t seq, last_seq, last_emitted; unsigned count_loop = 0; @@ -190,23 +249,77 @@ void radeon_fence_process(struct radeon_device *rdev, int ring) } } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); - if (wake) - wake_up_all(&rdev->fence_queue); + if (seq < last_emitted) + radeon_fence_schedule_check(rdev, ring); + + return wake; } /** - * radeon_fence_destroy - destroy a fence + * radeon_fence_check_lockup - check for hardware lockup * - * @kref: fence kref + * @work: delayed work item * - * Frees the fence object (all asics). + * Checks for fence activity and if there is none probe + * the hardware if a lockup occured. */ -static void radeon_fence_destroy(struct kref *kref) +static void radeon_fence_check_lockup(struct work_struct *work) { - struct radeon_fence *fence; + struct radeon_fence_driver *fence_drv; + struct radeon_device *rdev; + int ring; + + fence_drv = container_of(work, struct radeon_fence_driver, + lockup_work.work); + rdev = fence_drv->rdev; + ring = fence_drv - &rdev->fence_drv[0]; + + if (!down_read_trylock(&rdev->exclusive_lock)) { + /* just reschedule the check if a reset is going on */ + radeon_fence_schedule_check(rdev, ring); + return; + } + + if (fence_drv->delayed_irq && rdev->ddev->irq_enabled) { + unsigned long irqflags; + + fence_drv->delayed_irq = false; + spin_lock_irqsave(&rdev->irq.lock, irqflags); + radeon_irq_set(rdev); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); + } + + if (radeon_fence_activity(rdev, ring)) + wake_up_all(&rdev->fence_queue); - fence = container_of(kref, struct radeon_fence, kref); - kfree(fence); + else if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { + + /* good news we believe it's a lockup */ + dev_warn(rdev->dev, "GPU lockup (current fence id " + "0x%016llx last fence id 0x%016llx on ring %d)\n", + (uint64_t)atomic64_read(&fence_drv->last_seq), + fence_drv->sync_seq[ring], ring); + + /* remember that we need an reset */ + rdev->needs_reset = true; + wake_up_all(&rdev->fence_queue); + } + up_read(&rdev->exclusive_lock); +} + +/** + * radeon_fence_process - process a fence + * + * @rdev: radeon_device pointer + * @ring: ring index the fence is associated with + * + * Checks the current fence value and wakes the fence queue + * if the sequence number has increased (all asics). + */ +void radeon_fence_process(struct radeon_device *rdev, int ring) +{ + if (radeon_fence_activity(rdev, ring)) + wake_up_all(&rdev->fence_queue); } /** @@ -237,6 +350,75 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev, return false; } +static bool radeon_fence_is_signaled(struct fence *f) +{ + struct radeon_fence *fence = to_radeon_fence(f); + struct radeon_device *rdev = fence->rdev; + unsigned ring = fence->ring; + u64 seq = fence->seq; + + if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { + return true; + } + + if (down_read_trylock(&rdev->exclusive_lock)) { + radeon_fence_process(rdev, ring); + up_read(&rdev->exclusive_lock); + + if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { + return true; + } + } + return false; +} + +/** + * radeon_fence_enable_signaling - enable signalling on fence + * @fence: fence + * + * This function is called with fence_queue lock held, and adds a callback + * to fence_queue that checks if this fence is signaled, and if so it + * signals the fence and removes itself. + */ +static bool radeon_fence_enable_signaling(struct fence *f) +{ + struct radeon_fence *fence = to_radeon_fence(f); + struct radeon_device *rdev = fence->rdev; + + if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) + return false; + + if (down_read_trylock(&rdev->exclusive_lock)) { + radeon_irq_kms_sw_irq_get(rdev, fence->ring); + + if (radeon_fence_activity(rdev, fence->ring)) + wake_up_all_locked(&rdev->fence_queue); + + /* did fence get signaled after we enabled the sw irq? */ + if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) { + radeon_irq_kms_sw_irq_put(rdev, fence->ring); + up_read(&rdev->exclusive_lock); + return false; + } + + up_read(&rdev->exclusive_lock); + } else { + /* we're probably in a lockup, lets not fiddle too much */ + if (radeon_irq_kms_sw_irq_get_delayed(rdev, fence->ring)) + rdev->fence_drv[fence->ring].delayed_irq = true; + radeon_fence_schedule_check(rdev, fence->ring); + } + + fence->fence_wake.flags = 0; + fence->fence_wake.private = NULL; + fence->fence_wake.func = radeon_fence_check_signaled; + __add_wait_queue(&rdev->fence_queue, &fence->fence_wake); + fence_get(f); + + FENCE_TRACE(&fence->base, "armed on ring %i!\n", fence->ring); + return true; +} + /** * radeon_fence_signaled - check if a fence has signaled * @@ -247,14 +429,15 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev, */ bool radeon_fence_signaled(struct radeon_fence *fence) { - if (!fence) { + if (!fence) return true; - } - if (fence->seq == RADEON_FENCE_SIGNALED_SEQ) { - return true; - } + if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) { - fence->seq = RADEON_FENCE_SIGNALED_SEQ; + int ret; + + ret = fence_signal(&fence->base); + if (!ret) + FENCE_TRACE(&fence->base, "signaled from radeon_fence_signaled\n"); return true; } return false; @@ -283,110 +466,70 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) } /** - * radeon_fence_wait_seq - wait for a specific sequence numbers + * radeon_fence_wait_seq_timeout - wait for a specific sequence numbers * * @rdev: radeon device pointer * @target_seq: sequence number(s) we want to wait for * @intr: use interruptable sleep + * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait * * Wait for the requested sequence number(s) to be written by any ring * (all asics). Sequnce number array is indexed by ring id. * @intr selects whether to use interruptable (true) or non-interruptable * (false) sleep when waiting for the sequence number. Helper function * for radeon_fence_wait_*(). - * Returns 0 if the sequence number has passed, error for all other cases. + * Returns remaining time if the sequence number has passed, 0 when + * the wait timeout, or an error for all other cases. * -EDEADLK is returned when a GPU lockup has been detected. */ -static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, - bool intr) +static long radeon_fence_wait_seq_timeout(struct radeon_device *rdev, + u64 *target_seq, bool intr, + long timeout) { - uint64_t last_seq[RADEON_NUM_RINGS]; - bool signaled; - int i, r; - - while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { + long r; + int i; - /* Save current sequence values, used to check for GPU lockups */ - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; + if (radeon_fence_any_seq_signaled(rdev, target_seq)) + return timeout; - last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq); - trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]); - radeon_irq_kms_sw_irq_get(rdev, i); - } + /* enable IRQs and tracing */ + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; - if (intr) { - r = wait_event_interruptible_timeout(rdev->fence_queue, ( - (signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) - || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); - } else { - r = wait_event_timeout(rdev->fence_queue, ( - (signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) - || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); - } + trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]); + radeon_irq_kms_sw_irq_get(rdev, i); + } - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; + if (intr) { + r = wait_event_interruptible_timeout(rdev->fence_queue, ( + radeon_fence_any_seq_signaled(rdev, target_seq) + || rdev->needs_reset), timeout); + } else { + r = wait_event_timeout(rdev->fence_queue, ( + radeon_fence_any_seq_signaled(rdev, target_seq) + || rdev->needs_reset), timeout); + } - radeon_irq_kms_sw_irq_put(rdev, i); - trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]); - } + if (rdev->needs_reset) + r = -EDEADLK; - if (unlikely(r < 0)) - return r; + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; - if (unlikely(!signaled)) { - if (rdev->needs_reset) - return -EDEADLK; - - /* we were interrupted for some reason and fence - * isn't signaled yet, resume waiting */ - if (r) - continue; - - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; - - if (last_seq[i] != atomic64_read(&rdev->fence_drv[i].last_seq)) - break; - } - - if (i != RADEON_NUM_RINGS) - continue; - - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; - - if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i])) - break; - } - - if (i < RADEON_NUM_RINGS) { - /* good news we believe it's a lockup */ - dev_warn(rdev->dev, "GPU lockup (waiting for " - "0x%016llx last fence id 0x%016llx on" - " ring %d)\n", - target_seq[i], last_seq[i], i); - - /* remember that we need an reset */ - rdev->needs_reset = true; - wake_up_all(&rdev->fence_queue); - return -EDEADLK; - } - } + radeon_irq_kms_sw_irq_put(rdev, i); + trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]); } - return 0; + + return r; } /** * radeon_fence_wait - wait for a fence to signal * * @fence: radeon fence object - * @intr: use interruptable sleep + * @intr: use interruptible sleep * * Wait for the requested fence to signal (all asics). * @intr selects whether to use interruptable (true) or non-interruptable @@ -396,22 +539,26 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, int radeon_fence_wait(struct radeon_fence *fence, bool intr) { uint64_t seq[RADEON_NUM_RINGS] = {}; - int r; + long r; - if (fence == NULL) { - WARN(1, "Querying an invalid fence : %p !\n", fence); - return -EINVAL; - } + /* + * This function should not be called on !radeon fences. + * If this is the case, it would mean this function can + * also be called on radeon fences belonging to another card. + * exclusive_lock is not held in that case. + */ + if (WARN_ON_ONCE(!to_radeon_fence(&fence->base))) + return fence_wait(&fence->base, intr); seq[fence->ring] = fence->seq; - if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ) - return 0; - - r = radeon_fence_wait_seq(fence->rdev, seq, intr); - if (r) + r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); + if (r < 0) { return r; + } - fence->seq = RADEON_FENCE_SIGNALED_SEQ; + r = fence_signal(&fence->base); + if (!r) + FENCE_TRACE(&fence->base, "signaled from fence_wait\n"); return 0; } @@ -434,7 +581,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev, { uint64_t seq[RADEON_NUM_RINGS]; unsigned i, num_rings = 0; - int r; + long r; for (i = 0; i < RADEON_NUM_RINGS; ++i) { seq[i] = 0; @@ -445,18 +592,14 @@ int radeon_fence_wait_any(struct radeon_device *rdev, seq[i] = fences[i]->seq; ++num_rings; - - /* test if something was allready signaled */ - if (seq[i] == RADEON_FENCE_SIGNALED_SEQ) - return 0; } /* nothing to wait for ? */ if (num_rings == 0) return -ENOENT; - r = radeon_fence_wait_seq(rdev, seq, intr); - if (r) { + r = radeon_fence_wait_seq_timeout(rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); + if (r < 0) { return r; } return 0; @@ -475,6 +618,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev, int radeon_fence_wait_next(struct radeon_device *rdev, int ring) { uint64_t seq[RADEON_NUM_RINGS] = {}; + long r; seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) { @@ -482,7 +626,10 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) already the last emited fence */ return -ENOENT; } - return radeon_fence_wait_seq(rdev, seq, false); + r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT); + if (r < 0) + return r; + return 0; } /** @@ -498,18 +645,18 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) int radeon_fence_wait_empty(struct radeon_device *rdev, int ring) { uint64_t seq[RADEON_NUM_RINGS] = {}; - int r; + long r; seq[ring] = rdev->fence_drv[ring].sync_seq[ring]; if (!seq[ring]) return 0; - r = radeon_fence_wait_seq(rdev, seq, false); - if (r) { + r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT); + if (r < 0) { if (r == -EDEADLK) return -EDEADLK; - dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n", + dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%ld)\n", ring, r); } return 0; @@ -525,7 +672,7 @@ int radeon_fence_wait_empty(struct radeon_device *rdev, int ring) */ struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) { - kref_get(&fence->kref); + fence_get(&fence->base); return fence; } @@ -542,7 +689,7 @@ void radeon_fence_unref(struct radeon_fence **fence) *fence = NULL; if (tmp) { - kref_put(&tmp->kref, radeon_fence_destroy); + fence_put(&tmp->base); } } @@ -711,6 +858,9 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring) rdev->fence_drv[ring].sync_seq[i] = 0; atomic64_set(&rdev->fence_drv[ring].last_seq, 0); rdev->fence_drv[ring].initialized = false; + INIT_DELAYED_WORK(&rdev->fence_drv[ring].lockup_work, + radeon_fence_check_lockup); + rdev->fence_drv[ring].rdev = rdev; } /** @@ -758,8 +908,9 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) r = radeon_fence_wait_empty(rdev, ring); if (r) { /* no need to trigger GPU reset as we are unloading */ - radeon_fence_driver_force_completion(rdev); + radeon_fence_driver_force_completion(rdev, ring); } + cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work); wake_up_all(&rdev->fence_queue); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); rdev->fence_drv[ring].initialized = false; @@ -771,18 +922,16 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) * radeon_fence_driver_force_completion - force all fence waiter to complete * * @rdev: radeon device pointer + * @ring: the ring to complete * * In case of GPU reset failure make sure no process keep waiting on fence * that will never complete. */ -void radeon_fence_driver_force_completion(struct radeon_device *rdev) +void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring) { - int ring; - - for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { - if (!rdev->fence_drv[ring].initialized) - continue; + if (rdev->fence_drv[ring].initialized) { radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); + cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work); } } @@ -833,6 +982,7 @@ static int radeon_debugfs_gpu_reset(struct seq_file *m, void *data) down_read(&rdev->exclusive_lock); seq_printf(m, "%d\n", rdev->needs_reset); rdev->needs_reset = true; + wake_up_all(&rdev->fence_queue); up_read(&rdev->exclusive_lock); return 0; @@ -852,3 +1002,72 @@ int radeon_debugfs_fence_init(struct radeon_device *rdev) return 0; #endif } + +static const char *radeon_fence_get_driver_name(struct fence *fence) +{ + return "radeon"; +} + +static const char *radeon_fence_get_timeline_name(struct fence *f) +{ + struct radeon_fence *fence = to_radeon_fence(f); + switch (fence->ring) { + case RADEON_RING_TYPE_GFX_INDEX: return "radeon.gfx"; + case CAYMAN_RING_TYPE_CP1_INDEX: return "radeon.cp1"; + case CAYMAN_RING_TYPE_CP2_INDEX: return "radeon.cp2"; + case R600_RING_TYPE_DMA_INDEX: return "radeon.dma"; + case CAYMAN_RING_TYPE_DMA1_INDEX: return "radeon.dma1"; + case R600_RING_TYPE_UVD_INDEX: return "radeon.uvd"; + case TN_RING_TYPE_VCE1_INDEX: return "radeon.vce1"; + case TN_RING_TYPE_VCE2_INDEX: return "radeon.vce2"; + default: WARN_ON_ONCE(1); return "radeon.unk"; + } +} + +static inline bool radeon_test_signaled(struct radeon_fence *fence) +{ + return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags); +} + +static signed long radeon_fence_default_wait(struct fence *f, bool intr, + signed long t) +{ + struct radeon_fence *fence = to_radeon_fence(f); + struct radeon_device *rdev = fence->rdev; + bool signaled; + + fence_enable_sw_signaling(&fence->base); + + /* + * This function has to return -EDEADLK, but cannot hold + * exclusive_lock during the wait because some callers + * may already hold it. This means checking needs_reset without + * lock, and not fiddling with any gpu internals. + * + * The callback installed with fence_enable_sw_signaling will + * run before our wait_event_*timeout call, so we will see + * both the signaled fence and the changes to needs_reset. + */ + + if (intr) + t = wait_event_interruptible_timeout(rdev->fence_queue, + ((signaled = radeon_test_signaled(fence)) || + rdev->needs_reset), t); + else + t = wait_event_timeout(rdev->fence_queue, + ((signaled = radeon_test_signaled(fence)) || + rdev->needs_reset), t); + + if (t > 0 && !signaled) + return -EDEADLK; + return t; +} + +const struct fence_ops radeon_fence_ops = { + .get_driver_name = radeon_fence_get_driver_name, + .get_timeline_name = radeon_fence_get_timeline_name, + .enable_signaling = radeon_fence_enable_signaling, + .signaled = radeon_fence_is_signaled, + .wait = radeon_fence_default_wait, + .release = NULL, +}; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2e723651069b..84146d5901aa 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -128,7 +128,7 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) if (rdev->gart.robj == NULL) { r = radeon_bo_create(rdev, rdev->gart.table_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - NULL, &rdev->gart.robj); + 0, NULL, NULL, &rdev->gart.robj); if (r) { return r; } @@ -243,7 +243,8 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { if (rdev->gart.ptr) { - radeon_gart_set_page(rdev, t, page_base); + radeon_gart_set_page(rdev, t, page_base, + RADEON_GART_PAGE_DUMMY); } page_base += RADEON_GPU_PAGE_SIZE; } @@ -261,13 +262,15 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, * @pages: number of pages to bind * @pagelist: pages to bind * @dma_addr: DMA addresses of pages + * @flags: RADEON_GART_PAGE_* flags * * Binds the requested pages to the gart page table * (all asics). * Returns 0 for success, -EINVAL for failure. */ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, - int pages, struct page **pagelist, dma_addr_t *dma_addr) + int pages, struct page **pagelist, dma_addr_t *dma_addr, + uint32_t flags) { unsigned t; unsigned p; @@ -287,7 +290,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, if (rdev->gart.ptr) { page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); + radeon_gart_set_page(rdev, t, page_base, flags); page_base += RADEON_GPU_PAGE_SIZE; } } @@ -298,33 +301,6 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, } /** - * radeon_gart_restore - bind all pages in the gart page table - * - * @rdev: radeon_device pointer - * - * Binds all pages in the gart page table (all asics). - * Used to rebuild the gart table on device startup or resume. - */ -void radeon_gart_restore(struct radeon_device *rdev) -{ - int i, j, t; - u64 page_base; - - if (!rdev->gart.ptr) { - return; - } - for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) { - page_base = rdev->gart.pages_addr[i]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); - page_base += RADEON_GPU_PAGE_SIZE; - } - } - mb(); - radeon_gart_tlb_flush(rdev); -} - -/** * radeon_gart_init - init the driver info for managing the gart * * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index d09650c1d720..c194497aa586 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -40,9 +40,9 @@ void radeon_gem_object_free(struct drm_gem_object *gobj) } } -int radeon_gem_object_create(struct radeon_device *rdev, int size, +int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size, int alignment, int initial_domain, - bool discardable, bool kernel, + u32 flags, bool kernel, struct drm_gem_object **obj) { struct radeon_bo *robj; @@ -55,23 +55,26 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size, alignment = PAGE_SIZE; } - /* maximun bo size is the minimun btw visible vram and gtt size */ - max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size); + /* Maximum bo size is the unpinned gtt size since we use the gtt to + * handle vram to system pool migrations. + */ + max_size = rdev->mc.gtt_size - rdev->gart_pin_size; if (size > max_size) { - printk(KERN_WARNING "%s:%d alloc size %dMb bigger than %ldMb limit\n", - __func__, __LINE__, size >> 20, max_size >> 20); + DRM_DEBUG("Allocation size %ldMb bigger than %ldMb limit\n", + size >> 20, max_size >> 20); return -ENOMEM; } retry: - r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, NULL, &robj); + r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, + flags, NULL, NULL, &robj); if (r) { if (r != -ERESTARTSYS) { if (initial_domain == RADEON_GEM_DOMAIN_VRAM) { initial_domain |= RADEON_GEM_DOMAIN_GTT; goto retry; } - DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n", + DRM_ERROR("Failed to allocate GEM object (%ld, %d, %u, %d)\n", size, initial_domain, alignment, r); } return r; @@ -91,7 +94,7 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj, { struct radeon_bo *robj; uint32_t domain; - int r; + long r; /* FIXME: reeimplement */ robj = gem_to_radeon_bo(gobj); @@ -107,9 +110,12 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj, } if (domain == RADEON_GEM_DOMAIN_CPU) { /* Asking for cpu access wait for object idle */ - r = radeon_bo_wait(robj, NULL, false); - if (r) { - printk(KERN_ERR "Failed to wait for object !\n"); + r = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, 30 * HZ); + if (!r) + r = -EBUSY; + + if (r < 0 && r != -EINTR) { + printk(KERN_ERR "Failed to wait for object: %li\n", r); return r; } } @@ -208,18 +214,15 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, struct radeon_device *rdev = dev->dev_private; struct drm_radeon_gem_info *args = data; struct ttm_mem_type_manager *man; - unsigned i; man = &rdev->mman.bdev.man[TTM_PL_VRAM]; args->vram_size = rdev->mc.real_vram_size; args->vram_visible = (u64)man->size << PAGE_SHIFT; - if (rdev->stollen_vga_memory) - args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory); - args->vram_visible -= radeon_fbdev_total_size(rdev); - args->gart_size = rdev->mc.gtt_size - 4096 - RADEON_IB_POOL_SIZE*64*1024; - for(i = 0; i < RADEON_NUM_RINGS; ++i) - args->gart_size -= rdev->ring[i].ring_size; + args->vram_visible -= rdev->vram_pin_size; + args->gart_size = rdev->mc.gtt_size; + args->gart_size -= rdev->gart_pin_size; + return 0; } @@ -252,8 +255,8 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, /* create a gem object to contain this object in */ args->size = roundup(args->size, PAGE_SIZE); r = radeon_gem_object_create(rdev, args->size, args->alignment, - args->initial_domain, false, - false, &gobj); + args->initial_domain, args->flags, + false, &gobj); if (r) { up_read(&rdev->exclusive_lock); r = radeon_gem_handle_lockup(rdev, r); @@ -272,6 +275,94 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, return 0; } +int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_radeon_gem_userptr *args = data; + struct drm_gem_object *gobj; + struct radeon_bo *bo; + uint32_t handle; + int r; + + if (offset_in_page(args->addr | args->size)) + return -EINVAL; + + /* reject unknown flag values */ + if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | + RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE | + RADEON_GEM_USERPTR_REGISTER)) + return -EINVAL; + + if (args->flags & RADEON_GEM_USERPTR_READONLY) { + /* readonly pages not tested on older hardware */ + if (rdev->family < CHIP_R600) + return -EINVAL; + + } else if (!(args->flags & RADEON_GEM_USERPTR_ANONONLY) || + !(args->flags & RADEON_GEM_USERPTR_REGISTER)) { + + /* if we want to write to it we must require anonymous + memory and install a MMU notifier */ + return -EACCES; + } + + down_read(&rdev->exclusive_lock); + + /* create a gem object to contain this object in */ + r = radeon_gem_object_create(rdev, args->size, 0, + RADEON_GEM_DOMAIN_CPU, 0, + false, &gobj); + if (r) + goto handle_lockup; + + bo = gem_to_radeon_bo(gobj); + r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags); + if (r) + goto release_object; + + if (args->flags & RADEON_GEM_USERPTR_REGISTER) { + r = radeon_mn_register(bo, args->addr); + if (r) + goto release_object; + } + + if (args->flags & RADEON_GEM_USERPTR_VALIDATE) { + down_read(¤t->mm->mmap_sem); + r = radeon_bo_reserve(bo, true); + if (r) { + up_read(¤t->mm->mmap_sem); + goto release_object; + } + + radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_GTT); + r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); + radeon_bo_unreserve(bo); + up_read(¤t->mm->mmap_sem); + if (r) + goto release_object; + } + + r = drm_gem_handle_create(filp, gobj, &handle); + /* drop reference from allocate - handle holds it now */ + drm_gem_object_unreference_unlocked(gobj); + if (r) + goto handle_lockup; + + args->handle = handle; + up_read(&rdev->exclusive_lock); + return 0; + +release_object: + drm_gem_object_unreference_unlocked(gobj); + +handle_lockup: + up_read(&rdev->exclusive_lock); + r = radeon_gem_handle_lockup(rdev, r); + + return r; +} + int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { @@ -315,6 +406,10 @@ int radeon_mode_dumb_mmap(struct drm_file *filp, return -ENOENT; } robj = gem_to_radeon_bo(gobj); + if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) { + drm_gem_object_unreference_unlocked(gobj); + return -EPERM; + } *offset_p = radeon_bo_mmap_offset(robj); drm_gem_object_unreference_unlocked(gobj); return 0; @@ -357,17 +452,26 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_radeon_gem_wait_idle *args = data; struct drm_gem_object *gobj; struct radeon_bo *robj; - int r; + int r = 0; + uint32_t cur_placement = 0; + long ret; gobj = drm_gem_object_lookup(dev, filp, args->handle); if (gobj == NULL) { return -ENOENT; } robj = gem_to_radeon_bo(gobj); - r = radeon_bo_wait(robj, NULL, false); - /* callback hw specific functions if any */ - if (rdev->asic->ioctl_wait_idle) - robj->rdev->asic->ioctl_wait_idle(rdev, robj); + + ret = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, 30 * HZ); + if (ret == 0) + r = -EBUSY; + else if (ret < 0) + r = ret; + + /* Flush HDP cache via MMIO if necessary */ + if (rdev->asic->mmio_hdp_flush && + radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM) + robj->rdev->asic->mmio_hdp_flush(rdev); drm_gem_object_unreference_unlocked(gobj); r = radeon_gem_handle_lockup(rdev, r); return r; @@ -461,11 +565,6 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } - if (!(args->flags & RADEON_VM_PAGE_SNOOPED)) { - dev_err(&dev->pdev->dev, "only supported snooped mapping for now\n"); - args->operation = RADEON_VA_RESULT_ERROR; - return -EINVAL; - } switch (args->operation) { case RADEON_VA_MAP: @@ -499,9 +598,9 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, switch (args->operation) { case RADEON_VA_MAP: - if (bo_va->soffset) { + if (bo_va->it.start) { args->operation = RADEON_VA_RESULT_VA_EXIST; - args->offset = bo_va->soffset; + args->offset = bo_va->it.start * RADEON_GPU_PAGE_SIZE; goto out; } r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags); @@ -535,6 +634,11 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data, return -ENOENT; } robj = gem_to_radeon_bo(gobj); + + r = -EPERM; + if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) + goto out; + r = radeon_bo_reserve(robj, false); if (unlikely(r)) goto out; @@ -572,9 +676,8 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, args->size = ALIGN(args->size, PAGE_SIZE); r = radeon_gem_object_create(rdev, args->size, 0, - RADEON_GEM_DOMAIN_VRAM, - false, ttm_bo_type_device, - &gobj); + RADEON_GEM_DOMAIN_VRAM, 0, + false, &gobj); if (r) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/radeon_ib.c b/drivers/gpu/drm/radeon/radeon_ib.c new file mode 100644 index 000000000000..3f39fcca4d07 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_ib.c @@ -0,0 +1,321 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + * Christian König + */ +#include <drm/drmP.h> +#include "radeon.h" + +/* + * IB + * IBs (Indirect Buffers) and areas of GPU accessible memory where + * commands are stored. You can put a pointer to the IB in the + * command ring and the hw will fetch the commands from the IB + * and execute them. Generally userspace acceleration drivers + * produce command buffers which are send to the kernel and + * put in IBs for execution by the requested ring. + */ +static int radeon_debugfs_sa_init(struct radeon_device *rdev); + +/** + * radeon_ib_get - request an IB (Indirect Buffer) + * + * @rdev: radeon_device pointer + * @ring: ring index the IB is associated with + * @ib: IB object returned + * @size: requested IB size + * + * Request an IB (all asics). IBs are allocated using the + * suballocator. + * Returns 0 on success, error on failure. + */ +int radeon_ib_get(struct radeon_device *rdev, int ring, + struct radeon_ib *ib, struct radeon_vm *vm, + unsigned size) +{ + int r; + + r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256); + if (r) { + dev_err(rdev->dev, "failed to get a new IB (%d)\n", r); + return r; + } + + r = radeon_semaphore_create(rdev, &ib->semaphore); + if (r) { + return r; + } + + ib->ring = ring; + ib->fence = NULL; + ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); + ib->vm = vm; + if (vm) { + /* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address + * space and soffset is the offset inside the pool bo + */ + ib->gpu_addr = ib->sa_bo->soffset + RADEON_VA_IB_OFFSET; + } else { + ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); + } + ib->is_const_ib = false; + + return 0; +} + +/** + * radeon_ib_free - free an IB (Indirect Buffer) + * + * @rdev: radeon_device pointer + * @ib: IB object to free + * + * Free an IB (all asics). + */ +void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) +{ + radeon_semaphore_free(rdev, &ib->semaphore, ib->fence); + radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence); + radeon_fence_unref(&ib->fence); +} + +/** + * radeon_ib_schedule - schedule an IB (Indirect Buffer) on the ring + * + * @rdev: radeon_device pointer + * @ib: IB object to schedule + * @const_ib: Const IB to schedule (SI only) + * @hdp_flush: Whether or not to perform an HDP cache flush + * + * Schedule an IB on the associated ring (all asics). + * Returns 0 on success, error on failure. + * + * On SI, there are two parallel engines fed from the primary ring, + * the CE (Constant Engine) and the DE (Drawing Engine). Since + * resource descriptors have moved to memory, the CE allows you to + * prime the caches while the DE is updating register state so that + * the resource descriptors will be already in cache when the draw is + * processed. To accomplish this, the userspace driver submits two + * IBs, one for the CE and one for the DE. If there is a CE IB (called + * a CONST_IB), it will be put on the ring prior to the DE IB. Prior + * to SI there was just a DE IB. + */ +int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, + struct radeon_ib *const_ib, bool hdp_flush) +{ + struct radeon_ring *ring = &rdev->ring[ib->ring]; + int r = 0; + + if (!ib->length_dw || !ring->ready) { + /* TODO: Nothings in the ib we should report. */ + dev_err(rdev->dev, "couldn't schedule ib\n"); + return -EINVAL; + } + + /* 64 dwords should be enough for fence too */ + r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8); + if (r) { + dev_err(rdev->dev, "scheduling IB failed (%d).\n", r); + return r; + } + + /* grab a vm id if necessary */ + if (ib->vm) { + struct radeon_fence *vm_id_fence; + vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring); + radeon_semaphore_sync_fence(ib->semaphore, vm_id_fence); + } + + /* sync with other rings */ + r = radeon_semaphore_sync_rings(rdev, ib->semaphore, ib->ring); + if (r) { + dev_err(rdev->dev, "failed to sync rings (%d)\n", r); + radeon_ring_unlock_undo(rdev, ring); + return r; + } + + if (ib->vm) + radeon_vm_flush(rdev, ib->vm, ib->ring); + + if (const_ib) { + radeon_ring_ib_execute(rdev, const_ib->ring, const_ib); + radeon_semaphore_free(rdev, &const_ib->semaphore, NULL); + } + radeon_ring_ib_execute(rdev, ib->ring, ib); + r = radeon_fence_emit(rdev, &ib->fence, ib->ring); + if (r) { + dev_err(rdev->dev, "failed to emit fence for new IB (%d)\n", r); + radeon_ring_unlock_undo(rdev, ring); + return r; + } + if (const_ib) { + const_ib->fence = radeon_fence_ref(ib->fence); + } + + if (ib->vm) + radeon_vm_fence(rdev, ib->vm, ib->fence); + + radeon_ring_unlock_commit(rdev, ring, hdp_flush); + return 0; +} + +/** + * radeon_ib_pool_init - Init the IB (Indirect Buffer) pool + * + * @rdev: radeon_device pointer + * + * Initialize the suballocator to manage a pool of memory + * for use as IBs (all asics). + * Returns 0 on success, error on failure. + */ +int radeon_ib_pool_init(struct radeon_device *rdev) +{ + int r; + + if (rdev->ib_pool_ready) { + return 0; + } + + if (rdev->family >= CHIP_BONAIRE) { + 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, + RADEON_GEM_GTT_WC); + } else { + /* Before CIK, it's better to stick to cacheable GTT due + * to the command stream checking + */ + 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, 0); + } + if (r) { + return r; + } + + r = radeon_sa_bo_manager_start(rdev, &rdev->ring_tmp_bo); + if (r) { + return r; + } + + rdev->ib_pool_ready = true; + if (radeon_debugfs_sa_init(rdev)) { + dev_err(rdev->dev, "failed to register debugfs file for SA\n"); + } + return 0; +} + +/** + * radeon_ib_pool_fini - Free the IB (Indirect Buffer) pool + * + * @rdev: radeon_device pointer + * + * Tear down the suballocator managing the pool of memory + * for use as IBs (all asics). + */ +void radeon_ib_pool_fini(struct radeon_device *rdev) +{ + if (rdev->ib_pool_ready) { + radeon_sa_bo_manager_suspend(rdev, &rdev->ring_tmp_bo); + radeon_sa_bo_manager_fini(rdev, &rdev->ring_tmp_bo); + rdev->ib_pool_ready = false; + } +} + +/** + * radeon_ib_ring_tests - test IBs on the rings + * + * @rdev: radeon_device pointer + * + * Test an IB (Indirect Buffer) on each ring. + * If the test fails, disable the ring. + * Returns 0 on success, error if the primary GFX ring + * IB test fails. + */ +int radeon_ib_ring_tests(struct radeon_device *rdev) +{ + unsigned i; + int r; + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + struct radeon_ring *ring = &rdev->ring[i]; + + if (!ring->ready) + continue; + + r = radeon_ib_test(rdev, i, ring); + if (r) { + radeon_fence_driver_force_completion(rdev, i); + ring->ready = false; + rdev->needs_reset = false; + + if (i == RADEON_RING_TYPE_GFX_INDEX) { + /* oh, oh, that's really bad */ + DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); + rdev->accel_working = false; + return r; + + } else { + /* still not good, but we can live with it */ + DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); + } + } + } + return 0; +} + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) + +static int radeon_debugfs_sa_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + + radeon_sa_bo_dump_debug_info(&rdev->ring_tmp_bo, m); + + return 0; + +} + +static struct drm_info_list radeon_debugfs_sa_list[] = { + {"radeon_sa_info", &radeon_debugfs_sa_info, 0, NULL}, +}; + +#endif + +static int radeon_debugfs_sa_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); +#else + return 0; +#endif +} diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 16807afab362..7784911d78ef 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -88,23 +88,6 @@ static void radeon_hotplug_work_func(struct work_struct *work) } /** - * radeon_irq_reset_work_func - execute gpu reset - * - * @work: work struct - * - * Execute scheduled gpu reset (cayman+). - * This function is called when the irq handler - * thinks we need a gpu reset. - */ -static void radeon_irq_reset_work_func(struct work_struct *work) -{ - struct radeon_device *rdev = container_of(work, struct radeon_device, - reset_work); - - radeon_gpu_reset(rdev); -} - -/** * radeon_driver_irq_preinstall_kms - drm irq preinstall callback * * @dev: drm dev pointer @@ -284,7 +267,6 @@ int radeon_irq_kms_init(struct radeon_device *rdev) 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); rdev->irq.installed = true; r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); @@ -342,6 +324,21 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring) } /** + * radeon_irq_kms_sw_irq_get_delayed - enable software interrupt + * + * @rdev: radeon device pointer + * @ring: ring whose interrupt you want to enable + * + * Enables the software interrupt for a specific ring (all asics). + * The software interrupt is generally used to signal a fence on + * a particular ring. + */ +bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring) +{ + return atomic_inc_return(&rdev->irq.ring_int[ring]) == 1; +} + +/** * radeon_irq_kms_sw_irq_put - disable software interrupt * * @rdev: radeon device pointer diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index d25ae6acfd5a..8309b11e674d 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -254,7 +254,18 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file } break; case RADEON_INFO_ACCEL_WORKING2: - *value = rdev->accel_working; + if (rdev->family == CHIP_HAWAII) { + if (rdev->accel_working) { + if (rdev->new_fw) + *value = 3; + else + *value = 2; + } else { + *value = 0; + } + } else { + *value = rdev->accel_working; + } break; case RADEON_INFO_TILING_CONFIG: if (rdev->family >= CHIP_BONAIRE) @@ -874,5 +885,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = { DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_USERPTR, radeon_gem_userptr_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c new file mode 100644 index 000000000000..a69bd441dd2d --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_mn.c @@ -0,0 +1,274 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: + * Christian König <christian.koenig@amd.com> + */ + +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/mmu_notifier.h> +#include <drm/drmP.h> +#include <drm/drm.h> + +#include "radeon.h" + +struct radeon_mn { + /* constant after initialisation */ + struct radeon_device *rdev; + struct mm_struct *mm; + struct mmu_notifier mn; + + /* only used on destruction */ + struct work_struct work; + + /* protected by rdev->mn_lock */ + struct hlist_node node; + + /* objects protected by lock */ + struct mutex lock; + struct rb_root objects; +}; + +/** + * radeon_mn_destroy - destroy the rmn + * + * @work: previously sheduled work item + * + * Lazy destroys the notifier from a work item + */ +static void radeon_mn_destroy(struct work_struct *work) +{ + struct radeon_mn *rmn = container_of(work, struct radeon_mn, work); + struct radeon_device *rdev = rmn->rdev; + struct radeon_bo *bo, *next; + + mutex_lock(&rdev->mn_lock); + mutex_lock(&rmn->lock); + hash_del(&rmn->node); + rbtree_postorder_for_each_entry_safe(bo, next, &rmn->objects, mn_it.rb) { + interval_tree_remove(&bo->mn_it, &rmn->objects); + bo->mn = NULL; + } + mutex_unlock(&rmn->lock); + mutex_unlock(&rdev->mn_lock); + mmu_notifier_unregister(&rmn->mn, rmn->mm); + kfree(rmn); +} + +/** + * radeon_mn_release - callback to notify about mm destruction + * + * @mn: our notifier + * @mn: the mm this callback is about + * + * Shedule a work item to lazy destroy our notifier. + */ +static void radeon_mn_release(struct mmu_notifier *mn, + struct mm_struct *mm) +{ + struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn); + INIT_WORK(&rmn->work, radeon_mn_destroy); + schedule_work(&rmn->work); +} + +/** + * radeon_mn_invalidate_range_start - callback to notify about mm change + * + * @mn: our notifier + * @mn: the mm this callback is about + * @start: start of updated range + * @end: end of updated range + * + * We block for all BOs between start and end to be idle and + * unmap them by move them into system domain again. + */ +static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn); + struct interval_tree_node *it; + + /* notification is exclusive, but interval is inclusive */ + end -= 1; + + mutex_lock(&rmn->lock); + + it = interval_tree_iter_first(&rmn->objects, start, end); + while (it) { + struct radeon_bo *bo; + struct fence *fence; + int r; + + bo = container_of(it, struct radeon_bo, mn_it); + it = interval_tree_iter_next(it, start, end); + + r = radeon_bo_reserve(bo, true); + if (r) { + DRM_ERROR("(%d) failed to reserve user bo\n", r); + continue; + } + + fence = reservation_object_get_excl(bo->tbo.resv); + if (fence) { + r = radeon_fence_wait((struct radeon_fence *)fence, false); + if (r) + DRM_ERROR("(%d) failed to wait for user bo\n", r); + } + + radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU); + r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); + if (r) + DRM_ERROR("(%d) failed to validate user bo\n", r); + + radeon_bo_unreserve(bo); + } + + mutex_unlock(&rmn->lock); +} + +static const struct mmu_notifier_ops radeon_mn_ops = { + .release = radeon_mn_release, + .invalidate_range_start = radeon_mn_invalidate_range_start, +}; + +/** + * radeon_mn_get - create notifier context + * + * @rdev: radeon device pointer + * + * Creates a notifier context for current->mm. + */ +static struct radeon_mn *radeon_mn_get(struct radeon_device *rdev) +{ + struct mm_struct *mm = current->mm; + struct radeon_mn *rmn; + int r; + + down_write(&mm->mmap_sem); + mutex_lock(&rdev->mn_lock); + + hash_for_each_possible(rdev->mn_hash, rmn, node, (unsigned long)mm) + if (rmn->mm == mm) + goto release_locks; + + rmn = kzalloc(sizeof(*rmn), GFP_KERNEL); + if (!rmn) { + rmn = ERR_PTR(-ENOMEM); + goto release_locks; + } + + rmn->rdev = rdev; + rmn->mm = mm; + rmn->mn.ops = &radeon_mn_ops; + mutex_init(&rmn->lock); + rmn->objects = RB_ROOT; + + r = __mmu_notifier_register(&rmn->mn, mm); + if (r) + goto free_rmn; + + hash_add(rdev->mn_hash, &rmn->node, (unsigned long)mm); + +release_locks: + mutex_unlock(&rdev->mn_lock); + up_write(&mm->mmap_sem); + + return rmn; + +free_rmn: + mutex_unlock(&rdev->mn_lock); + up_write(&mm->mmap_sem); + kfree(rmn); + + return ERR_PTR(r); +} + +/** + * radeon_mn_register - register a BO for notifier updates + * + * @bo: radeon buffer object + * @addr: userptr addr we should monitor + * + * Registers an MMU notifier for the given BO at the specified address. + * Returns 0 on success, -ERRNO if anything goes wrong. + */ +int radeon_mn_register(struct radeon_bo *bo, unsigned long addr) +{ + unsigned long end = addr + radeon_bo_size(bo) - 1; + struct radeon_device *rdev = bo->rdev; + struct radeon_mn *rmn; + struct interval_tree_node *it; + + rmn = radeon_mn_get(rdev); + if (IS_ERR(rmn)) + return PTR_ERR(rmn); + + mutex_lock(&rmn->lock); + + it = interval_tree_iter_first(&rmn->objects, addr, end); + if (it) { + mutex_unlock(&rmn->lock); + return -EEXIST; + } + + bo->mn = rmn; + bo->mn_it.start = addr; + bo->mn_it.last = end; + interval_tree_insert(&bo->mn_it, &rmn->objects); + + mutex_unlock(&rmn->lock); + + return 0; +} + +/** + * radeon_mn_unregister - unregister a BO for notifier updates + * + * @bo: radeon buffer object + * + * Remove any registration of MMU notifier updates from the buffer object. + */ +void radeon_mn_unregister(struct radeon_bo *bo) +{ + struct radeon_device *rdev = bo->rdev; + struct radeon_mn *rmn; + + mutex_lock(&rdev->mn_lock); + rmn = bo->mn; + if (rmn == NULL) { + mutex_unlock(&rdev->mn_lock); + return; + } + + mutex_lock(&rmn->lock); + interval_tree_remove(&bo->mn_it, &rmn->objects); + bo->mn = NULL; + mutex_unlock(&rmn->lock); + mutex_unlock(&rdev->mn_lock); +} diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 0592ddb0904b..04db2fdd8692 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -685,10 +685,11 @@ extern bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder, extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder); extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector); -extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector); extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector); extern int radeon_get_monitor_bpc(struct drm_connector *connector); +extern struct edid *radeon_connector_edid(struct drm_connector *connector); + extern void radeon_connector_hotplug(struct drm_connector *connector); extern int radeon_dp_mode_valid_helper(struct drm_connector *connector, struct drm_display_mode *mode); @@ -738,7 +739,6 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux); -extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); @@ -777,6 +777,7 @@ extern void atombios_digital_setup(struct drm_encoder *encoder, int action); extern int atombios_get_encoder_mode(struct drm_encoder *encoder); extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action); extern void radeon_encoder_set_active_device(struct drm_encoder *encoder); +extern bool radeon_encoder_is_digital(struct drm_encoder *encoder); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 6c717b257d6d..99a960a4f302 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -46,16 +46,6 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo); * function are calling it. */ -static void radeon_bo_clear_va(struct radeon_bo *bo) -{ - struct radeon_bo_va *bo_va, *tmp; - - list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) { - /* remove from all vm address space */ - radeon_vm_bo_rmv(bo->rdev, bo_va); - } -} - static void radeon_update_memory_usage(struct radeon_bo *bo, unsigned mem_type, int sign) { @@ -85,12 +75,13 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo) bo = container_of(tbo, struct radeon_bo, tbo); radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1); + radeon_mn_unregister(bo); mutex_lock(&bo->rdev->gem.mutex); list_del_init(&bo->list); mutex_unlock(&bo->rdev->gem.mutex); radeon_bo_clear_surface_reg(bo); - radeon_bo_clear_va(bo); + WARN_ON(!list_empty(&bo->va)); drm_gem_object_release(&bo->gem_base); kfree(bo); } @@ -106,47 +97,80 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) { u32 c = 0, i; - rbo->placement.fpfn = 0; - rbo->placement.lpfn = 0; rbo->placement.placement = rbo->placements; rbo->placement.busy_placement = rbo->placements; if (domain & RADEON_GEM_DOMAIN_VRAM) - rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_VRAM; + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_VRAM; + if (domain & RADEON_GEM_DOMAIN_GTT) { - if (rbo->rdev->flags & RADEON_IS_AGP) { - rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT; + if (rbo->flags & RADEON_GEM_GTT_UC) { + rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_TT; + + } else if ((rbo->flags & RADEON_GEM_GTT_WC) || + (rbo->rdev->flags & RADEON_IS_AGP)) { + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_TT; } else { - rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT; + rbo->placements[c++].flags = TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_TT; } } + if (domain & RADEON_GEM_DOMAIN_CPU) { - if (rbo->rdev->flags & RADEON_IS_AGP) { - rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_SYSTEM; + if (rbo->flags & RADEON_GEM_GTT_UC) { + rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_SYSTEM; + + } else if ((rbo->flags & RADEON_GEM_GTT_WC) || + rbo->rdev->flags & RADEON_IS_AGP) { + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_SYSTEM; } else { - rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; + rbo->placements[c++].flags = TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_SYSTEM; } } if (!c) - rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + rbo->placements[c++].flags = TTM_PL_MASK_CACHING | + TTM_PL_FLAG_SYSTEM; + rbo->placement.num_placement = c; rbo->placement.num_busy_placement = c; + for (i = 0; i < c; ++i) { + rbo->placements[i].fpfn = 0; + if ((rbo->flags & RADEON_GEM_CPU_ACCESS) && + (rbo->placements[i].flags & TTM_PL_FLAG_VRAM)) + rbo->placements[i].lpfn = + rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + else + rbo->placements[i].lpfn = 0; + } + /* * Use two-ended allocation depending on the buffer size to * improve fragmentation quality. * 512kb was measured as the most optimal number. */ - if (rbo->tbo.mem.size > 512 * 1024) { + if (!((rbo->flags & RADEON_GEM_CPU_ACCESS) && + (rbo->placements[i].flags & TTM_PL_FLAG_VRAM)) && + rbo->tbo.mem.size > 512 * 1024) { for (i = 0; i < c; i++) { - rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN; + rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN; } } } int radeon_bo_create(struct radeon_device *rdev, - unsigned long size, int byte_align, bool kernel, u32 domain, - struct sg_table *sg, struct radeon_bo **bo_ptr) + unsigned long size, int byte_align, bool kernel, + u32 domain, u32 flags, struct sg_table *sg, + struct reservation_object *resv, + struct radeon_bo **bo_ptr) { struct radeon_bo *bo; enum ttm_bo_type type; @@ -183,12 +207,18 @@ int radeon_bo_create(struct radeon_device *rdev, bo->initial_domain = domain & (RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_CPU); + + bo->flags = flags; + /* PCI GART is always snooped */ + if (!(rdev->flags & RADEON_IS_PCIE)) + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); + radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ down_read(&rdev->pm.mclk_lock); r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, &bo->placement, page_align, !kernel, NULL, - acc_size, sg, &radeon_ttm_bo_destroy); + acc_size, sg, resv, &radeon_ttm_bo_destroy); up_read(&rdev->pm.mclk_lock); if (unlikely(r != 0)) { return r; @@ -232,6 +262,15 @@ void radeon_bo_kunmap(struct radeon_bo *bo) ttm_bo_kunmap(&bo->kmap); } +struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo) +{ + if (bo == NULL) + return NULL; + + ttm_bo_reference(&bo->tbo); + return bo; +} + void radeon_bo_unref(struct radeon_bo **bo) { struct ttm_buffer_object *tbo; @@ -241,9 +280,7 @@ void radeon_bo_unref(struct radeon_bo **bo) return; rdev = (*bo)->rdev; tbo = &((*bo)->tbo); - down_read(&rdev->pm.mclk_lock); ttm_bo_unref(&tbo); - up_read(&rdev->pm.mclk_lock); if (tbo == NULL) *bo = NULL; } @@ -253,6 +290,9 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, { int r, i; + if (radeon_ttm_tt_has_userptr(bo->tbo.ttm)) + return -EPERM; + if (bo->pin_count) { bo->pin_count++; if (gpu_addr) @@ -272,29 +312,31 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, return 0; } radeon_ttm_placement_from_domain(bo, domain); - if (domain == RADEON_GEM_DOMAIN_VRAM) { + for (i = 0; i < bo->placement.num_placement; i++) { /* force to pin into visible video ram */ - bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; - } - if (max_offset) { - u64 lpfn = max_offset >> PAGE_SHIFT; - - if (!bo->placement.lpfn) - bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT; + if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) && + !(bo->flags & RADEON_GEM_NO_CPU_ACCESS) && + (!max_offset || max_offset > bo->rdev->mc.visible_vram_size)) + bo->placements[i].lpfn = + bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + else + bo->placements[i].lpfn = max_offset >> PAGE_SHIFT; - if (lpfn < bo->placement.lpfn) - bo->placement.lpfn = lpfn; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; } - for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); if (likely(r == 0)) { bo->pin_count = 1; if (gpu_addr != NULL) *gpu_addr = radeon_bo_gpu_offset(bo); - } - if (unlikely(r != 0)) + if (domain == RADEON_GEM_DOMAIN_VRAM) + bo->rdev->vram_pin_size += radeon_bo_size(bo); + else + bo->rdev->gart_pin_size += radeon_bo_size(bo); + } else { dev_err(bo->rdev->dev, "%p pin failed\n", bo); + } return r; } @@ -314,11 +356,19 @@ int radeon_bo_unpin(struct radeon_bo *bo) bo->pin_count--; if (bo->pin_count) return 0; - for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + for (i = 0; i < bo->placement.num_placement; i++) { + bo->placements[i].lpfn = 0; + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; + } r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); - if (unlikely(r != 0)) + if (likely(r == 0)) { + if (bo->tbo.mem.mem_type == TTM_PL_VRAM) + bo->rdev->vram_pin_size -= radeon_bo_size(bo); + else + bo->rdev->gart_pin_size -= radeon_bo_size(bo); + } else { dev_err(bo->rdev->dev, "%p validate failed for unpin\n", bo); + } return r; } @@ -438,7 +488,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, u64 bytes_moved = 0, initial_bytes_moved; u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev); - r = ttm_eu_reserve_buffers(ticket, head); + r = ttm_eu_reserve_buffers(ticket, head, true); if (unlikely(r != 0)) { return r; } @@ -447,6 +497,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, bo = lobj->robj; if (!bo->pin_count) { u32 domain = lobj->prefered_domains; + u32 allowed = lobj->allowed_domains; u32 current_domain = radeon_mem_type_to_domain(bo->tbo.mem.mem_type); @@ -458,7 +509,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, * into account. We don't want to disallow buffer moves * completely. */ - if ((lobj->allowed_domains & current_domain) != 0 && + if ((allowed & current_domain) != 0 && (domain & current_domain) == 0 && /* will be moved */ bytes_moved > bytes_moved_threshold) { /* don't move it */ @@ -468,7 +519,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, retry: radeon_ttm_placement_from_domain(bo, domain); if (ring == R600_RING_TYPE_UVD_INDEX) - radeon_uvd_force_into_uvd_segment(bo); + radeon_uvd_force_into_uvd_segment(bo, allowed); initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved); r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); @@ -710,7 +761,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) /* hurrah the memory is not visible ! */ radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); - rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; + rbo->placements[0].lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; r = ttm_bo_validate(bo, &rbo->placement, false, false); if (unlikely(r == -ENOMEM)) { radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); @@ -734,12 +785,10 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait) r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL); if (unlikely(r != 0)) return r; - spin_lock(&bo->tbo.bdev->fence_lock); if (mem_type) *mem_type = bo->tbo.mem.mem_type; - if (bo->tbo.sync_obj) - r = ttm_bo_wait(&bo->tbo, true, true, no_wait); - spin_unlock(&bo->tbo.bdev->fence_lock); + + r = ttm_bo_wait(&bo->tbo, true, true, no_wait); ttm_bo_unreserve(&bo->tbo); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 5a873f31a171..1b8ec7917154 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -124,11 +124,13 @@ extern int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, extern int radeon_bo_create(struct radeon_device *rdev, unsigned long size, int byte_align, - bool kernel, u32 domain, + bool kernel, u32 domain, u32 flags, struct sg_table *sg, + struct reservation_object *resv, struct radeon_bo **bo_ptr); extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); +extern struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo); extern void radeon_bo_unref(struct radeon_bo **bo); extern int radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr); extern int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, @@ -170,7 +172,8 @@ 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 align, u32 domain); + unsigned size, u32 align, u32 domain, + u32 flags); 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_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index e447e390d09a..32522cc940a1 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -460,10 +460,6 @@ static ssize_t radeon_get_dpm_state(struct device *dev, struct radeon_device *rdev = ddev->dev_private; enum radeon_pm_state_type pm = rdev->pm.dpm.user_state; - if ((rdev->flags & RADEON_IS_PX) && - (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) - return snprintf(buf, PAGE_SIZE, "off\n"); - return snprintf(buf, PAGE_SIZE, "%s\n", (pm == POWER_STATE_TYPE_BATTERY) ? "battery" : (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance"); @@ -477,11 +473,6 @@ static ssize_t radeon_set_dpm_state(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct radeon_device *rdev = ddev->dev_private; - /* Can't set dpm state when the card is off */ - if ((rdev->flags & RADEON_IS_PX) && - (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) - return -EINVAL; - mutex_lock(&rdev->pm.mutex); if (strncmp("battery", buf, strlen("battery")) == 0) rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; @@ -495,7 +486,12 @@ static ssize_t radeon_set_dpm_state(struct device *dev, goto fail; } mutex_unlock(&rdev->pm.mutex); - radeon_pm_compute_clocks(rdev); + + /* Can't set dpm state when the card is off */ + if (!(rdev->flags & RADEON_IS_PX) || + (ddev->switch_power_state == DRM_SWITCH_POWER_ON)) + radeon_pm_compute_clocks(rdev); + fail: return count; } @@ -1303,10 +1299,6 @@ int radeon_pm_init(struct radeon_device *rdev) case CHIP_RS780: case CHIP_RS880: case CHIP_RV770: - case CHIP_BARTS: - case CHIP_TURKS: - case CHIP_CAICOS: - case CHIP_CAYMAN: /* DPM requires the RLC, RV770+ dGPU requires SMC */ if (!rdev->rlc_fw) rdev->pm.pm_method = PM_METHOD_PROFILE; @@ -1330,6 +1322,10 @@ int radeon_pm_init(struct radeon_device *rdev) case CHIP_PALM: case CHIP_SUMO: case CHIP_SUMO2: + case CHIP_BARTS: + case CHIP_TURKS: + case CHIP_CAICOS: + case CHIP_CAYMAN: case CHIP_ARUBA: case CHIP_TAHITI: case CHIP_PITCAIRN: @@ -1400,9 +1396,7 @@ static void radeon_pm_fini_old(struct radeon_device *rdev) } radeon_hwmon_fini(rdev); - - if (rdev->pm.power_state) - kfree(rdev->pm.power_state); + kfree(rdev->pm.power_state); } static void radeon_pm_fini_dpm(struct radeon_device *rdev) @@ -1421,9 +1415,7 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev) radeon_dpm_fini(rdev); radeon_hwmon_fini(rdev); - - if (rdev->pm.power_state) - kfree(rdev->pm.power_state); + kfree(rdev->pm.power_state); } void radeon_pm_fini(struct radeon_device *rdev) @@ -1564,7 +1556,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) if (rdev->pm.active_crtcs & (1 << crtc)) { vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); if ((vbl_status & DRM_SCANOUTPOS_VALID) && - !(vbl_status & DRM_SCANOUTPOS_INVBL)) + !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK)) in_vbl = false; } } diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c index 28d71070c389..f3609c97496b 100644 --- a/drivers/gpu/drm/radeon/radeon_prime.c +++ b/drivers/gpu/drm/radeon/radeon_prime.c @@ -27,6 +27,7 @@ #include "radeon.h" #include <drm/radeon_drm.h> +#include <linux/dma-buf.h> struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj) { @@ -57,15 +58,18 @@ void radeon_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) } struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev, - size_t size, + struct dma_buf_attachment *attach, struct sg_table *sg) { + struct reservation_object *resv = attach->dmabuf->resv; struct radeon_device *rdev = dev->dev_private; struct radeon_bo *bo; int ret; - ret = radeon_bo_create(rdev, size, PAGE_SIZE, false, - RADEON_GEM_DOMAIN_GTT, sg, &bo); + ww_mutex_lock(&resv->lock, NULL); + ret = radeon_bo_create(rdev, attach->dmabuf->size, PAGE_SIZE, false, + RADEON_GEM_DOMAIN_GTT, 0, sg, resv, &bo); + ww_mutex_unlock(&resv->lock); if (ret) return ERR_PTR(ret); @@ -111,3 +115,13 @@ struct reservation_object *radeon_gem_prime_res_obj(struct drm_gem_object *obj) return bo->tbo.resv; } + +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gobj, + int flags) +{ + struct radeon_bo *bo = gem_to_radeon_bo(gobj); + if (radeon_ttm_tt_has_userptr(bo->tbo.ttm)) + return ERR_PTR(-EPERM); + return drm_gem_prime_export(dev, gobj, flags); +} diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index f8050f5429e2..2456f69efd23 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -26,258 +26,8 @@ * Jerome Glisse * Christian König */ -#include <linux/seq_file.h> -#include <linux/slab.h> #include <drm/drmP.h> -#include <drm/radeon_drm.h> -#include "radeon_reg.h" #include "radeon.h" -#include "atom.h" - -/* - * IB - * IBs (Indirect Buffers) and areas of GPU accessible memory where - * commands are stored. You can put a pointer to the IB in the - * command ring and the hw will fetch the commands from the IB - * and execute them. Generally userspace acceleration drivers - * produce command buffers which are send to the kernel and - * put in IBs for execution by the requested ring. - */ -static int radeon_debugfs_sa_init(struct radeon_device *rdev); - -/** - * radeon_ib_get - request an IB (Indirect Buffer) - * - * @rdev: radeon_device pointer - * @ring: ring index the IB is associated with - * @ib: IB object returned - * @size: requested IB size - * - * Request an IB (all asics). IBs are allocated using the - * suballocator. - * Returns 0 on success, error on failure. - */ -int radeon_ib_get(struct radeon_device *rdev, int ring, - struct radeon_ib *ib, struct radeon_vm *vm, - unsigned size) -{ - int r; - - r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256); - if (r) { - dev_err(rdev->dev, "failed to get a new IB (%d)\n", r); - return r; - } - - r = radeon_semaphore_create(rdev, &ib->semaphore); - if (r) { - return r; - } - - ib->ring = ring; - ib->fence = NULL; - ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); - ib->vm = vm; - if (vm) { - /* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address - * space and soffset is the offset inside the pool bo - */ - ib->gpu_addr = ib->sa_bo->soffset + RADEON_VA_IB_OFFSET; - } else { - ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); - } - ib->is_const_ib = false; - - return 0; -} - -/** - * radeon_ib_free - free an IB (Indirect Buffer) - * - * @rdev: radeon_device pointer - * @ib: IB object to free - * - * Free an IB (all asics). - */ -void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) -{ - radeon_semaphore_free(rdev, &ib->semaphore, ib->fence); - radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence); - radeon_fence_unref(&ib->fence); -} - -/** - * radeon_ib_schedule - schedule an IB (Indirect Buffer) on the ring - * - * @rdev: radeon_device pointer - * @ib: IB object to schedule - * @const_ib: Const IB to schedule (SI only) - * - * Schedule an IB on the associated ring (all asics). - * Returns 0 on success, error on failure. - * - * On SI, there are two parallel engines fed from the primary ring, - * the CE (Constant Engine) and the DE (Drawing Engine). Since - * resource descriptors have moved to memory, the CE allows you to - * prime the caches while the DE is updating register state so that - * the resource descriptors will be already in cache when the draw is - * processed. To accomplish this, the userspace driver submits two - * IBs, one for the CE and one for the DE. If there is a CE IB (called - * a CONST_IB), it will be put on the ring prior to the DE IB. Prior - * to SI there was just a DE IB. - */ -int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, - struct radeon_ib *const_ib) -{ - struct radeon_ring *ring = &rdev->ring[ib->ring]; - int r = 0; - - if (!ib->length_dw || !ring->ready) { - /* TODO: Nothings in the ib we should report. */ - dev_err(rdev->dev, "couldn't schedule ib\n"); - return -EINVAL; - } - - /* 64 dwords should be enough for fence too */ - r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8); - if (r) { - dev_err(rdev->dev, "scheduling IB failed (%d).\n", r); - return r; - } - - /* grab a vm id if necessary */ - if (ib->vm) { - struct radeon_fence *vm_id_fence; - vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring); - radeon_semaphore_sync_to(ib->semaphore, vm_id_fence); - } - - /* sync with other rings */ - r = radeon_semaphore_sync_rings(rdev, ib->semaphore, ib->ring); - if (r) { - dev_err(rdev->dev, "failed to sync rings (%d)\n", r); - radeon_ring_unlock_undo(rdev, ring); - return r; - } - - if (ib->vm) - radeon_vm_flush(rdev, ib->vm, ib->ring); - - if (const_ib) { - radeon_ring_ib_execute(rdev, const_ib->ring, const_ib); - radeon_semaphore_free(rdev, &const_ib->semaphore, NULL); - } - radeon_ring_ib_execute(rdev, ib->ring, ib); - r = radeon_fence_emit(rdev, &ib->fence, ib->ring); - if (r) { - dev_err(rdev->dev, "failed to emit fence for new IB (%d)\n", r); - radeon_ring_unlock_undo(rdev, ring); - return r; - } - if (const_ib) { - const_ib->fence = radeon_fence_ref(ib->fence); - } - - if (ib->vm) - radeon_vm_fence(rdev, ib->vm, ib->fence); - - radeon_ring_unlock_commit(rdev, ring); - return 0; -} - -/** - * radeon_ib_pool_init - Init the IB (Indirect Buffer) pool - * - * @rdev: radeon_device pointer - * - * Initialize the suballocator to manage a pool of memory - * for use as IBs (all asics). - * Returns 0 on success, error on failure. - */ -int radeon_ib_pool_init(struct radeon_device *rdev) -{ - int r; - - if (rdev->ib_pool_ready) { - return 0; - } - 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; - } - - r = radeon_sa_bo_manager_start(rdev, &rdev->ring_tmp_bo); - if (r) { - return r; - } - - rdev->ib_pool_ready = true; - if (radeon_debugfs_sa_init(rdev)) { - dev_err(rdev->dev, "failed to register debugfs file for SA\n"); - } - return 0; -} - -/** - * radeon_ib_pool_fini - Free the IB (Indirect Buffer) pool - * - * @rdev: radeon_device pointer - * - * Tear down the suballocator managing the pool of memory - * for use as IBs (all asics). - */ -void radeon_ib_pool_fini(struct radeon_device *rdev) -{ - if (rdev->ib_pool_ready) { - radeon_sa_bo_manager_suspend(rdev, &rdev->ring_tmp_bo); - radeon_sa_bo_manager_fini(rdev, &rdev->ring_tmp_bo); - rdev->ib_pool_ready = false; - } -} - -/** - * radeon_ib_ring_tests - test IBs on the rings - * - * @rdev: radeon_device pointer - * - * Test an IB (Indirect Buffer) on each ring. - * If the test fails, disable the ring. - * Returns 0 on success, error if the primary GFX ring - * IB test fails. - */ -int radeon_ib_ring_tests(struct radeon_device *rdev) -{ - unsigned i; - int r; - - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - struct radeon_ring *ring = &rdev->ring[i]; - - if (!ring->ready) - continue; - - r = radeon_ib_test(rdev, i, ring); - if (r) { - ring->ready = false; - rdev->needs_reset = false; - - if (i == RADEON_RING_TYPE_GFX_INDEX) { - /* oh, oh, that's really bad */ - DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); - rdev->accel_working = false; - return r; - - } else { - /* still not good, but we can live with it */ - DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); - } - } - } - return 0; -} /* * Rings @@ -295,27 +45,6 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); /** - * radeon_ring_write - write a value to the ring - * - * @ring: radeon_ring structure holding ring information - * @v: dword (dw) value to write - * - * Write a value to the requested ring buffer (all asics). - */ -void radeon_ring_write(struct radeon_ring *ring, uint32_t v) -{ -#if DRM_DEBUG_CODE - if (ring->count_dw <= 0) { - DRM_ERROR("radeon: writing more dwords to the ring than expected!\n"); - } -#endif - ring->ring[ring->wptr++] = v; - ring->wptr &= ring->ptr_mask; - ring->count_dw--; - ring->ring_free_dw--; -} - -/** * radeon_ring_supports_scratch_reg - check if the ring supports * writing to scratch registers * @@ -427,17 +156,29 @@ int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsig * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information + * @hdp_flush: Whether or not to perform an HDP cache flush * * Update the wptr (write pointer) to tell the GPU to * execute new commands on the ring buffer (all asics). */ -void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring) +void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring, + bool hdp_flush) { + /* If we are emitting the HDP flush via the ring buffer, we need to + * do it before padding. + */ + if (hdp_flush && rdev->asic->ring[ring->idx]->hdp_flush) + rdev->asic->ring[ring->idx]->hdp_flush(rdev, ring); /* We pad to match fetch size */ while (ring->wptr & ring->align_mask) { radeon_ring_write(ring, ring->nop); } mb(); + /* If we are emitting the HDP flush via MMIO, we need to do it after + * all CPU writes to VRAM finished. + */ + if (hdp_flush && rdev->asic->mmio_hdp_flush) + rdev->asic->mmio_hdp_flush(rdev); radeon_ring_set_wptr(rdev, ring); } @@ -447,12 +188,14 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring) * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information + * @hdp_flush: Whether or not to perform an HDP cache flush * * Call radeon_ring_commit() then unlock the ring (all asics). */ -void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring) +void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring, + bool hdp_flush) { - radeon_ring_commit(rdev, ring); + radeon_ring_commit(rdev, ring, hdp_flush); mutex_unlock(&rdev->ring_lock); } @@ -571,7 +314,7 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring } /* and then save the content of the ring */ - *data = kmalloc_array(size, sizeof(uint32_t), GFP_KERNEL); + *data = drm_malloc_ab(size, sizeof(uint32_t)); if (!*data) { mutex_unlock(&rdev->ring_lock); return 0; @@ -612,8 +355,8 @@ int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, data[i]); } - radeon_ring_unlock_commit(rdev, ring); - kfree(data); + radeon_ring_unlock_commit(rdev, ring, false); + drm_free_large(data); return 0; } @@ -640,7 +383,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig /* Allocate ring buffer */ if (ring->ring_obj == NULL) { r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, + RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL, &ring->ring_obj); if (r) { dev_err(rdev->dev, "(%d) ring create failed\n", r); @@ -791,22 +534,6 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = { {"radeon_ring_vce2", radeon_debugfs_ring_info, 0, &si_vce2_index}, }; -static int radeon_debugfs_sa_info(struct seq_file *m, void *data) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - struct radeon_device *rdev = dev->dev_private; - - radeon_sa_bo_dump_debug_info(&rdev->ring_tmp_bo, m); - - return 0; - -} - -static struct drm_info_list radeon_debugfs_sa_list[] = { - {"radeon_sa_info", &radeon_debugfs_sa_info, 0, NULL}, -}; - #endif static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) @@ -828,12 +555,3 @@ static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ri #endif return 0; } - -static int radeon_debugfs_sa_init(struct radeon_device *rdev) -{ -#if defined(CONFIG_DEBUG_FS) - return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1); -#else - return 0; -#endif -} diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index adcf3e2f07da..c507896aca45 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 align, u32 domain) + unsigned size, u32 align, u32 domain, u32 flags) { int i, r; @@ -65,7 +65,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, } r = radeon_bo_create(rdev, size, align, true, - domain, NULL, &sa_manager->bo); + domain, flags, NULL, NULL, &sa_manager->bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); return r; diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index dbd6bcde92de..6deb08f045b7 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -34,7 +34,7 @@ int radeon_semaphore_create(struct radeon_device *rdev, struct radeon_semaphore **semaphore) { - uint32_t *cpu_addr; + uint64_t *cpu_addr; int i, r; *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL); @@ -96,15 +96,15 @@ bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx, } /** - * radeon_semaphore_sync_to - use the semaphore to sync to a fence + * radeon_semaphore_sync_fence - use the semaphore to sync to a fence * * @semaphore: semaphore object to add fence to * @fence: fence to sync to * * Sync to the fence using this semaphore object */ -void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore, - struct radeon_fence *fence) +void radeon_semaphore_sync_fence(struct radeon_semaphore *semaphore, + struct radeon_fence *fence) { struct radeon_fence *other; @@ -116,6 +116,53 @@ void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore, } /** + * radeon_semaphore_sync_to - use the semaphore to sync to a reservation object + * + * @sema: semaphore object to add fence from reservation object to + * @resv: reservation object with embedded fence + * @shared: true if we should onyl sync to the exclusive fence + * + * Sync to the fence using this semaphore object + */ +int radeon_semaphore_sync_resv(struct radeon_device *rdev, + struct radeon_semaphore *sema, + struct reservation_object *resv, + bool shared) +{ + struct reservation_object_list *flist; + struct fence *f; + struct radeon_fence *fence; + unsigned i; + int r = 0; + + /* always sync to the exclusive fence */ + f = reservation_object_get_excl(resv); + fence = f ? to_radeon_fence(f) : NULL; + if (fence && fence->rdev == rdev) + radeon_semaphore_sync_fence(sema, fence); + else if (f) + r = fence_wait(f, true); + + flist = reservation_object_get_list(resv); + if (shared || !flist || r) + return r; + + for (i = 0; i < flist->shared_count; ++i) { + f = rcu_dereference_protected(flist->shared[i], + reservation_object_held(resv)); + fence = to_radeon_fence(f); + if (fence && fence->rdev == rdev) + radeon_semaphore_sync_fence(sema, fence); + else + r = fence_wait(f, true); + + if (r) + break; + } + return r; +} + +/** * radeon_semaphore_sync_rings - sync ring to all registered fences * * @rdev: radeon_device pointer @@ -179,7 +226,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev, continue; } - radeon_ring_commit(rdev, &rdev->ring[i]); + radeon_ring_commit(rdev, &rdev->ring[i], false); radeon_fence_note_sync(fence, ring); semaphore->gpu_addr += 8; diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 23bb64fd775f..535403e0c8a2 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -30,9 +30,9 @@ */ #include <drm/drmP.h> -#include <drm/drm_buffer.h> #include <drm/radeon_drm.h> #include "radeon_drv.h" +#include "drm_buffer.h" /* ================================================================ * Helper functions for client state checking and fixup diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 3a13e0d1055c..07b506b41008 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -56,13 +56,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) /* Number of tests = * (Total GTT - IB pool - writeback page - ring buffers) / test size */ - n = rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024; - for (i = 0; i < RADEON_NUM_RINGS; ++i) - n -= rdev->ring[i].ring_size; - if (rdev->wb.wb_obj) - n -= RADEON_GPU_PAGE_SIZE; - if (rdev->ih.ring_obj) - n -= rdev->ih.ring_size; + n = rdev->mc.gtt_size - rdev->gart_pin_size; n /= size; gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); @@ -73,7 +67,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) } r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - NULL, &vram_obj); + 0, NULL, NULL, &vram_obj); if (r) { DRM_ERROR("Failed to create VRAM object\n"); goto out_cleanup; @@ -93,7 +87,8 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) struct radeon_fence *fence = NULL; r = radeon_bo_create(rdev, size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, NULL, gtt_obj + i); + RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL, + gtt_obj + i); if (r) { DRM_ERROR("Failed to create GTT object %d\n", i); goto out_lclean; @@ -122,11 +117,16 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) radeon_bo_kunmap(gtt_obj[i]); if (ring == R600_RING_TYPE_DMA_INDEX) - r = radeon_copy_dma(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence); + fence = radeon_copy_dma(rdev, gtt_addr, vram_addr, + size / RADEON_GPU_PAGE_SIZE, + NULL); else - r = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence); - if (r) { + fence = radeon_copy_blit(rdev, gtt_addr, vram_addr, + size / RADEON_GPU_PAGE_SIZE, + NULL); + if (IS_ERR(fence)) { DRM_ERROR("Failed GTT->VRAM copy %d\n", i); + r = PTR_ERR(fence); goto out_lclean_unpin; } @@ -168,11 +168,16 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) radeon_bo_kunmap(vram_obj); if (ring == R600_RING_TYPE_DMA_INDEX) - r = radeon_copy_dma(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence); + fence = radeon_copy_dma(rdev, vram_addr, gtt_addr, + size / RADEON_GPU_PAGE_SIZE, + NULL); else - r = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence); - if (r) { + fence = radeon_copy_blit(rdev, vram_addr, gtt_addr, + size / RADEON_GPU_PAGE_SIZE, + NULL); + if (IS_ERR(fence)) { DRM_ERROR("Failed VRAM->GTT copy %d\n", i); + r = PTR_ERR(fence); goto out_lclean_unpin; } @@ -228,7 +233,7 @@ out_lclean: radeon_bo_unreserve(gtt_obj[i]); radeon_bo_unref(>t_obj[i]); } - if (fence) + if (fence && !IS_ERR(fence)) radeon_fence_unref(&fence); break; } @@ -294,7 +299,7 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev, return r; } radeon_fence_emit(rdev, fence, ring->idx); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } return 0; } @@ -319,7 +324,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringA); + radeon_ring_unlock_commit(rdev, ringA, false); r = radeon_test_create_and_emit_fence(rdev, ringA, &fence1); if (r) @@ -331,7 +336,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringA); + radeon_ring_unlock_commit(rdev, ringA, false); r = radeon_test_create_and_emit_fence(rdev, ringA, &fence2); if (r) @@ -350,7 +355,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringB); + radeon_ring_unlock_commit(rdev, ringB, false); r = radeon_fence_wait(fence1, false); if (r) { @@ -371,7 +376,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringB); + radeon_ring_unlock_commit(rdev, ringB, false); r = radeon_fence_wait(fence2, false); if (r) { @@ -414,7 +419,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringA); + radeon_ring_unlock_commit(rdev, ringA, false); r = radeon_test_create_and_emit_fence(rdev, ringA, &fenceA); if (r) @@ -426,7 +431,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringB->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringB); + radeon_ring_unlock_commit(rdev, ringB, false); r = radeon_test_create_and_emit_fence(rdev, ringB, &fenceB); if (r) goto out_cleanup; @@ -448,7 +453,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringC); + radeon_ring_unlock_commit(rdev, ringC, false); for (i = 0; i < 30; ++i) { mdelay(100); @@ -474,7 +479,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringC); + radeon_ring_unlock_commit(rdev, ringC, false); mdelay(1000); diff --git a/drivers/gpu/drm/radeon/radeon_trace.h b/drivers/gpu/drm/radeon/radeon_trace.h index f749f2c3bbdb..9db74a96ef61 100644 --- a/drivers/gpu/drm/radeon/radeon_trace.h +++ b/drivers/gpu/drm/radeon/radeon_trace.h @@ -72,8 +72,8 @@ TRACE_EVENT(radeon_vm_bo_update, ), TP_fast_assign( - __entry->soffset = bo_va->soffset; - __entry->eoffset = bo_va->eoffset; + __entry->soffset = bo_va->it.start; + __entry->eoffset = bo_va->it.last + 1; __entry->flags = bo_va->flags; ), TP_printk("soffs=%010llx, eoffs=%010llx, flags=%08x", @@ -104,6 +104,24 @@ TRACE_EVENT(radeon_vm_set_page, __entry->flags, __entry->count) ); +TRACE_EVENT(radeon_vm_flush, + TP_PROTO(uint64_t pd_addr, unsigned ring, unsigned id), + TP_ARGS(pd_addr, ring, id), + TP_STRUCT__entry( + __field(u64, pd_addr) + __field(u32, ring) + __field(u32, id) + ), + + TP_fast_assign( + __entry->pd_addr = pd_addr; + __entry->ring = ring; + __entry->id = id; + ), + TP_printk("pd_addr=%010Lx, ring=%u, id=%u", + __entry->pd_addr, __entry->ring, __entry->id) +); + DECLARE_EVENT_CLASS(radeon_fence_request, TP_PROTO(struct drm_device *dev, int ring, u32 seqno), diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index c8a8a5144ec1..8624979afb65 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -39,6 +39,8 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/swiotlb.h> +#include <linux/swap.h> +#include <linux/pagemap.h> #include <linux/debugfs.h> #include "radeon_reg.h" #include "radeon.h" @@ -176,12 +178,15 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, static void radeon_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { + static struct ttm_place placements = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM + }; + struct radeon_bo *rbo; - static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; if (!radeon_ttm_bo_is_radeon_bo(bo)) { - placement->fpfn = 0; - placement->lpfn = 0; placement->placement = &placements; placement->busy_placement = &placements; placement->num_placement = 1; @@ -228,6 +233,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, struct radeon_device *rdev; uint64_t old_start, new_start; struct radeon_fence *fence; + unsigned num_pages; int r, ridx; rdev = radeon_get_rdev(bo->bdev); @@ -264,13 +270,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0); - /* sync other rings */ - fence = bo->sync_obj; - r = radeon_copy(rdev, old_start, new_start, - new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */ - &fence); - /* FIXME: handle copy error */ - r = ttm_bo_move_accel_cleanup(bo, (void *)fence, + num_pages = new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); + fence = radeon_copy(rdev, old_start, new_start, num_pages, bo->resv); + if (IS_ERR(fence)) + return PTR_ERR(fence); + + r = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, no_wait_gpu, new_mem); radeon_fence_unref(&fence); return r; @@ -284,20 +289,20 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, struct radeon_device *rdev; struct ttm_mem_reg *old_mem = &bo->mem; struct ttm_mem_reg tmp_mem; - u32 placements; + struct ttm_place placements; struct ttm_placement placement; int r; rdev = radeon_get_rdev(bo->bdev); tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - placement.fpfn = 0; - placement.lpfn = 0; placement.num_placement = 1; placement.placement = &placements; placement.num_busy_placement = 1; placement.busy_placement = &placements; - placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; + placements.fpfn = 0; + placements.lpfn = 0; + placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; r = ttm_bo_mem_space(bo, &placement, &tmp_mem, interruptible, no_wait_gpu); if (unlikely(r)) { @@ -332,19 +337,19 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, struct ttm_mem_reg *old_mem = &bo->mem; struct ttm_mem_reg tmp_mem; struct ttm_placement placement; - u32 placements; + struct ttm_place placements; int r; rdev = radeon_get_rdev(bo->bdev); tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - placement.fpfn = 0; - placement.lpfn = 0; placement.num_placement = 1; placement.placement = &placements; placement.num_busy_placement = 1; placement.busy_placement = &placements; - placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; + placements.fpfn = 0; + placements.lpfn = 0; + placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; r = ttm_bo_mem_space(bo, &placement, &tmp_mem, interruptible, no_wait_gpu); if (unlikely(r)) { @@ -483,53 +488,131 @@ static void radeon_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re { } -static int radeon_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible) -{ - return radeon_fence_wait((struct radeon_fence *)sync_obj, interruptible); -} +/* + * TTM backend functions. + */ +struct radeon_ttm_tt { + struct ttm_dma_tt ttm; + struct radeon_device *rdev; + u64 offset; -static int radeon_sync_obj_flush(void *sync_obj) + uint64_t userptr; + struct mm_struct *usermm; + uint32_t userflags; +}; + +/* prepare the sg table with the user pages */ +static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm) { + struct radeon_device *rdev = radeon_get_rdev(ttm->bdev); + struct radeon_ttm_tt *gtt = (void *)ttm; + unsigned pinned = 0, nents; + int r; + + int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY); + enum dma_data_direction direction = write ? + DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + + if (current->mm != gtt->usermm) + return -EPERM; + + if (gtt->userflags & RADEON_GEM_USERPTR_ANONONLY) { + /* check that we only pin down anonymous memory + to prevent problems with writeback */ + unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE; + struct vm_area_struct *vma; + vma = find_vma(gtt->usermm, gtt->userptr); + if (!vma || vma->vm_file || vma->vm_end < end) + return -EPERM; + } + + do { + unsigned num_pages = ttm->num_pages - pinned; + uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE; + struct page **pages = ttm->pages + pinned; + + r = get_user_pages(current, current->mm, userptr, num_pages, + write, 0, pages, NULL); + if (r < 0) + goto release_pages; + + pinned += r; + + } while (pinned < ttm->num_pages); + + r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0, + ttm->num_pages << PAGE_SHIFT, + GFP_KERNEL); + if (r) + goto release_sg; + + r = -ENOMEM; + nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction); + if (nents != ttm->sg->nents) + goto release_sg; + + drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, + gtt->ttm.dma_address, ttm->num_pages); + return 0; -} -static void radeon_sync_obj_unref(void **sync_obj) -{ - radeon_fence_unref((struct radeon_fence **)sync_obj); -} +release_sg: + kfree(ttm->sg); -static void *radeon_sync_obj_ref(void *sync_obj) -{ - return radeon_fence_ref((struct radeon_fence *)sync_obj); +release_pages: + release_pages(ttm->pages, pinned, 0); + return r; } -static bool radeon_sync_obj_signaled(void *sync_obj) +static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) { - return radeon_fence_signaled((struct radeon_fence *)sync_obj); -} + struct radeon_device *rdev = radeon_get_rdev(ttm->bdev); + struct radeon_ttm_tt *gtt = (void *)ttm; + struct scatterlist *sg; + int i; -/* - * TTM backend functions. - */ -struct radeon_ttm_tt { - struct ttm_dma_tt ttm; - struct radeon_device *rdev; - u64 offset; -}; + int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY); + enum dma_data_direction direction = write ? + DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + + /* free the sg table and pages again */ + dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction); + + for_each_sg(ttm->sg->sgl, sg, ttm->sg->nents, i) { + struct page *page = sg_page(sg); + + if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY)) + set_page_dirty(page); + + mark_page_accessed(page); + page_cache_release(page); + } + + sg_free_table(ttm->sg); +} static int radeon_ttm_backend_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) { struct radeon_ttm_tt *gtt = (void*)ttm; + uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ | + RADEON_GART_PAGE_WRITE; int r; + if (gtt->userptr) { + radeon_ttm_tt_pin_userptr(ttm); + flags &= ~RADEON_GART_PAGE_WRITE; + } + gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); if (!ttm->num_pages) { WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", ttm->num_pages, bo_mem, ttm); } - r = radeon_gart_bind(gtt->rdev, gtt->offset, - ttm->num_pages, ttm->pages, gtt->ttm.dma_address); + if (ttm->caching_state == tt_cached) + flags |= RADEON_GART_PAGE_SNOOP; + r = radeon_gart_bind(gtt->rdev, gtt->offset, ttm->num_pages, + ttm->pages, gtt->ttm.dma_address, flags); if (r) { DRM_ERROR("failed to bind %lu pages at 0x%08X\n", ttm->num_pages, (unsigned)gtt->offset); @@ -543,6 +626,10 @@ static int radeon_ttm_backend_unbind(struct ttm_tt *ttm) struct radeon_ttm_tt *gtt = (void *)ttm; radeon_gart_unbind(gtt->rdev, gtt->offset, ttm->num_pages); + + if (gtt->userptr) + radeon_ttm_tt_unpin_userptr(ttm); + return 0; } @@ -588,10 +675,17 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, return >t->ttm.ttm; } +static struct radeon_ttm_tt *radeon_ttm_tt_to_gtt(struct ttm_tt *ttm) +{ + if (!ttm || ttm->func != &radeon_backend_func) + return NULL; + return (struct radeon_ttm_tt *)ttm; +} + static int radeon_ttm_tt_populate(struct ttm_tt *ttm) { + struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm); struct radeon_device *rdev; - struct radeon_ttm_tt *gtt = (void *)ttm; unsigned i; int r; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); @@ -599,6 +693,16 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) if (ttm->state != tt_unpopulated) return 0; + if (gtt && gtt->userptr) { + ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL); + if (!ttm->sg) + return -ENOMEM; + + ttm->page_flags |= TTM_PAGE_FLAG_SG; + ttm->state = tt_unbound; + return 0; + } + if (slave && ttm->sg) { drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, gtt->ttm.dma_address, ttm->num_pages); @@ -644,10 +748,16 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) { struct radeon_device *rdev; - struct radeon_ttm_tt *gtt = (void *)ttm; + struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm); unsigned i; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); + if (gtt && gtt->userptr) { + kfree(ttm->sg); + ttm->page_flags &= ~TTM_PAGE_FLAG_SG; + return; + } + if (slave) return; @@ -676,6 +786,40 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) ttm_pool_unpopulate(ttm); } +int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, + uint32_t flags) +{ + struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm); + + if (gtt == NULL) + return -EINVAL; + + gtt->userptr = addr; + gtt->usermm = current->mm; + gtt->userflags = flags; + return 0; +} + +bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm) +{ + struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm); + + if (gtt == NULL) + return false; + + return !!gtt->userptr; +} + +bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm) +{ + struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm); + + if (gtt == NULL) + return false; + + return !!(gtt->userflags & RADEON_GEM_USERPTR_READONLY); +} + static struct ttm_bo_driver radeon_bo_driver = { .ttm_tt_create = &radeon_ttm_tt_create, .ttm_tt_populate = &radeon_ttm_tt_populate, @@ -685,11 +829,6 @@ static struct ttm_bo_driver radeon_bo_driver = { .evict_flags = &radeon_evict_flags, .move = &radeon_bo_move, .verify_access = &radeon_verify_access, - .sync_obj_signaled = &radeon_sync_obj_signaled, - .sync_obj_wait = &radeon_sync_obj_wait, - .sync_obj_flush = &radeon_sync_obj_flush, - .sync_obj_unref = &radeon_sync_obj_unref, - .sync_obj_ref = &radeon_sync_obj_ref, .move_notify = &radeon_bo_move_notify, .fault_reserve_notify = &radeon_bo_fault_reserve_notify, .io_mem_reserve = &radeon_ttm_io_mem_reserve, @@ -726,7 +865,7 @@ int radeon_ttm_init(struct radeon_device *rdev) radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, + RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, &rdev->stollen_vga_memory); if (r) { return r; @@ -824,7 +963,7 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma) int r; if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) { - return drm_mmap(filp, vma); + return -EINVAL; } file_priv = filp->private_data; diff --git a/drivers/gpu/drm/radeon/radeon_ucode.c b/drivers/gpu/drm/radeon/radeon_ucode.c new file mode 100644 index 000000000000..6beec680390c --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_ucode.c @@ -0,0 +1,167 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <drm/drmP.h> +#include "radeon.h" +#include "radeon_ucode.h" + +static void radeon_ucode_print_common_hdr(const struct common_firmware_header *hdr) +{ + DRM_DEBUG("size_bytes: %u\n", le32_to_cpu(hdr->size_bytes)); + DRM_DEBUG("header_size_bytes: %u\n", le32_to_cpu(hdr->header_size_bytes)); + DRM_DEBUG("header_version_major: %u\n", le16_to_cpu(hdr->header_version_major)); + DRM_DEBUG("header_version_minor: %u\n", le16_to_cpu(hdr->header_version_minor)); + DRM_DEBUG("ip_version_major: %u\n", le16_to_cpu(hdr->ip_version_major)); + DRM_DEBUG("ip_version_minor: %u\n", le16_to_cpu(hdr->ip_version_minor)); + DRM_DEBUG("ucode_version: 0x%08x\n", le32_to_cpu(hdr->ucode_version)); + DRM_DEBUG("ucode_size_bytes: %u\n", le32_to_cpu(hdr->ucode_size_bytes)); + DRM_DEBUG("ucode_array_offset_bytes: %u\n", + le32_to_cpu(hdr->ucode_array_offset_bytes)); + DRM_DEBUG("crc32: 0x%08x\n", le32_to_cpu(hdr->crc32)); +} + +void radeon_ucode_print_mc_hdr(const struct common_firmware_header *hdr) +{ + uint16_t version_major = le16_to_cpu(hdr->header_version_major); + uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); + + DRM_DEBUG("MC\n"); + radeon_ucode_print_common_hdr(hdr); + + if (version_major == 1) { + const struct mc_firmware_header_v1_0 *mc_hdr = + container_of(hdr, struct mc_firmware_header_v1_0, header); + + DRM_DEBUG("io_debug_size_bytes: %u\n", + le32_to_cpu(mc_hdr->io_debug_size_bytes)); + DRM_DEBUG("io_debug_array_offset_bytes: %u\n", + le32_to_cpu(mc_hdr->io_debug_array_offset_bytes)); + } else { + DRM_ERROR("Unknown MC ucode version: %u.%u\n", version_major, version_minor); + } +} + +void radeon_ucode_print_smc_hdr(const struct common_firmware_header *hdr) +{ + uint16_t version_major = le16_to_cpu(hdr->header_version_major); + uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); + + DRM_DEBUG("SMC\n"); + radeon_ucode_print_common_hdr(hdr); + + if (version_major == 1) { + const struct smc_firmware_header_v1_0 *smc_hdr = + container_of(hdr, struct smc_firmware_header_v1_0, header); + + DRM_DEBUG("ucode_start_addr: %u\n", le32_to_cpu(smc_hdr->ucode_start_addr)); + } else { + DRM_ERROR("Unknown SMC ucode version: %u.%u\n", version_major, version_minor); + } +} + +void radeon_ucode_print_gfx_hdr(const struct common_firmware_header *hdr) +{ + uint16_t version_major = le16_to_cpu(hdr->header_version_major); + uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); + + DRM_DEBUG("GFX\n"); + radeon_ucode_print_common_hdr(hdr); + + if (version_major == 1) { + const struct gfx_firmware_header_v1_0 *gfx_hdr = + container_of(hdr, struct gfx_firmware_header_v1_0, header); + + DRM_DEBUG("ucode_feature_version: %u\n", + le32_to_cpu(gfx_hdr->ucode_feature_version)); + DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(gfx_hdr->jt_offset)); + DRM_DEBUG("jt_size: %u\n", le32_to_cpu(gfx_hdr->jt_size)); + } else { + DRM_ERROR("Unknown GFX ucode version: %u.%u\n", version_major, version_minor); + } +} + +void radeon_ucode_print_rlc_hdr(const struct common_firmware_header *hdr) +{ + uint16_t version_major = le16_to_cpu(hdr->header_version_major); + uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); + + DRM_DEBUG("RLC\n"); + radeon_ucode_print_common_hdr(hdr); + + if (version_major == 1) { + const struct rlc_firmware_header_v1_0 *rlc_hdr = + container_of(hdr, struct rlc_firmware_header_v1_0, header); + + DRM_DEBUG("ucode_feature_version: %u\n", + le32_to_cpu(rlc_hdr->ucode_feature_version)); + DRM_DEBUG("save_and_restore_offset: %u\n", + le32_to_cpu(rlc_hdr->save_and_restore_offset)); + DRM_DEBUG("clear_state_descriptor_offset: %u\n", + le32_to_cpu(rlc_hdr->clear_state_descriptor_offset)); + DRM_DEBUG("avail_scratch_ram_locations: %u\n", + le32_to_cpu(rlc_hdr->avail_scratch_ram_locations)); + DRM_DEBUG("master_pkt_description_offset: %u\n", + le32_to_cpu(rlc_hdr->master_pkt_description_offset)); + } else { + DRM_ERROR("Unknown RLC ucode version: %u.%u\n", version_major, version_minor); + } +} + +void radeon_ucode_print_sdma_hdr(const struct common_firmware_header *hdr) +{ + uint16_t version_major = le16_to_cpu(hdr->header_version_major); + uint16_t version_minor = le16_to_cpu(hdr->header_version_minor); + + DRM_DEBUG("SDMA\n"); + radeon_ucode_print_common_hdr(hdr); + + if (version_major == 1) { + const struct sdma_firmware_header_v1_0 *sdma_hdr = + container_of(hdr, struct sdma_firmware_header_v1_0, header); + + DRM_DEBUG("ucode_feature_version: %u\n", + le32_to_cpu(sdma_hdr->ucode_feature_version)); + DRM_DEBUG("ucode_change_version: %u\n", + le32_to_cpu(sdma_hdr->ucode_change_version)); + DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(sdma_hdr->jt_offset)); + DRM_DEBUG("jt_size: %u\n", le32_to_cpu(sdma_hdr->jt_size)); + } else { + DRM_ERROR("Unknown SDMA ucode version: %u.%u\n", + version_major, version_minor); + } +} + +int radeon_ucode_validate(const struct firmware *fw) +{ + const struct common_firmware_header *hdr = + (const struct common_firmware_header *)fw->data; + + if (fw->size == le32_to_cpu(hdr->size_bytes)) + return 0; + + return -EINVAL; +} + diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h index 4e7c3269b183..dc4576e4d8ad 100644 --- a/drivers/gpu/drm/radeon/radeon_ucode.h +++ b/drivers/gpu/drm/radeon/radeon_ucode.h @@ -153,4 +153,75 @@ #define HAWAII_SMC_UCODE_START 0x20000 #define HAWAII_SMC_UCODE_SIZE 0x1FDEC +struct common_firmware_header { + uint32_t size_bytes; /* size of the entire header+image(s) in bytes */ + uint32_t header_size_bytes; /* size of just the header in bytes */ + uint16_t header_version_major; /* header version */ + uint16_t header_version_minor; /* header version */ + uint16_t ip_version_major; /* IP version */ + uint16_t ip_version_minor; /* IP version */ + uint32_t ucode_version; + uint32_t ucode_size_bytes; /* size of ucode in bytes */ + uint32_t ucode_array_offset_bytes; /* payload offset from the start of the header */ + uint32_t crc32; /* crc32 checksum of the payload */ +}; + +/* version_major=1, version_minor=0 */ +struct mc_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t io_debug_size_bytes; /* size of debug array in dwords */ + uint32_t io_debug_array_offset_bytes; /* payload offset from the start of the header */ +}; + +/* version_major=1, version_minor=0 */ +struct smc_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t ucode_start_addr; +}; + +/* version_major=1, version_minor=0 */ +struct gfx_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t ucode_feature_version; + uint32_t jt_offset; /* jt location */ + uint32_t jt_size; /* size of jt */ +}; + +/* version_major=1, version_minor=0 */ +struct rlc_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t ucode_feature_version; + uint32_t save_and_restore_offset; + uint32_t clear_state_descriptor_offset; + uint32_t avail_scratch_ram_locations; + uint32_t master_pkt_description_offset; +}; + +/* version_major=1, version_minor=0 */ +struct sdma_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t ucode_feature_version; + uint32_t ucode_change_version; + uint32_t jt_offset; /* jt location */ + uint32_t jt_size; /* size of jt */ +}; + +/* header is fixed size */ +union radeon_firmware_header { + struct common_firmware_header common; + struct mc_firmware_header_v1_0 mc; + struct smc_firmware_header_v1_0 smc; + struct gfx_firmware_header_v1_0 gfx; + struct rlc_firmware_header_v1_0 rlc; + struct sdma_firmware_header_v1_0 sdma; + uint8_t raw[0x100]; +}; + +void radeon_ucode_print_mc_hdr(const struct common_firmware_header *hdr); +void radeon_ucode_print_smc_hdr(const struct common_firmware_header *hdr); +void radeon_ucode_print_gfx_hdr(const struct common_firmware_header *hdr); +void radeon_ucode_print_rlc_hdr(const struct common_firmware_header *hdr); +void radeon_ucode_print_sdma_hdr(const struct common_firmware_header *hdr); +int radeon_ucode_validate(const struct firmware *fw); + #endif diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index a4ad270e8261..11b662469253 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -40,12 +40,18 @@ #define UVD_IDLE_TIMEOUT_MS 1000 /* Firmware Names */ +#define FIRMWARE_R600 "radeon/R600_uvd.bin" +#define FIRMWARE_RS780 "radeon/RS780_uvd.bin" +#define FIRMWARE_RV770 "radeon/RV770_uvd.bin" #define FIRMWARE_RV710 "radeon/RV710_uvd.bin" #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" #define FIRMWARE_SUMO "radeon/SUMO_uvd.bin" #define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin" #define FIRMWARE_BONAIRE "radeon/BONAIRE_uvd.bin" +MODULE_FIRMWARE(FIRMWARE_R600); +MODULE_FIRMWARE(FIRMWARE_RS780); +MODULE_FIRMWARE(FIRMWARE_RV770); MODULE_FIRMWARE(FIRMWARE_RV710); MODULE_FIRMWARE(FIRMWARE_CYPRESS); MODULE_FIRMWARE(FIRMWARE_SUMO); @@ -63,6 +69,23 @@ int radeon_uvd_init(struct radeon_device *rdev) INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); switch (rdev->family) { + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV670: + case CHIP_RV620: + case CHIP_RV635: + fw_name = FIRMWARE_R600; + break; + + case CHIP_RS780: + case CHIP_RS880: + fw_name = FIRMWARE_RS780; + break; + + case CHIP_RV770: + fw_name = FIRMWARE_RV770; + break; + case CHIP_RV710: case CHIP_RV730: case CHIP_RV740: @@ -115,9 +138,11 @@ int radeon_uvd_init(struct radeon_device *rdev) } bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + - RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE + + RADEON_GPU_PAGE_SIZE; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); + RADEON_GEM_DOMAIN_VRAM, 0, NULL, + NULL, &rdev->uvd.vcpu_bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r); return r; @@ -231,10 +256,30 @@ int radeon_uvd_resume(struct radeon_device *rdev) return 0; } -void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo) +void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, + uint32_t allowed_domains) { - rbo->placement.fpfn = 0 >> PAGE_SHIFT; - rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; + int i; + + for (i = 0; i < rbo->placement.num_placement; ++i) { + rbo->placements[i].fpfn = 0 >> PAGE_SHIFT; + rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; + } + + /* If it must be in VRAM it must be in the first segment as well */ + if (allowed_domains == RADEON_GEM_DOMAIN_VRAM) + return; + + /* abort if we already have more than one placement */ + if (rbo->placement.num_placement > 1) + return; + + /* add another 256MB segment */ + rbo->placements[1] = rbo->placements[0]; + rbo->placements[1].fpfn += (256 * 1024 * 1024) >> PAGE_SHIFT; + rbo->placements[1].lpfn += (256 * 1024 * 1024) >> PAGE_SHIFT; + rbo->placement.num_placement++; + rbo->placement.num_busy_placement++; } void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) @@ -356,6 +401,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, { int32_t *msg, msg_type, handle; unsigned img_size = 0; + struct fence *f; void *ptr; int i, r; @@ -365,8 +411,9 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } - if (bo->tbo.sync_obj) { - r = radeon_fence_wait(bo->tbo.sync_obj, false); + f = reservation_object_get_excl(bo->tbo.resv); + if (f) { + r = radeon_fence_wait((struct radeon_fence *)f, false); if (r) { DRM_ERROR("Failed waiting for UVD message (%d)!\n", r); return r; @@ -604,38 +651,16 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) } static int radeon_uvd_send_msg(struct radeon_device *rdev, - int ring, struct radeon_bo *bo, + int ring, uint64_t addr, struct radeon_fence **fence) { - struct ttm_validate_buffer tv; - struct ww_acquire_ctx ticket; - struct list_head head; struct radeon_ib ib; - uint64_t addr; int i, r; - memset(&tv, 0, sizeof(tv)); - tv.bo = &bo->tbo; - - INIT_LIST_HEAD(&head); - list_add(&tv.head, &head); - - r = ttm_eu_reserve_buffers(&ticket, &head); - if (r) - return r; - - radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM); - radeon_uvd_force_into_uvd_segment(bo); - - r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); - if (r) - goto err; - r = radeon_ib_get(rdev, ring, &ib, NULL, 64); if (r) - goto err; + return r; - addr = radeon_bo_gpu_offset(bo); ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0); ib.ptr[1] = addr; ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0); @@ -646,20 +671,12 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, ib.ptr[i] = PACKET2(0); ib.length_dw = 16; - r = radeon_ib_schedule(rdev, &ib, NULL); - if (r) - goto err; - ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (fence) *fence = radeon_fence_ref(ib.fence); radeon_ib_free(rdev, &ib); - radeon_bo_unref(&bo); - return 0; - -err: - ttm_eu_backoff_reservation(&ticket, &head); return r; } @@ -669,27 +686,18 @@ err: int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { - struct radeon_bo *bo; - uint32_t *msg; - int r, i; + /* we use the last page of the vcpu bo for the UVD message */ + uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) - + RADEON_GPU_PAGE_SIZE; - r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &bo); - if (r) - return r; + uint32_t *msg = rdev->uvd.cpu_addr + offs; + uint64_t addr = rdev->uvd.gpu_addr + offs; - r = radeon_bo_reserve(bo, false); - if (r) { - radeon_bo_unref(&bo); - return r; - } + int r, i; - r = radeon_bo_kmap(bo, (void **)&msg); - if (r) { - radeon_bo_unreserve(bo); - radeon_bo_unref(&bo); + r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true); + if (r) return r; - } /* stitch together an UVD create msg */ msg[0] = cpu_to_le32(0x00000de4); @@ -706,36 +714,26 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, for (i = 11; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - radeon_bo_kunmap(bo); - radeon_bo_unreserve(bo); - - return radeon_uvd_send_msg(rdev, ring, bo, fence); + r = radeon_uvd_send_msg(rdev, ring, addr, fence); + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + return r; } int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { - struct radeon_bo *bo; - uint32_t *msg; - int r, i; + /* we use the last page of the vcpu bo for the UVD message */ + uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) - + RADEON_GPU_PAGE_SIZE; - r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &bo); - if (r) - return r; + uint32_t *msg = rdev->uvd.cpu_addr + offs; + uint64_t addr = rdev->uvd.gpu_addr + offs; - r = radeon_bo_reserve(bo, false); - if (r) { - radeon_bo_unref(&bo); - return r; - } + int r, i; - r = radeon_bo_kmap(bo, (void **)&msg); - if (r) { - radeon_bo_unreserve(bo); - radeon_bo_unref(&bo); + r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true); + if (r) return r; - } /* stitch together an UVD destroy msg */ msg[0] = cpu_to_le32(0x00000de4); @@ -745,10 +743,9 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, for (i = 4; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - radeon_bo_kunmap(bo); - radeon_bo_unreserve(bo); - - return radeon_uvd_send_msg(rdev, ring, bo, fence); + r = radeon_uvd_send_msg(rdev, ring, addr, fence); + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + return r; } /** diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index aa21c31a846c..9e85757d5599 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -126,7 +126,8 @@ int radeon_vce_init(struct radeon_device *rdev) size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) + RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; r = radeon_bo_create(rdev, size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->vce.vcpu_bo); + RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, + &rdev->vce.vcpu_bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); return r; @@ -368,7 +369,7 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, for (i = ib.length_dw; i < ib_size_dw; ++i) ib.ptr[i] = 0x0; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); } @@ -425,7 +426,7 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, for (i = ib.length_dw; i < ib_size_dw; ++i) ib.ptr[i] = 0x0; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); } @@ -715,7 +716,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) return r; } radeon_ring_write(ring, VCE_CMD_END); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { if (vce_v1_0_get_rptr(rdev, ring) != rptr) diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 725d3669014f..dfde266529e2 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -132,8 +132,8 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, struct radeon_cs_reloc *list; unsigned i, idx; - list = kmalloc_array(vm->max_pde_used + 2, - sizeof(struct radeon_cs_reloc), GFP_KERNEL); + list = drm_malloc_ab(vm->max_pde_used + 2, + sizeof(struct radeon_cs_reloc)); if (!list) return NULL; @@ -143,6 +143,7 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM; list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM; list[0].tv.bo = &vm->page_directory->tbo; + list[0].tv.shared = false; list[0].tiling_flags = 0; list[0].handle = 0; list_add(&list[0].tv.head, head); @@ -156,6 +157,7 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM; list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM; list[idx].tv.bo = &list[idx].robj->tbo; + list[idx].tv.shared = false; list[idx].tiling_flags = 0; list[idx].handle = 0; list_add(&list[idx++].tv.head, head); @@ -238,8 +240,8 @@ void radeon_vm_flush(struct radeon_device *rdev, uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); /* if we can't remember our last VM flush then flush now! */ - /* XXX figure out why we have to flush all the time */ - if (!vm->last_flush || true || pd_addr != vm->pd_gpu_addr) { + if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { + trace_radeon_vm_flush(pd_addr, ring, vm->id); vm->pd_gpu_addr = pd_addr; radeon_ring_vm_flush(rdev, ring, vm); } @@ -325,17 +327,15 @@ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, } bo_va->vm = vm; bo_va->bo = bo; - bo_va->soffset = 0; - bo_va->eoffset = 0; + bo_va->it.start = 0; + bo_va->it.last = 0; bo_va->flags = 0; - bo_va->valid = false; + bo_va->addr = 0; bo_va->ref_count = 1; INIT_LIST_HEAD(&bo_va->bo_list); - INIT_LIST_HEAD(&bo_va->vm_list); INIT_LIST_HEAD(&bo_va->vm_status); mutex_lock(&vm->mutex); - list_add(&bo_va->vm_list, &vm->va); list_add_tail(&bo_va->bo_list, &bo->va); mutex_unlock(&vm->mutex); @@ -343,6 +343,42 @@ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, } /** + * radeon_vm_set_pages - helper to call the right asic function + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @addr: dst addr to write into pe + * @count: number of page entries to update + * @incr: increase next addr by incr bytes + * @flags: hw access flags + * + * Traces the parameters and calls the right asic functions + * to setup the page table using the DMA. + */ +static void radeon_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) +{ + trace_radeon_vm_set_page(pe, addr, count, incr, flags); + + if ((flags & R600_PTE_GART_MASK) == R600_PTE_GART_MASK) { + uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; + radeon_asic_vm_copy_pages(rdev, ib, pe, src, count); + + } else if ((flags & R600_PTE_SYSTEM) || (count < 3)) { + radeon_asic_vm_write_pages(rdev, ib, pe, addr, + count, incr, flags); + + } else { + radeon_asic_vm_set_pages(rdev, ib, pe, addr, + count, incr, flags); + } +} + +/** * radeon_vm_clear_bo - initially clear the page dir/table * * @rdev: radeon_device pointer @@ -361,11 +397,12 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev, memset(&tv, 0, sizeof(tv)); tv.bo = &bo->tbo; + tv.shared = false; INIT_LIST_HEAD(&head); list_add(&tv.head, &head); - r = ttm_eu_reserve_buffers(&ticket, &head); + r = ttm_eu_reserve_buffers(&ticket, &head, true); if (r) return r; @@ -376,20 +413,21 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev, addr = radeon_bo_gpu_offset(bo); entries = radeon_bo_size(bo) / 8; - r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, - NULL, entries * 2 + 64); + r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, 256); if (r) goto error; ib.length_dw = 0; - radeon_asic_vm_set_page(rdev, &ib, addr, 0, entries, 0, 0); + radeon_vm_set_pages(rdev, &ib, addr, 0, entries, 0, 0); + radeon_asic_vm_pad_ib(rdev, &ib); + WARN_ON(ib.length_dw > 64); - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) goto error; - ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence); + ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base); radeon_ib_free(rdev, &ib); return 0; @@ -419,11 +457,9 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, uint32_t flags) { uint64_t size = radeon_bo_size(bo_va->bo); - uint64_t eoffset, last_offset = 0; struct radeon_vm *vm = bo_va->vm; - struct radeon_bo_va *tmp; - struct list_head *head; unsigned last_pfn, pt_idx; + uint64_t eoffset; int r; if (soffset) { @@ -445,51 +481,53 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, } mutex_lock(&vm->mutex); - head = &vm->va; - last_offset = 0; - list_for_each_entry(tmp, &vm->va, vm_list) { - if (bo_va == tmp) { - /* skip over currently modified bo */ - continue; + if (bo_va->it.start || bo_va->it.last) { + if (bo_va->addr) { + /* add a clone of the bo_va to clear the old address */ + struct radeon_bo_va *tmp; + tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); + if (!tmp) { + mutex_unlock(&vm->mutex); + return -ENOMEM; + } + tmp->it.start = bo_va->it.start; + tmp->it.last = bo_va->it.last; + tmp->vm = vm; + tmp->addr = bo_va->addr; + tmp->bo = radeon_bo_ref(bo_va->bo); + list_add(&tmp->vm_status, &vm->freed); } - if (soffset >= last_offset && eoffset <= tmp->soffset) { - /* bo can be added before this one */ - break; - } - if (eoffset > tmp->soffset && soffset < tmp->eoffset) { - /* bo and tmp overlap, invalid offset */ - dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", - bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, - (unsigned)tmp->soffset, (unsigned)tmp->eoffset); - mutex_unlock(&vm->mutex); - return -EINVAL; - } - last_offset = tmp->eoffset; - head = &tmp->vm_list; + interval_tree_remove(&bo_va->it, &vm->va); + bo_va->it.start = 0; + bo_va->it.last = 0; } - if (bo_va->soffset) { - /* add a clone of the bo_va to clear the old address */ - tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); - if (!tmp) { + soffset /= RADEON_GPU_PAGE_SIZE; + eoffset /= RADEON_GPU_PAGE_SIZE; + if (soffset || eoffset) { + struct interval_tree_node *it; + it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1); + if (it) { + struct radeon_bo_va *tmp; + tmp = container_of(it, struct radeon_bo_va, it); + /* bo and tmp overlap, invalid offset */ + dev_err(rdev->dev, "bo %p va 0x%010Lx conflict with " + "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo, + soffset, tmp->bo, tmp->it.start, tmp->it.last); mutex_unlock(&vm->mutex); - return -ENOMEM; + return -EINVAL; } - tmp->soffset = bo_va->soffset; - tmp->eoffset = bo_va->eoffset; - tmp->vm = vm; - list_add(&tmp->vm_status, &vm->freed); + bo_va->it.start = soffset; + bo_va->it.last = eoffset - 1; + interval_tree_insert(&bo_va->it, &vm->va); } - bo_va->soffset = soffset; - bo_va->eoffset = eoffset; bo_va->flags = flags; - bo_va->valid = false; - list_move(&bo_va->vm_list, head); + bo_va->addr = 0; - soffset = (soffset / RADEON_GPU_PAGE_SIZE) >> radeon_vm_block_size; - eoffset = (eoffset / RADEON_GPU_PAGE_SIZE) >> radeon_vm_block_size; + soffset >>= radeon_vm_block_size; + eoffset >>= radeon_vm_block_size; BUG_ON(eoffset >= radeon_vm_num_pdes(rdev)); @@ -510,7 +548,8 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8, RADEON_GPU_PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, NULL, &pt); + RADEON_GEM_DOMAIN_VRAM, 0, + NULL, NULL, &pt); if (r) return r; @@ -611,7 +650,7 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev, ndw = 64; /* assume the worst case */ - ndw += vm->max_pde_used * 16; + ndw += vm->max_pde_used * 6; /* update too big for an IB */ if (ndw > 0xfffff) @@ -640,9 +679,9 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev, ((last_pt + incr * count) != pt)) { if (count) { - radeon_asic_vm_set_page(rdev, &ib, last_pde, - last_pt, count, incr, - R600_PTE_VALID); + radeon_vm_set_pages(rdev, &ib, last_pde, + last_pt, count, incr, + R600_PTE_VALID); } count = 1; @@ -654,13 +693,16 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev, } if (count) - radeon_asic_vm_set_page(rdev, &ib, last_pde, last_pt, count, - incr, R600_PTE_VALID); + radeon_vm_set_pages(rdev, &ib, last_pde, last_pt, count, + incr, R600_PTE_VALID); if (ib.length_dw != 0) { - radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj); - radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use); - r = radeon_ib_schedule(rdev, &ib, NULL); + radeon_asic_vm_pad_ib(rdev, &ib); + + radeon_semaphore_sync_resv(rdev, ib.semaphore, pd->tbo.resv, false); + radeon_semaphore_sync_fence(ib.semaphore, vm->last_id_use); + WARN_ON(ib.length_dw > ndw); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); return r; @@ -725,30 +767,30 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev, (frag_start >= frag_end)) { count = (pe_end - pe_start) / 8; - radeon_asic_vm_set_page(rdev, ib, pe_start, addr, count, - RADEON_GPU_PAGE_SIZE, flags); + radeon_vm_set_pages(rdev, ib, pe_start, addr, count, + RADEON_GPU_PAGE_SIZE, flags); return; } /* handle the 4K area at the beginning */ if (pe_start != frag_start) { count = (frag_start - pe_start) / 8; - radeon_asic_vm_set_page(rdev, ib, pe_start, addr, count, - RADEON_GPU_PAGE_SIZE, flags); + radeon_vm_set_pages(rdev, ib, pe_start, addr, count, + RADEON_GPU_PAGE_SIZE, flags); addr += RADEON_GPU_PAGE_SIZE * count; } /* handle the area in the middle */ count = (frag_end - frag_start) / 8; - radeon_asic_vm_set_page(rdev, ib, frag_start, addr, count, - RADEON_GPU_PAGE_SIZE, flags | frag_flags); + radeon_vm_set_pages(rdev, ib, frag_start, addr, count, + RADEON_GPU_PAGE_SIZE, flags | frag_flags); /* handle the 4K area at the end */ if (frag_end != pe_end) { addr += RADEON_GPU_PAGE_SIZE * count; count = (pe_end - frag_end) / 8; - radeon_asic_vm_set_page(rdev, ib, frag_end, addr, count, - RADEON_GPU_PAGE_SIZE, flags); + radeon_vm_set_pages(rdev, ib, frag_end, addr, count, + RADEON_GPU_PAGE_SIZE, flags); } } @@ -777,9 +819,6 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev, unsigned count = 0; uint64_t addr; - start = start / RADEON_GPU_PAGE_SIZE; - end = end / RADEON_GPU_PAGE_SIZE; - /* walk over the address space and update the page tables */ for (addr = start; addr < end; ) { uint64_t pt_idx = addr >> radeon_vm_block_size; @@ -787,7 +826,7 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev, unsigned nptes; uint64_t pte; - radeon_semaphore_sync_to(ib->semaphore, pt->tbo.sync_obj); + radeon_semaphore_sync_resv(rdev, ib->semaphore, pt->tbo.resv, false); if ((addr & ~mask) == (end & ~mask)) nptes = end - addr; @@ -842,55 +881,76 @@ int radeon_vm_bo_update(struct radeon_device *rdev, { struct radeon_vm *vm = bo_va->vm; struct radeon_ib ib; - unsigned nptes, ndw; + unsigned nptes, ncmds, ndw; uint64_t addr; + uint32_t flags; int r; - - if (!bo_va->soffset) { + if (!bo_va->it.start) { dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", bo_va->bo, vm); return -EINVAL; } - if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) - return 0; + list_del_init(&bo_va->vm_status); bo_va->flags &= ~RADEON_VM_PAGE_VALID; bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; + bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED; + if (bo_va->bo && radeon_ttm_tt_is_readonly(bo_va->bo->tbo.ttm)) + bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE; + if (mem) { addr = mem->start << PAGE_SHIFT; if (mem->mem_type != TTM_PL_SYSTEM) { bo_va->flags |= RADEON_VM_PAGE_VALID; - bo_va->valid = true; } if (mem->mem_type == TTM_PL_TT) { bo_va->flags |= RADEON_VM_PAGE_SYSTEM; + if (!(bo_va->bo->flags & (RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC))) + bo_va->flags |= RADEON_VM_PAGE_SNOOPED; + } else { addr += rdev->vm_manager.vram_base_offset; } } else { addr = 0; - bo_va->valid = false; } + if (addr == bo_va->addr) + return 0; + bo_va->addr = addr; + trace_radeon_vm_bo_update(bo_va); - nptes = (bo_va->eoffset - bo_va->soffset) / RADEON_GPU_PAGE_SIZE; + nptes = bo_va->it.last - bo_va->it.start + 1; + + /* reserve space for one command every (1 << BLOCK_SIZE) entries + or 2k dwords (whatever is smaller) */ + ncmds = (nptes >> min(radeon_vm_block_size, 11)) + 1; /* padding, etc. */ ndw = 64; - if (radeon_vm_block_size > 11) - /* reserve space for one header for every 2k dwords */ - ndw += (nptes >> 11) * 4; - else - /* reserve space for one header for - every (1 << BLOCK_SIZE) entries */ - ndw += (nptes >> radeon_vm_block_size) * 4; + flags = radeon_vm_page_flags(bo_va->flags); + if ((flags & R600_PTE_GART_MASK) == R600_PTE_GART_MASK) { + /* only copy commands needed */ + ndw += ncmds * 7; + + } else if (flags & R600_PTE_SYSTEM) { + /* header for write data commands */ + ndw += ncmds * 4; + + /* body of write data command */ + ndw += nptes * 2; + + } else { + /* set page commands needed */ + ndw += ncmds * 10; - /* reserve space for pte addresses */ - ndw += nptes * 2; + /* two extra commands for begin/end of fragment */ + ndw += 2 * 10; + } /* update too big for an IB */ if (ndw > 0xfffff) @@ -901,11 +961,15 @@ int radeon_vm_bo_update(struct radeon_device *rdev, return r; ib.length_dw = 0; - radeon_vm_update_ptes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset, - addr, radeon_vm_page_flags(bo_va->flags)); + radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start, + bo_va->it.last + 1, addr, + radeon_vm_page_flags(bo_va->flags)); - radeon_semaphore_sync_to(ib.semaphore, vm->fence); - r = radeon_ib_schedule(rdev, &ib, NULL); + radeon_asic_vm_pad_ib(rdev, &ib); + WARN_ON(ib.length_dw > ndw); + + radeon_semaphore_sync_fence(ib.semaphore, vm->fence); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); return r; @@ -936,8 +1000,8 @@ int radeon_vm_clear_freed(struct radeon_device *rdev, int r; list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { - list_del(&bo_va->vm_status); r = radeon_vm_bo_update(rdev, bo_va, NULL); + radeon_bo_unref(&bo_va->bo); kfree(bo_va); if (r) return r; @@ -947,6 +1011,31 @@ int radeon_vm_clear_freed(struct radeon_device *rdev, } /** + * radeon_vm_clear_invalids - clear invalidated BOs in the PT + * + * @rdev: radeon_device pointer + * @vm: requested vm + * + * Make sure all invalidated BOs are cleared in the PT. + * Returns 0 for success. + * + * PTs have to be reserved and mutex must be locked! + */ +int radeon_vm_clear_invalids(struct radeon_device *rdev, + struct radeon_vm *vm) +{ + struct radeon_bo_va *bo_va, *tmp; + int r; + + list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, vm_status) { + r = radeon_vm_bo_update(rdev, bo_va, NULL); + if (r) + return r; + } + return 0; +} + +/** * radeon_vm_bo_rmv - remove a bo to a specific vm * * @rdev: radeon_device pointer @@ -964,10 +1053,11 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev, list_del(&bo_va->bo_list); mutex_lock(&vm->mutex); - list_del(&bo_va->vm_list); + interval_tree_remove(&bo_va->it, &vm->va); + list_del(&bo_va->vm_status); - if (bo_va->soffset) { - bo_va->bo = NULL; + if (bo_va->addr) { + bo_va->bo = radeon_bo_ref(bo_va->bo); list_add(&bo_va->vm_status, &vm->freed); } else { kfree(bo_va); @@ -991,7 +1081,12 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, struct radeon_bo_va *bo_va; list_for_each_entry(bo_va, &bo->va, bo_list) { - bo_va->valid = false; + if (bo_va->addr) { + mutex_lock(&bo_va->vm->mutex); + list_del(&bo_va->vm_status); + list_add(&bo_va->vm_status, &bo_va->vm->invalidated); + mutex_unlock(&bo_va->vm->mutex); + } } } @@ -1016,7 +1111,8 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) vm->last_flush = NULL; vm->last_id_use = NULL; mutex_init(&vm->mutex); - INIT_LIST_HEAD(&vm->va); + vm->va = RB_ROOT; + INIT_LIST_HEAD(&vm->invalidated); INIT_LIST_HEAD(&vm->freed); pd_size = radeon_vm_directory_size(rdev); @@ -1031,8 +1127,8 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) } r = radeon_bo_create(rdev, pd_size, align, true, - RADEON_GEM_DOMAIN_VRAM, NULL, - &vm->page_directory); + RADEON_GEM_DOMAIN_VRAM, 0, NULL, + NULL, &vm->page_directory); if (r) return r; @@ -1060,11 +1156,11 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) struct radeon_bo_va *bo_va, *tmp; int i, r; - if (!list_empty(&vm->va)) { + if (!RB_EMPTY_ROOT(&vm->va)) { dev_err(rdev->dev, "still active bo inside vm\n"); } - list_for_each_entry_safe(bo_va, tmp, &vm->va, vm_list) { - list_del_init(&bo_va->vm_list); + rbtree_postorder_for_each_entry_safe(bo_va, tmp, &vm->va, it.rb) { + interval_tree_remove(&bo_va->it, &vm->va); r = radeon_bo_reserve(bo_va->bo, false); if (!r) { list_del_init(&bo_va->bo_list); @@ -1072,8 +1168,10 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) kfree(bo_va); } } - list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) + list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { + radeon_bo_unref(&bo_va->bo); kfree(bo_va); + } for (i = 0; i < radeon_vm_num_pdes(rdev); i++) radeon_bo_unref(&vm->page_tables[i].bo); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index a0f96decece3..c5799f16aa4b 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -109,7 +109,6 @@ int rs400_gart_enable(struct radeon_device *rdev) uint32_t size_reg; uint32_t tmp; - radeon_gart_restore(rdev); tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH); tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS; WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp); @@ -209,17 +208,24 @@ void rs400_gart_fini(struct radeon_device *rdev) radeon_gart_table_ram_free(rdev); } +#define RS400_PTE_UNSNOOPED (1 << 0) #define RS400_PTE_WRITEABLE (1 << 2) #define RS400_PTE_READABLE (1 << 3) -void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr) +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t addr, uint32_t flags) { uint32_t entry; u32 *gtt = rdev->gart.ptr; entry = (lower_32_bits(addr) & PAGE_MASK) | - ((upper_32_bits(addr) & 0xff) << 4) | - RS400_PTE_WRITEABLE | RS400_PTE_READABLE; + ((upper_32_bits(addr) & 0xff) << 4); + if (flags & RADEON_GART_PAGE_READ) + entry |= RS400_PTE_READABLE; + if (flags & RADEON_GART_PAGE_WRITE) + entry |= RS400_PTE_WRITEABLE; + if (!(flags & RADEON_GART_PAGE_SNOOP)) + entry |= RS400_PTE_UNSNOOPED; entry = cpu_to_le32(entry); gtt[i] = entry; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index d1a35cb1c91d..9acb1c3c005b 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -555,7 +555,6 @@ static int rs600_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Enable bus master */ tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; WREG32(RADEON_BUS_CNTL, tmp); @@ -626,15 +625,21 @@ static void rs600_gart_fini(struct radeon_device *rdev) radeon_gart_table_vram_free(rdev); } -void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, uint64_t addr) +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t addr, uint32_t flags) { void __iomem *ptr = (void *)rdev->gart.ptr; addr = addr & 0xFFFFFFFFFFFFF000ULL; - if (addr == rdev->dummy_page.addr) - addr |= R600_PTE_SYSTEM | R600_PTE_SNOOPED; - else - addr |= R600_PTE_GART; + addr |= R600_PTE_SYSTEM; + if (flags & RADEON_GART_PAGE_VALID) + addr |= R600_PTE_VALID; + if (flags & RADEON_GART_PAGE_READ) + addr |= R600_PTE_READABLE; + if (flags & RADEON_GART_PAGE_WRITE) + addr |= R600_PTE_WRITEABLE; + if (flags & RADEON_GART_PAGE_SNOOP) + addr |= R600_PTE_SNOOPED; writeq(addr, ptr + (i * 8)); } @@ -874,6 +879,9 @@ void rs600_bandwidth_update(struct radeon_device *rdev) u32 d1mode_priority_a_cnt, d2mode_priority_a_cnt; /* FIXME: implement full support */ + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); if (rdev->mode_info.crtcs[0]->base.enabled) diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 3462b64369bf..0a2d36e81108 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -579,6 +579,9 @@ void rs690_bandwidth_update(struct radeon_device *rdev) u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt; u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt; + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); if (rdev->mode_info.crtcs[0]->base.enabled) diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index 02f7710de470..9031f4b69824 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -24,6 +24,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "rs780d.h" #include "r600_dpm.h" #include "rs780_dpm.h" diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 3e21e869015f..c55d653aaf5f 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -124,7 +124,7 @@ void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, GEOMETRY_ROUND_NEAREST | COLOR_ROUND_NEAREST); radeon_ring_write(ring, PACKET0(0x20C8, 0)); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } int rv515_mc_wait_for_idle(struct radeon_device *rdev) @@ -1277,6 +1277,9 @@ void rv515_bandwidth_update(struct radeon_device *rdev) struct drm_display_mode *mode0 = NULL; struct drm_display_mode *mode1 = NULL; + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); if (rdev->mode_info.crtcs[0]->base.enabled) diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index e7045b085715..6a5c233361e9 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -24,6 +24,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "rv6xxd.h" #include "r600_dpm.h" #include "rv6xx_dpm.h" diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index da8703d8d455..372016e266d0 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -26,7 +26,6 @@ * Jerome Glisse */ #include <linux/firmware.h> -#include <linux/platform_device.h> #include <linux/slab.h> #include <drm/drmP.h> #include "radeon.h" @@ -900,7 +899,6 @@ static int rv770_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Setup L2 cache */ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE | @@ -1178,7 +1176,6 @@ static void rv770_gpu_init(struct radeon_device *rdev) u32 hdp_host_path_cntl; u32 sq_dyn_gpr_size_simd_ab_0; u32 gb_tiling_config = 0; - u32 cc_rb_backend_disable = 0; u32 cc_gc_shader_pipe_config = 0; u32 mc_arb_ramcfg; u32 db_debug4, tmp; @@ -1312,21 +1309,7 @@ static void rv770_gpu_init(struct radeon_device *rdev) WREG32(SPI_CONFIG_CNTL, 0); } - cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; - tmp = R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_rb_backend_disable >> 16); - if (tmp < rdev->config.rv770.max_backends) { - rdev->config.rv770.max_backends = tmp; - } - cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; - tmp = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R7XX_MAX_PIPES_MASK); - if (tmp < rdev->config.rv770.max_pipes) { - rdev->config.rv770.max_pipes = tmp; - } - tmp = R7XX_MAX_SIMDS - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK); - if (tmp < rdev->config.rv770.max_simds) { - rdev->config.rv770.max_simds = tmp; - } tmp = rdev->config.rv770.max_simds - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK); rdev->config.rv770.active_simds = tmp; @@ -1349,6 +1332,14 @@ static void rv770_gpu_init(struct radeon_device *rdev) rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes; disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R7XX_MAX_BACKENDS_MASK; + tmp = 0; + for (i = 0; i < rdev->config.rv770.max_backends; i++) + tmp |= (1 << i); + /* if all the backends are disabled, fix it up here */ + if ((disabled_rb_mask & tmp) == tmp) { + for (i = 0; i < rdev->config.rv770.max_backends; i++) + disabled_rb_mask &= ~(1 << i); + } tmp = (gb_tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.rv770.max_backends, R7XX_MAX_BACKENDS, disabled_rb_mask); diff --git a/drivers/gpu/drm/radeon/rv770_dma.c b/drivers/gpu/drm/radeon/rv770_dma.c index bbf2e076ee45..7f34bad2e724 100644 --- a/drivers/gpu/drm/radeon/rv770_dma.c +++ b/drivers/gpu/drm/radeon/rv770_dma.c @@ -33,18 +33,19 @@ * @src_offset: src GPU address * @dst_offset: dst GPU address * @num_gpu_pages: number of GPU pages to xfer - * @fence: radeon fence object + * @resv: reservation object to sync to * * Copy GPU paging using the DMA engine (r7xx). * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ -int rv770_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; int ring_index = rdev->asic->copy.dma_ring_index; struct radeon_ring *ring = &rdev->ring[ring_index]; u32 size_in_dw, cur_size_in_dw; @@ -54,7 +55,7 @@ int rv770_copy_dma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4; @@ -63,10 +64,10 @@ int rv770_copy_dma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); for (i = 0; i < num_loops; i++) { @@ -83,15 +84,15 @@ int rv770_copy_dma(struct radeon_device *rdev, dst_offset += cur_size_in_dw * 4; } - r = radeon_fence_emit(rdev, fence, ring->idx); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 3c76e1dcdf04..755a8f96fe46 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -24,6 +24,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "rv770d.h" #include "r600_dpm.h" #include "rv770_dpm.h" diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 9e854fd016da..7d5083dc4acb 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -42,6 +42,14 @@ MODULE_FIRMWARE("radeon/TAHITI_mc.bin"); MODULE_FIRMWARE("radeon/TAHITI_mc2.bin"); MODULE_FIRMWARE("radeon/TAHITI_rlc.bin"); MODULE_FIRMWARE("radeon/TAHITI_smc.bin"); + +MODULE_FIRMWARE("radeon/tahiti_pfp.bin"); +MODULE_FIRMWARE("radeon/tahiti_me.bin"); +MODULE_FIRMWARE("radeon/tahiti_ce.bin"); +MODULE_FIRMWARE("radeon/tahiti_mc.bin"); +MODULE_FIRMWARE("radeon/tahiti_rlc.bin"); +MODULE_FIRMWARE("radeon/tahiti_smc.bin"); + MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_me.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin"); @@ -49,6 +57,14 @@ MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_mc2.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_smc.bin"); + +MODULE_FIRMWARE("radeon/pitcairn_pfp.bin"); +MODULE_FIRMWARE("radeon/pitcairn_me.bin"); +MODULE_FIRMWARE("radeon/pitcairn_ce.bin"); +MODULE_FIRMWARE("radeon/pitcairn_mc.bin"); +MODULE_FIRMWARE("radeon/pitcairn_rlc.bin"); +MODULE_FIRMWARE("radeon/pitcairn_smc.bin"); + MODULE_FIRMWARE("radeon/VERDE_pfp.bin"); MODULE_FIRMWARE("radeon/VERDE_me.bin"); MODULE_FIRMWARE("radeon/VERDE_ce.bin"); @@ -56,6 +72,14 @@ MODULE_FIRMWARE("radeon/VERDE_mc.bin"); MODULE_FIRMWARE("radeon/VERDE_mc2.bin"); MODULE_FIRMWARE("radeon/VERDE_rlc.bin"); MODULE_FIRMWARE("radeon/VERDE_smc.bin"); + +MODULE_FIRMWARE("radeon/verde_pfp.bin"); +MODULE_FIRMWARE("radeon/verde_me.bin"); +MODULE_FIRMWARE("radeon/verde_ce.bin"); +MODULE_FIRMWARE("radeon/verde_mc.bin"); +MODULE_FIRMWARE("radeon/verde_rlc.bin"); +MODULE_FIRMWARE("radeon/verde_smc.bin"); + MODULE_FIRMWARE("radeon/OLAND_pfp.bin"); MODULE_FIRMWARE("radeon/OLAND_me.bin"); MODULE_FIRMWARE("radeon/OLAND_ce.bin"); @@ -63,6 +87,14 @@ MODULE_FIRMWARE("radeon/OLAND_mc.bin"); MODULE_FIRMWARE("radeon/OLAND_mc2.bin"); MODULE_FIRMWARE("radeon/OLAND_rlc.bin"); MODULE_FIRMWARE("radeon/OLAND_smc.bin"); + +MODULE_FIRMWARE("radeon/oland_pfp.bin"); +MODULE_FIRMWARE("radeon/oland_me.bin"); +MODULE_FIRMWARE("radeon/oland_ce.bin"); +MODULE_FIRMWARE("radeon/oland_mc.bin"); +MODULE_FIRMWARE("radeon/oland_rlc.bin"); +MODULE_FIRMWARE("radeon/oland_smc.bin"); + MODULE_FIRMWARE("radeon/HAINAN_pfp.bin"); MODULE_FIRMWARE("radeon/HAINAN_me.bin"); MODULE_FIRMWARE("radeon/HAINAN_ce.bin"); @@ -71,6 +103,13 @@ MODULE_FIRMWARE("radeon/HAINAN_mc2.bin"); MODULE_FIRMWARE("radeon/HAINAN_rlc.bin"); MODULE_FIRMWARE("radeon/HAINAN_smc.bin"); +MODULE_FIRMWARE("radeon/hainan_pfp.bin"); +MODULE_FIRMWARE("radeon/hainan_me.bin"); +MODULE_FIRMWARE("radeon/hainan_ce.bin"); +MODULE_FIRMWARE("radeon/hainan_mc.bin"); +MODULE_FIRMWARE("radeon/hainan_rlc.bin"); +MODULE_FIRMWARE("radeon/hainan_smc.bin"); + static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh); static void si_pcie_gen3_enable(struct radeon_device *rdev); static void si_program_aspm(struct radeon_device *rdev); @@ -1470,38 +1509,54 @@ static const u32 hainan_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = { /* ucode loading */ int si_mc_load_microcode(struct radeon_device *rdev) { - const __be32 *fw_data; + const __be32 *fw_data = NULL; + const __le32 *new_fw_data = NULL; u32 running, blackout = 0; - u32 *io_mc_regs; + u32 *io_mc_regs = NULL; + const __le32 *new_io_mc_regs = NULL; int i, regs_size, ucode_size; if (!rdev->mc_fw) return -EINVAL; - ucode_size = rdev->mc_fw->size / 4; + if (rdev->new_fw) { + const struct mc_firmware_header_v1_0 *hdr = + (const struct mc_firmware_header_v1_0 *)rdev->mc_fw->data; + + radeon_ucode_print_mc_hdr(&hdr->header); + regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); + new_io_mc_regs = (const __le32 *) + (rdev->mc_fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); + ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + new_fw_data = (const __le32 *) + (rdev->mc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + } else { + ucode_size = rdev->mc_fw->size / 4; - switch (rdev->family) { - case CHIP_TAHITI: - io_mc_regs = (u32 *)&tahiti_io_mc_regs; - regs_size = TAHITI_IO_MC_REGS_SIZE; - break; - case CHIP_PITCAIRN: - io_mc_regs = (u32 *)&pitcairn_io_mc_regs; - regs_size = TAHITI_IO_MC_REGS_SIZE; - break; - case CHIP_VERDE: - default: - io_mc_regs = (u32 *)&verde_io_mc_regs; - regs_size = TAHITI_IO_MC_REGS_SIZE; - break; - case CHIP_OLAND: - io_mc_regs = (u32 *)&oland_io_mc_regs; - regs_size = TAHITI_IO_MC_REGS_SIZE; - break; - case CHIP_HAINAN: - io_mc_regs = (u32 *)&hainan_io_mc_regs; - regs_size = TAHITI_IO_MC_REGS_SIZE; - break; + switch (rdev->family) { + case CHIP_TAHITI: + io_mc_regs = (u32 *)&tahiti_io_mc_regs; + regs_size = TAHITI_IO_MC_REGS_SIZE; + break; + case CHIP_PITCAIRN: + io_mc_regs = (u32 *)&pitcairn_io_mc_regs; + regs_size = TAHITI_IO_MC_REGS_SIZE; + break; + case CHIP_VERDE: + default: + io_mc_regs = (u32 *)&verde_io_mc_regs; + regs_size = TAHITI_IO_MC_REGS_SIZE; + break; + case CHIP_OLAND: + io_mc_regs = (u32 *)&oland_io_mc_regs; + regs_size = TAHITI_IO_MC_REGS_SIZE; + break; + case CHIP_HAINAN: + io_mc_regs = (u32 *)&hainan_io_mc_regs; + regs_size = TAHITI_IO_MC_REGS_SIZE; + break; + } + fw_data = (const __be32 *)rdev->mc_fw->data; } running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; @@ -1518,13 +1573,21 @@ int si_mc_load_microcode(struct radeon_device *rdev) /* load mc io regs */ for (i = 0; i < regs_size; i++) { - WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); - WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); + if (rdev->new_fw) { + WREG32(MC_SEQ_IO_DEBUG_INDEX, le32_to_cpup(new_io_mc_regs++)); + WREG32(MC_SEQ_IO_DEBUG_DATA, le32_to_cpup(new_io_mc_regs++)); + } else { + WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); + WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); + } } /* load the MC ucode */ - fw_data = (const __be32 *)rdev->mc_fw->data; - for (i = 0; i < ucode_size; i++) - WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); + for (i = 0; i < ucode_size; i++) { + if (rdev->new_fw) + WREG32(MC_SEQ_SUP_PGM, le32_to_cpup(new_fw_data++)); + else + WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); + } /* put the engine back into the active state */ WREG32(MC_SEQ_SUP_CNTL, 0x00000008); @@ -1553,18 +1616,19 @@ int si_mc_load_microcode(struct radeon_device *rdev) static int si_init_microcode(struct radeon_device *rdev) { const char *chip_name; - const char *rlc_chip_name; + const char *new_chip_name; size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size; size_t smc_req_size, mc2_req_size; char fw_name[30]; int err; + int new_fw = 0; DRM_DEBUG("\n"); switch (rdev->family) { case CHIP_TAHITI: chip_name = "TAHITI"; - rlc_chip_name = "TAHITI"; + new_chip_name = "tahiti"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; ce_req_size = SI_CE_UCODE_SIZE * 4; @@ -1575,7 +1639,7 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_PITCAIRN: chip_name = "PITCAIRN"; - rlc_chip_name = "PITCAIRN"; + new_chip_name = "pitcairn"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; ce_req_size = SI_CE_UCODE_SIZE * 4; @@ -1586,7 +1650,7 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_VERDE: chip_name = "VERDE"; - rlc_chip_name = "VERDE"; + new_chip_name = "verde"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; ce_req_size = SI_CE_UCODE_SIZE * 4; @@ -1597,7 +1661,7 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_OLAND: chip_name = "OLAND"; - rlc_chip_name = "OLAND"; + new_chip_name = "oland"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; ce_req_size = SI_CE_UCODE_SIZE * 4; @@ -1607,7 +1671,7 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_HAINAN: chip_name = "HAINAN"; - rlc_chip_name = "HAINAN"; + new_chip_name = "hainan"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; ce_req_size = SI_CE_UCODE_SIZE * 4; @@ -1618,86 +1682,178 @@ static int si_init_microcode(struct radeon_device *rdev) default: BUG(); } - DRM_INFO("Loading %s Microcode\n", chip_name); + DRM_INFO("Loading %s Microcode\n", new_chip_name); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name); err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->pfp_fw->size != pfp_req_size) { - printk(KERN_ERR - "si_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->pfp_fw->size, fw_name); - err = -EINVAL; - goto out; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->pfp_fw->size != pfp_req_size) { + printk(KERN_ERR + "si_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->pfp_fw->size, fw_name); + err = -EINVAL; + goto out; + } + } else { + err = radeon_ucode_validate(rdev->pfp_fw); + if (err) { + printk(KERN_ERR + "si_cp: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", new_chip_name); err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->me_fw->size != me_req_size) { - printk(KERN_ERR - "si_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->me_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->me_fw->size != me_req_size) { + printk(KERN_ERR + "si_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->me_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->me_fw); + if (err) { + printk(KERN_ERR + "si_cp: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", new_chip_name); err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->ce_fw->size != ce_req_size) { - printk(KERN_ERR - "si_cp: Bogus length %zu in firmware \"%s\"\n", - rdev->ce_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->ce_fw->size != ce_req_size) { + printk(KERN_ERR + "si_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->ce_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->ce_fw); + if (err) { + printk(KERN_ERR + "si_cp: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", new_chip_name); err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); - if (err) - goto out; - if (rdev->rlc_fw->size != rlc_req_size) { - printk(KERN_ERR - "si_rlc: Bogus length %zu in firmware \"%s\"\n", - rdev->rlc_fw->size, fw_name); - err = -EINVAL; + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev); + if (err) + goto out; + if (rdev->rlc_fw->size != rlc_req_size) { + printk(KERN_ERR + "si_rlc: Bogus length %zu in firmware \"%s\"\n", + rdev->rlc_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->rlc_fw); + if (err) { + printk(KERN_ERR + "si_cp: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name); err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) { - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); - if (err) + if (err) { + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); + if (err) + goto out; + } + if ((rdev->mc_fw->size != mc_req_size) && + (rdev->mc_fw->size != mc2_req_size)) { + printk(KERN_ERR + "si_mc: Bogus length %zu in firmware \"%s\"\n", + rdev->mc_fw->size, fw_name); + err = -EINVAL; + } + DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size); + } else { + err = radeon_ucode_validate(rdev->mc_fw); + if (err) { + printk(KERN_ERR + "si_cp: validation failed for firmware \"%s\"\n", + fw_name); goto out; + } else { + new_fw++; + } } - if ((rdev->mc_fw->size != mc_req_size) && - (rdev->mc_fw->size != mc2_req_size)) { - printk(KERN_ERR - "si_mc: Bogus length %zu in firmware \"%s\"\n", - rdev->mc_fw->size, fw_name); - err = -EINVAL; - } - DRM_INFO("%s: %zu bytes\n", fw_name, rdev->mc_fw->size); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name); err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); if (err) { - printk(KERN_ERR - "smc: error loading firmware \"%s\"\n", - fw_name); - release_firmware(rdev->smc_fw); - rdev->smc_fw = NULL; - err = 0; - } else if (rdev->smc_fw->size != smc_req_size) { - printk(KERN_ERR - "si_smc: Bogus length %zu in firmware \"%s\"\n", - rdev->smc_fw->size, fw_name); - err = -EINVAL; + snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev); + if (err) { + printk(KERN_ERR + "smc: error loading firmware \"%s\"\n", + fw_name); + release_firmware(rdev->smc_fw); + rdev->smc_fw = NULL; + err = 0; + } else if (rdev->smc_fw->size != smc_req_size) { + printk(KERN_ERR + "si_smc: Bogus length %zu in firmware \"%s\"\n", + rdev->smc_fw->size, fw_name); + err = -EINVAL; + } + } else { + err = radeon_ucode_validate(rdev->smc_fw); + if (err) { + printk(KERN_ERR + "si_cp: validation failed for firmware \"%s\"\n", + fw_name); + goto out; + } else { + new_fw++; + } } + if (new_fw == 0) { + rdev->new_fw = false; + } else if (new_fw < 6) { + printk(KERN_ERR "si_fw: mixing new and old firmware!\n"); + err = -EINVAL; + } else { + rdev->new_fw = true; + } out: if (err) { if (err != -EINVAL) @@ -2228,6 +2384,9 @@ void dce6_bandwidth_update(struct radeon_device *rdev) u32 num_heads = 0, lb_size; int i; + if (!rdev->mode_info.mode_config_initialized) + return; + radeon_update_display_priority(rdev); for (i = 0; i < rdev->num_crtc; i++) { @@ -2901,7 +3060,7 @@ static void si_gpu_init(struct radeon_device *rdev) u32 sx_debug_1; u32 hdp_host_path_cntl; u32 tmp; - int i, j, k; + int i, j; switch (rdev->family) { case CHIP_TAHITI: @@ -3099,12 +3258,11 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.max_sh_per_se, rdev->config.si.max_cu_per_sh); + rdev->config.si.active_cus = 0; for (i = 0; i < rdev->config.si.max_shader_engines; i++) { for (j = 0; j < rdev->config.si.max_sh_per_se; j++) { - for (k = 0; k < rdev->config.si.max_cu_per_sh; k++) { - rdev->config.si.active_cus += - hweight32(si_get_cu_active_bitmap(rdev, i, j)); - } + rdev->config.si.active_cus += + hweight32(si_get_cu_active_bitmap(rdev, i, j)); } } @@ -3282,34 +3440,77 @@ static void si_cp_enable(struct radeon_device *rdev, bool enable) static int si_cp_load_microcode(struct radeon_device *rdev) { - const __be32 *fw_data; int i; - if (!rdev->me_fw || !rdev->pfp_fw) + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw) return -EINVAL; si_cp_enable(rdev, false); - /* PFP */ - fw_data = (const __be32 *)rdev->pfp_fw->data; - WREG32(CP_PFP_UCODE_ADDR, 0); - for (i = 0; i < SI_PFP_UCODE_SIZE; i++) - WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_PFP_UCODE_ADDR, 0); - - /* CE */ - fw_data = (const __be32 *)rdev->ce_fw->data; - WREG32(CP_CE_UCODE_ADDR, 0); - for (i = 0; i < SI_CE_UCODE_SIZE; i++) - WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_CE_UCODE_ADDR, 0); - - /* ME */ - fw_data = (const __be32 *)rdev->me_fw->data; - WREG32(CP_ME_RAM_WADDR, 0); - for (i = 0; i < SI_PM4_UCODE_SIZE; i++) - WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); - WREG32(CP_ME_RAM_WADDR, 0); + if (rdev->new_fw) { + const struct gfx_firmware_header_v1_0 *pfp_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->pfp_fw->data; + const struct gfx_firmware_header_v1_0 *ce_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->ce_fw->data; + const struct gfx_firmware_header_v1_0 *me_hdr = + (const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data; + const __le32 *fw_data; + u32 fw_size; + + radeon_ucode_print_gfx_hdr(&pfp_hdr->header); + radeon_ucode_print_gfx_hdr(&ce_hdr->header); + radeon_ucode_print_gfx_hdr(&me_hdr->header); + + /* PFP */ + fw_data = (const __le32 *) + (rdev->pfp_fw->data + le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + /* CE */ + fw_data = (const __le32 *) + (rdev->ce_fw->data + le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(ce_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_CE_UCODE_ADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_CE_UCODE_ADDR, 0); + + /* ME */ + fw_data = (const __be32 *) + (rdev->me_fw->data + le32_to_cpu(me_hdr->header.ucode_array_offset_bytes)); + fw_size = le32_to_cpu(me_hdr->header.ucode_size_bytes) / 4; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < fw_size; i++) + WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++)); + WREG32(CP_ME_RAM_WADDR, 0); + } else { + const __be32 *fw_data; + + /* PFP */ + fw_data = (const __be32 *)rdev->pfp_fw->data; + WREG32(CP_PFP_UCODE_ADDR, 0); + for (i = 0; i < SI_PFP_UCODE_SIZE; i++) + WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_PFP_UCODE_ADDR, 0); + + /* CE */ + fw_data = (const __be32 *)rdev->ce_fw->data; + WREG32(CP_CE_UCODE_ADDR, 0); + for (i = 0; i < SI_CE_UCODE_SIZE; i++) + WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_CE_UCODE_ADDR, 0); + + /* ME */ + fw_data = (const __be32 *)rdev->me_fw->data; + WREG32(CP_ME_RAM_WADDR, 0); + for (i = 0; i < SI_PM4_UCODE_SIZE; i++) + WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++)); + WREG32(CP_ME_RAM_WADDR, 0); + } WREG32(CP_PFP_UCODE_ADDR, 0); WREG32(CP_CE_UCODE_ADDR, 0); @@ -3342,7 +3543,7 @@ static int si_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE)); radeon_ring_write(ring, 0xc000); radeon_ring_write(ring, 0xe000); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); si_cp_enable(rdev, true); @@ -3371,7 +3572,7 @@ static int si_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) { ring = &rdev->ring[i]; @@ -3381,7 +3582,7 @@ static int si_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0)); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } return 0; @@ -4048,7 +4249,6 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) r = radeon_gart_table_vram_pin(rdev); if (r) return r; - radeon_gart_restore(rdev); /* Setup TLB control */ WREG32(MC_VM_MX_L1_TLB_CNTL, (0xA << 7) | @@ -4093,10 +4293,10 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) for (i = 1; i < 16; i++) { if (i < 8) WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), - rdev->gart.table_addr >> 12); + rdev->vm_manager.saved_table_addr[i]); else WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2), - rdev->gart.table_addr >> 12); + rdev->vm_manager.saved_table_addr[i]); } /* enable context1-15 */ @@ -4128,6 +4328,17 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) static void si_pcie_gart_disable(struct radeon_device *rdev) { + unsigned i; + + for (i = 1; i < 16; ++i) { + uint32_t reg; + if (i < 8) + reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2); + else + reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2); + rdev->vm_manager.saved_table_addr[i] = RREG32(reg); + } + /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); WREG32(VM_CONTEXT1_CNTL, 0); @@ -4476,7 +4687,7 @@ static int si_vm_packet3_compute_check(struct radeon_device *rdev, int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) { int ret = 0; - u32 idx = 0; + u32 idx = 0, i; struct radeon_cs_packet pkt; do { @@ -4487,6 +4698,12 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) switch (pkt.type) { case RADEON_PACKET_TYPE0: dev_err(rdev->dev, "Packet0 not allowed!\n"); + for (i = 0; i < ib->length_dw; i++) { + if (i == idx) + printk("\t0x%08x <---\n", ib->ptr[i]); + else + printk("\t0x%08x\n", ib->ptr[i]); + } ret = -EINVAL; break; case RADEON_PACKET_TYPE2: @@ -4815,7 +5032,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* write new base address */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | WRITE_DATA_DST_SEL(0))); if (vm->id < 8) { @@ -4830,7 +5047,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* flush hdp cache */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); radeon_ring_write(ring, 0); @@ -4838,7 +5055,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* bits 0-15 are the VM contexts0-15 */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); @@ -5592,7 +5809,6 @@ static void si_enable_lbpw(struct radeon_device *rdev, bool enable) static int si_rlc_resume(struct radeon_device *rdev) { u32 i; - const __be32 *fw_data; if (!rdev->rlc_fw) return -EINVAL; @@ -5615,10 +5831,26 @@ static int si_rlc_resume(struct radeon_device *rdev) WREG32(RLC_MC_CNTL, 0); WREG32(RLC_UCODE_CNTL, 0); - fw_data = (const __be32 *)rdev->rlc_fw->data; - for (i = 0; i < SI_RLC_UCODE_SIZE; i++) { - WREG32(RLC_UCODE_ADDR, i); - WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); + if (rdev->new_fw) { + const struct rlc_firmware_header_v1_0 *hdr = + (const struct rlc_firmware_header_v1_0 *)rdev->rlc_fw->data; + u32 fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; + const __le32 *fw_data = (const __le32 *) + (rdev->rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + + radeon_ucode_print_rlc_hdr(&hdr->header); + + for (i = 0; i < fw_size; i++) { + WREG32(RLC_UCODE_ADDR, i); + WREG32(RLC_UCODE_DATA, le32_to_cpup(fw_data++)); + } + } else { + const __be32 *fw_data = + (const __be32 *)rdev->rlc_fw->data; + for (i = 0; i < SI_RLC_UCODE_SIZE; i++) { + WREG32(RLC_UCODE_ADDR, i); + WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++)); + } } WREG32(RLC_UCODE_ADDR, 0); @@ -6093,17 +6325,17 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -6318,7 +6550,8 @@ restart_ih: case 16: /* D5 page flip */ case 18: /* D6 page flip */ DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); - radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); + if (radeon_use_pflipirq > 0) + radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); break; case 42: /* HPD hotplug */ switch (src_data) { @@ -6440,13 +6673,13 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ @@ -6964,6 +7197,9 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) int ret, i; u16 tmp16; + if (pci_is_root_bus(rdev->pdev->bus)) + return; + if (radeon_pcie_gen2 == 0) return; @@ -7241,7 +7477,8 @@ static void si_program_aspm(struct radeon_device *rdev) if (orig != data) WREG32_PIF_PHY1(PB1_PIF_CNTL, data); - if (!disable_clkreq) { + if (!disable_clkreq && + !pci_is_root_bus(rdev->pdev->bus)) { struct pci_dev *root = rdev->pdev->bus->self; u32 lnkcap; diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index e24c94b6d14d..b58f12b762d7 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -56,7 +56,41 @@ bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) } /** - * si_dma_vm_set_page - update the page tables using the DMA + * si_dma_vm_copy_pages - update PTEs by copying them from the GART + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @src: src addr where to copy from + * @count: number of page entries to update + * + * Update PTEs by copying them from the GART using the DMA (SI). + */ +void si_dma_vm_copy_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, uint64_t src, + unsigned count) +{ + while (count) { + unsigned bytes = count * 8; + if (bytes > 0xFFFF8) + bytes = 0xFFFF8; + + ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, + 1, 0, 0, bytes); + ib->ptr[ib->length_dw++] = lower_32_bits(pe); + ib->ptr[ib->length_dw++] = lower_32_bits(src); + ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; + ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff; + + pe += bytes; + src += bytes; + count -= bytes / 8; + } +} + +/** + * si_dma_vm_write_pages - update PTEs by writing them manually * * @rdev: radeon_device pointer * @ib: indirect buffer to fill with commands @@ -66,83 +100,89 @@ bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) * @incr: increase next addr by incr bytes * @flags: access flags * - * Update the page tables using the DMA (SI). + * Update PTEs by writing them manually using the DMA (SI). */ -void si_dma_vm_set_page(struct radeon_device *rdev, - struct radeon_ib *ib, - uint64_t pe, - uint64_t addr, unsigned count, - uint32_t incr, uint32_t flags) +void si_dma_vm_write_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) { uint64_t value; unsigned ndw; - trace_radeon_vm_set_page(pe, addr, count, incr, flags); - - if (flags == R600_PTE_GART) { - uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; - while (count) { - unsigned bytes = count * 8; - if (bytes > 0xFFFF8) - bytes = 0xFFFF8; - - ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, - 1, 0, 0, bytes); - ib->ptr[ib->length_dw++] = lower_32_bits(pe); - ib->ptr[ib->length_dw++] = lower_32_bits(src); - ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; - ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff; - - pe += bytes; - src += bytes; - count -= bytes / 8; - } - } else if (flags & R600_PTE_SYSTEM) { - while (count) { - ndw = count * 2; - if (ndw > 0xFFFFE) - ndw = 0xFFFFE; - - /* for non-physically contiguous pages (system) */ - ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw); - ib->ptr[ib->length_dw++] = pe; - ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; - for (; ndw > 0; ndw -= 2, --count, pe += 8) { + while (count) { + ndw = count * 2; + if (ndw > 0xFFFFE) + ndw = 0xFFFFE; + + /* for non-physically contiguous pages (system) */ + ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw); + ib->ptr[ib->length_dw++] = pe; + ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; + for (; ndw > 0; ndw -= 2, --count, pe += 8) { + if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); value &= 0xFFFFFFFFFFFFF000ULL; - addr += incr; - value |= flags; - ib->ptr[ib->length_dw++] = value; - ib->ptr[ib->length_dw++] = upper_32_bits(value); - } - } - } else { - while (count) { - ndw = count * 2; - if (ndw > 0xFFFFE) - ndw = 0xFFFFE; - - if (flags & R600_PTE_VALID) + } else if (flags & R600_PTE_VALID) { value = addr; - else + } else { value = 0; - /* for physically contiguous pages (vram) */ - ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw); - ib->ptr[ib->length_dw++] = pe; /* dst addr */ - ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; - ib->ptr[ib->length_dw++] = flags; /* mask */ - ib->ptr[ib->length_dw++] = 0; - ib->ptr[ib->length_dw++] = value; /* value */ + } + addr += incr; + value |= flags; + ib->ptr[ib->length_dw++] = value; ib->ptr[ib->length_dw++] = upper_32_bits(value); - ib->ptr[ib->length_dw++] = incr; /* increment size */ - ib->ptr[ib->length_dw++] = 0; - pe += ndw * 4; - addr += (ndw / 2) * incr; - count -= ndw / 2; } } - while (ib->length_dw & 0x7) - ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0); +} + +/** + * si_dma_vm_set_pages - update the page tables using the DMA + * + * @rdev: radeon_device pointer + * @ib: indirect buffer to fill with commands + * @pe: addr of the page entry + * @addr: dst addr to write into pe + * @count: number of page entries to update + * @incr: increase next addr by incr bytes + * @flags: access flags + * + * Update the page tables using the DMA (SI). + */ +void si_dma_vm_set_pages(struct radeon_device *rdev, + struct radeon_ib *ib, + uint64_t pe, + uint64_t addr, unsigned count, + uint32_t incr, uint32_t flags) +{ + uint64_t value; + unsigned ndw; + + while (count) { + ndw = count * 2; + if (ndw > 0xFFFFE) + ndw = 0xFFFFE; + + if (flags & R600_PTE_VALID) + value = addr; + else + value = 0; + + /* for physically contiguous pages (vram) */ + ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw); + ib->ptr[ib->length_dw++] = pe; /* dst addr */ + ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; + ib->ptr[ib->length_dw++] = flags; /* mask */ + ib->ptr[ib->length_dw++] = 0; + ib->ptr[ib->length_dw++] = value; /* value */ + ib->ptr[ib->length_dw++] = upper_32_bits(value); + ib->ptr[ib->length_dw++] = incr; /* increment size */ + ib->ptr[ib->length_dw++] = 0; + pe += ndw * 4; + addr += (ndw / 2) * incr; + count -= ndw / 2; + } } void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) @@ -178,18 +218,19 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) * @src_offset: src GPU address * @dst_offset: dst GPU address * @num_gpu_pages: number of GPU pages to xfer - * @fence: radeon fence object + * @resv: reservation object to sync to * * Copy GPU paging using the DMA engine (SI). * Used by the radeon ttm implementation to move pages if * registered as the asic copy callback. */ -int si_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_gpu_pages, - struct radeon_fence **fence) +struct radeon_fence *si_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, uint64_t dst_offset, + unsigned num_gpu_pages, + struct reservation_object *resv) { struct radeon_semaphore *sem = NULL; + struct radeon_fence *fence; int ring_index = rdev->asic->copy.dma_ring_index; struct radeon_ring *ring = &rdev->ring[ring_index]; u32 size_in_bytes, cur_size_in_bytes; @@ -199,7 +240,7 @@ int si_copy_dma(struct radeon_device *rdev, r = radeon_semaphore_create(rdev, &sem); if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); - return r; + return ERR_PTR(r); } size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT); @@ -208,10 +249,10 @@ int si_copy_dma(struct radeon_device *rdev, if (r) { DRM_ERROR("radeon: moving bo (%d).\n", r); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_semaphore_sync_to(sem, *fence); + radeon_semaphore_sync_resv(rdev, sem, resv, false); radeon_semaphore_sync_rings(rdev, sem, ring->idx); for (i = 0; i < num_loops; i++) { @@ -228,16 +269,16 @@ int si_copy_dma(struct radeon_device *rdev, dst_offset += cur_size_in_bytes; } - r = radeon_fence_emit(rdev, fence, ring->idx); + r = radeon_fence_emit(rdev, &fence, ring->idx); if (r) { radeon_ring_unlock_undo(rdev, ring); radeon_semaphore_free(rdev, &sem, NULL); - return r; + return ERR_PTR(r); } - radeon_ring_unlock_commit(rdev, ring); - radeon_semaphore_free(rdev, &sem, *fence); + radeon_ring_unlock_commit(rdev, ring, false); + radeon_semaphore_free(rdev, &sem, fence); - return r; + return fence; } diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 58918868f894..676e6c2ba90a 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -23,6 +23,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "sid.h" #include "r600_dpm.h" #include "si_dpm.h" @@ -3812,6 +3813,27 @@ void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev, voltage_table->count = max_voltage_steps; } +static int si_get_svi2_voltage_table(struct radeon_device *rdev, + struct radeon_clock_voltage_dependency_table *voltage_dependency_table, + struct atom_voltage_table *voltage_table) +{ + u32 i; + + if (voltage_dependency_table == NULL) + return -EINVAL; + + voltage_table->mask_low = 0; + voltage_table->phase_delay = 0; + + voltage_table->count = voltage_dependency_table->count; + for (i = 0; i < voltage_table->count; i++) { + voltage_table->entries[i].value = voltage_dependency_table->entries[i].v; + voltage_table->entries[i].smio_low = 0; + } + + return 0; +} + static int si_construct_voltage_tables(struct radeon_device *rdev) { struct rv7xx_power_info *pi = rv770_get_pi(rdev); @@ -3819,15 +3841,25 @@ static int si_construct_voltage_tables(struct radeon_device *rdev) struct si_power_info *si_pi = si_get_pi(rdev); int ret; - ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC, - VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table); - if (ret) - return ret; + if (pi->voltage_control) { + ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC, + VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table); + if (ret) + return ret; - if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS) - si_trim_voltage_table_to_fit_state_table(rdev, - SISLANDS_MAX_NO_VREG_STEPS, - &eg_pi->vddc_voltage_table); + if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS) + si_trim_voltage_table_to_fit_state_table(rdev, + SISLANDS_MAX_NO_VREG_STEPS, + &eg_pi->vddc_voltage_table); + } else if (si_pi->voltage_control_svi2) { + ret = si_get_svi2_voltage_table(rdev, + &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, + &eg_pi->vddc_voltage_table); + if (ret) + return ret; + } else { + return -EINVAL; + } if (eg_pi->vddci_control) { ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI, @@ -3840,6 +3872,13 @@ static int si_construct_voltage_tables(struct radeon_device *rdev) SISLANDS_MAX_NO_VREG_STEPS, &eg_pi->vddci_voltage_table); } + if (si_pi->vddci_control_svi2) { + ret = si_get_svi2_voltage_table(rdev, + &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, + &eg_pi->vddci_voltage_table); + if (ret) + return ret; + } if (pi->mvdd_control) { ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC, @@ -3893,46 +3932,55 @@ static int si_populate_smc_voltage_tables(struct radeon_device *rdev, struct si_power_info *si_pi = si_get_pi(rdev); u8 i; - if (eg_pi->vddc_voltage_table.count) { - si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table); - table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] = - cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); - - for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) { - if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) { - table->maxVDDCIndexInPPTable = i; - break; + if (si_pi->voltage_control_svi2) { + si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc, + si_pi->svc_gpio_id); + si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd, + si_pi->svd_gpio_id); + si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_svi_rework_plat_type, + 2); + } else { + if (eg_pi->vddc_voltage_table.count) { + si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table); + table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] = + cpu_to_be32(eg_pi->vddc_voltage_table.mask_low); + + for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) { + if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) { + table->maxVDDCIndexInPPTable = i; + break; + } } } - } - if (eg_pi->vddci_voltage_table.count) { - si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table); + if (eg_pi->vddci_voltage_table.count) { + si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table); - table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] = - cpu_to_be32(eg_pi->vddci_voltage_table.mask_low); - } + table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] = + cpu_to_be32(eg_pi->vddci_voltage_table.mask_low); + } - if (si_pi->mvdd_voltage_table.count) { - si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table); + if (si_pi->mvdd_voltage_table.count) { + si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table); - table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] = - cpu_to_be32(si_pi->mvdd_voltage_table.mask_low); - } + table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] = + cpu_to_be32(si_pi->mvdd_voltage_table.mask_low); + } - if (si_pi->vddc_phase_shed_control) { - if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table, - &rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) { - si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table); + if (si_pi->vddc_phase_shed_control) { + if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table, + &rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) { + si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table); - table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] = - cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low); + table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] = + cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low); - si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay, - (u32)si_pi->vddc_phase_shed_table.phase_delay); - } else { - si_pi->vddc_phase_shed_control = false; + si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay, + (u32)si_pi->vddc_phase_shed_table.phase_delay); + } else { + si_pi->vddc_phase_shed_control = false; + } } } @@ -5798,16 +5846,17 @@ int si_dpm_enable(struct radeon_device *rdev) { struct rv7xx_power_info *pi = rv770_get_pi(rdev); struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct si_power_info *si_pi = si_get_pi(rdev); struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; int ret; if (si_is_smc_running(rdev)) return -EINVAL; - if (pi->voltage_control) + if (pi->voltage_control || si_pi->voltage_control_svi2) si_enable_voltage_control(rdev, true); if (pi->mvdd_control) si_get_mvdd_configuration(rdev); - if (pi->voltage_control) { + if (pi->voltage_control || si_pi->voltage_control_svi2) { ret = si_construct_voltage_tables(rdev); if (ret) { DRM_ERROR("si_construct_voltage_tables failed\n"); @@ -6207,7 +6256,7 @@ static void si_parse_pplib_clock_info(struct radeon_device *rdev, if ((rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) && index == 0) { /* XXX disable for A0 tahiti */ - si_pi->ulv.supported = true; + si_pi->ulv.supported = false; si_pi->ulv.pl = *pl; si_pi->ulv.one_pcie_lane_in_ulv = false; si_pi->ulv.volt_change_delay = SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT; @@ -6406,16 +6455,32 @@ int si_dpm_init(struct radeon_device *rdev) ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold; pi->voltage_control = - radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_GPIO_LUT); + radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, + VOLTAGE_OBJ_GPIO_LUT); + if (!pi->voltage_control) { + si_pi->voltage_control_svi2 = + radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, + VOLTAGE_OBJ_SVID2); + if (si_pi->voltage_control_svi2) + radeon_atom_get_svi2_info(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, + &si_pi->svd_gpio_id, &si_pi->svc_gpio_id); + } pi->mvdd_control = - radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, VOLTAGE_OBJ_GPIO_LUT); + radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, + VOLTAGE_OBJ_GPIO_LUT); eg_pi->vddci_control = - radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, VOLTAGE_OBJ_GPIO_LUT); + radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, + VOLTAGE_OBJ_GPIO_LUT); + if (!eg_pi->vddci_control) + si_pi->vddci_control_svi2 = + radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, + VOLTAGE_OBJ_SVID2); si_pi->vddc_phase_shed_control = - radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_PHASE_LUT); + radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, + VOLTAGE_OBJ_PHASE_LUT); rv770_get_engine_memory_ss(rdev); diff --git a/drivers/gpu/drm/radeon/si_dpm.h b/drivers/gpu/drm/radeon/si_dpm.h index 4ce5032cdf49..8b5c06a0832d 100644 --- a/drivers/gpu/drm/radeon/si_dpm.h +++ b/drivers/gpu/drm/radeon/si_dpm.h @@ -170,6 +170,8 @@ struct si_power_info { bool vddc_phase_shed_control; bool pspp_notify_required; bool sclk_deep_sleep_above_low; + bool voltage_control_svi2; + bool vddci_control_svi2; /* smc offsets */ u32 sram_end; u32 state_table_start; @@ -192,6 +194,9 @@ struct si_power_info { SMC_SIslands_MCRegisters smc_mc_reg_table; SISLANDS_SMC_STATETABLE smc_statetable; PP_SIslands_PAPMParameters papm_parm; + /* SVI2 */ + u8 svd_gpio_id; + u8 svc_gpio_id; }; #define SISLANDS_INITIAL_STATE_ARB_INDEX 0 diff --git a/drivers/gpu/drm/radeon/si_smc.c b/drivers/gpu/drm/radeon/si_smc.c index e80efcf0c230..73dbc79c959d 100644 --- a/drivers/gpu/drm/radeon/si_smc.c +++ b/drivers/gpu/drm/radeon/si_smc.c @@ -219,36 +219,48 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) if (!rdev->smc_fw) return -EINVAL; - switch (rdev->family) { - case CHIP_TAHITI: - ucode_start_address = TAHITI_SMC_UCODE_START; - ucode_size = TAHITI_SMC_UCODE_SIZE; - break; - case CHIP_PITCAIRN: - ucode_start_address = PITCAIRN_SMC_UCODE_START; - ucode_size = PITCAIRN_SMC_UCODE_SIZE; - break; - case CHIP_VERDE: - ucode_start_address = VERDE_SMC_UCODE_START; - ucode_size = VERDE_SMC_UCODE_SIZE; - break; - case CHIP_OLAND: - ucode_start_address = OLAND_SMC_UCODE_START; - ucode_size = OLAND_SMC_UCODE_SIZE; - break; - case CHIP_HAINAN: - ucode_start_address = HAINAN_SMC_UCODE_START; - ucode_size = HAINAN_SMC_UCODE_SIZE; - break; - default: - DRM_ERROR("unknown asic in smc ucode loader\n"); - BUG(); + if (rdev->new_fw) { + const struct smc_firmware_header_v1_0 *hdr = + (const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data; + + radeon_ucode_print_smc_hdr(&hdr->header); + + ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); + ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); + src = (const u8 *) + (rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + } else { + switch (rdev->family) { + case CHIP_TAHITI: + ucode_start_address = TAHITI_SMC_UCODE_START; + ucode_size = TAHITI_SMC_UCODE_SIZE; + break; + case CHIP_PITCAIRN: + ucode_start_address = PITCAIRN_SMC_UCODE_START; + ucode_size = PITCAIRN_SMC_UCODE_SIZE; + break; + case CHIP_VERDE: + ucode_start_address = VERDE_SMC_UCODE_START; + ucode_size = VERDE_SMC_UCODE_SIZE; + break; + case CHIP_OLAND: + ucode_start_address = OLAND_SMC_UCODE_START; + ucode_size = OLAND_SMC_UCODE_SIZE; + break; + case CHIP_HAINAN: + ucode_start_address = HAINAN_SMC_UCODE_START; + ucode_size = HAINAN_SMC_UCODE_SIZE; + break; + default: + DRM_ERROR("unknown asic in smc ucode loader\n"); + BUG(); + } + src = (const u8 *)rdev->smc_fw->data; } if (ucode_size & 3) return -EINVAL; - src = (const u8 *)rdev->smc_fw->data; spin_lock_irqsave(&rdev->smc_idx_lock, flags); WREG32(SMC_IND_INDEX_0, ucode_start_address); WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index fd414d34d885..6635da9ec986 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -736,7 +736,7 @@ # define DESCRIPTION16(x) (((x) & 0xff) << 0) # define DESCRIPTION17(x) (((x) & 0xff) << 8) -#define AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL 0x54 +#define AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL 0x54 # define AUDIO_ENABLED (1 << 31) #define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT 0x56 diff --git a/drivers/gpu/drm/radeon/sislands_smc.h b/drivers/gpu/drm/radeon/sislands_smc.h index 10e945a49479..623a0b1e2d9d 100644 --- a/drivers/gpu/drm/radeon/sislands_smc.h +++ b/drivers/gpu/drm/radeon/sislands_smc.h @@ -241,6 +241,9 @@ typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE; #define SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width 0xF4 #define SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen 0xFC #define SI_SMC_SOFT_REGISTER_vr_hot_gpio 0x100 +#define SI_SMC_SOFT_REGISTER_svi_rework_plat_type 0x118 +#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd 0x11c +#define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc 0x120 #define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16 #define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32 diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 3f0e8d7b8dbe..1f8a8833e1be 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -23,6 +23,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "sumod.h" #include "r600_dpm.h" #include "cypress_dpm.h" diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 32e50be9c4ac..b4ec5c4e7969 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -23,6 +23,7 @@ #include "drmP.h" #include "radeon.h" +#include "radeon_asic.h" #include "trinityd.h" #include "r600_dpm.h" #include "trinity_dpm.h" @@ -1874,16 +1875,22 @@ int trinity_dpm_init(struct radeon_device *rdev) for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) pi->at[i] = TRINITY_AT_DFLT; - /* There are stability issues reported on with - * bapm enabled when switching between AC and battery - * power. At the same time, some MSI boards hang - * if it's not enabled and dpm is enabled. Just enable - * it for MSI boards right now. - */ - if (rdev->pdev->subsystem_vendor == 0x1462) - pi->enable_bapm = true; - else + if (radeon_bapm == -1) { + /* There are stability issues reported on with + * bapm enabled when switching between AC and battery + * power. At the same time, some MSI boards hang + * if it's not enabled and dpm is enabled. Just enable + * it for MSI boards right now. + */ + if (rdev->pdev->subsystem_vendor == 0x1462) + pi->enable_bapm = true; + else + pi->enable_bapm = false; + } else if (radeon_bapm == 0) { pi->enable_bapm = false; + } else { + pi->enable_bapm = true; + } pi->enable_nbps_policy = true; pi->enable_sclk_ds = true; pi->enable_gfx_power_gating = true; diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index be42c8125203..e72b3cb59358 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -22,6 +22,7 @@ * Authors: Christian König <christian.koenig@amd.com> */ +#include <linux/firmware.h> #include <drm/drmP.h> #include "radeon.h" #include "radeon_asic.h" @@ -70,6 +71,82 @@ void uvd_v1_0_set_wptr(struct radeon_device *rdev, } /** + * uvd_v1_0_fence_emit - emit an fence & trap command + * + * @rdev: radeon_device pointer + * @fence: fence to emit + * + * Write a fence and a trap command to the ring. + */ +void uvd_v1_0_fence_emit(struct radeon_device *rdev, + struct radeon_fence *fence) +{ + struct radeon_ring *ring = &rdev->ring[fence->ring]; + uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; + + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); + radeon_ring_write(ring, addr & 0xffffffff); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); + radeon_ring_write(ring, fence->seq); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); + radeon_ring_write(ring, 0); + + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); + radeon_ring_write(ring, 2); + return; +} + +/** + * uvd_v1_0_resume - memory controller programming + * + * @rdev: radeon_device pointer + * + * Let the UVD memory controller know it's offsets + */ +int uvd_v1_0_resume(struct radeon_device *rdev) +{ + uint64_t addr; + uint32_t size; + int r; + + r = radeon_uvd_resume(rdev); + if (r) + return r; + + /* programm the VCPU memory controller bits 0-27 */ + addr = (rdev->uvd.gpu_addr >> 3) + 16; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3; + WREG32(UVD_VCPU_CACHE_OFFSET0, addr); + WREG32(UVD_VCPU_CACHE_SIZE0, size); + + addr += size; + size = RADEON_UVD_STACK_SIZE >> 3; + WREG32(UVD_VCPU_CACHE_OFFSET1, addr); + WREG32(UVD_VCPU_CACHE_SIZE1, size); + + addr += size; + size = RADEON_UVD_HEAP_SIZE >> 3; + WREG32(UVD_VCPU_CACHE_OFFSET2, addr); + WREG32(UVD_VCPU_CACHE_SIZE2, size); + + /* bits 28-31 */ + addr = (rdev->uvd.gpu_addr >> 28) & 0xF; + WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); + + /* bits 32-39 */ + addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; + WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); + + WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr)); + + return 0; +} + +/** * uvd_v1_0_init - start and test UVD block * * @rdev: radeon_device pointer @@ -124,14 +201,38 @@ int uvd_v1_0_init(struct radeon_device *rdev) radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); radeon_ring_write(ring, 3); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); done: /* lower clocks again */ radeon_set_uvd_clocks(rdev, 0, 0); - if (!r) + if (!r) { + switch (rdev->family) { + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV620: + /* 64byte granularity workaround */ + WREG32(MC_CONFIG, 0); + WREG32(MC_CONFIG, 1 << 4); + WREG32(RS_DQ_RD_RET_CONF, 0x3f); + WREG32(MC_CONFIG, 0x1f); + + /* fall through */ + case CHIP_RV670: + case CHIP_RV635: + + /* write clean workaround */ + WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10); + break; + + default: + /* TODO: Do we need more? */ + break; + } + DRM_INFO("UVD initialized successfully.\n"); + } return r; } @@ -218,12 +319,12 @@ int uvd_v1_0_start(struct radeon_device *rdev) /* enable UMC */ WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); + WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); + /* boot up the VCPU */ WREG32(UVD_SOFT_RESET, 0); mdelay(10); - WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); - for (i = 0; i < 10; ++i) { uint32_t status; for (j = 0; j < 100; ++j) { @@ -331,7 +432,7 @@ int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) } radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(UVD_CONTEXT_ID); if (tmp == 0xDEADBEEF) diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index 8bfdadd56598..89193519f8a1 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -72,6 +72,10 @@ int uvd_v2_2_resume(struct radeon_device *rdev) uint32_t chip_id, size; int r; + /* RV770 uses V1.0 MC */ + if (rdev->family == CHIP_RV770) + return uvd_v1_0_resume(rdev); + r = radeon_uvd_resume(rdev); if (r) return r; |